function F = spm_ncFcdf(x,df,d)
% Cumulative Distribution Function (CDF) of non-central F-distribution
% FORMAT f = spm_ncFcdf(x,df,d)
% x  - F-variate (F has range [0,Inf) )
% df - degrees of freedom, df = [v,w] with v>0 and w>0
% d  - non-centrality parameter
% F  - CDF of non-central F-distribution with [v,w] d.f. at points x
%
% Reference:
% https://en.wikipedia.org/wiki/Noncentral_F-distribution
%__________________________________________________________________________
% Copyright (C) 2018 Wellcome Trust Centre for Neuroimaging

% Guillaume Flandin
% $Id: spm_ncFcdf.m 7354 2018-06-22 10:44:22Z guillaume $

%-Format arguments, note & check sizes
%--------------------------------------------------------------------------
%-Unpack degrees of freedom v & w from single df parameter (df)
if numel(df) == 2
    v = df(1);
    w = df(2);
elseif size(df,2) == 2
    v = df(:,1);
    w = df(:,2);
else
    error('Cannot unpack degrees of freedom.');
end

%-Check argument sizes
ad = [ndims(x);ndims(v);ndims(w);ndims(d)];
rd = max(ad);
as = [[size(x),ones(1,rd-ad(1))];...
      [size(v),ones(1,rd-ad(2))];...
      [size(w),ones(1,rd-ad(3))];...
      [size(d),ones(1,rd-ad(4))];];
rs = max(as);
xa = prod(as,2)>1;
if all(xa) && any(any(diff(as(xa,:)),1))
    error('Non-scalar arguments must match in size.');
end

%-Computation
%--------------------------------------------------------------------------
%-Initialise result to zeros
F = zeros(rs);

%-Only defined for v>0, w>0 and d>=0. Return NaN if undefined.
md = true(size(F)) & v>0 & w>0 & d>=0;
if any(~md(:))
    F(~md) = NaN;
    warning('Returning NaN for out of range arguments');
end

%-Compute where defined
if ~any(md(:)), return, end
Q = md;
if xa(1), Qx=Q; else Qx=1; end
if xa(2), Qv=Q; else Qv=1; end
if xa(3), Qw=Q; else Qw=1; end
if xa(4), Qd=Q; else Qd=1; end

a = exp(-d(Qd)/2);
x = v(Qv) .* x(Qx) ./ (w(Qw) + v(Qv) .* x(Qx));
F(Q) = a .* betainc(x(Qx), v(Qv)/2, w(Qw)/2);
for i=1:1024
    a = a .* d(Qd) / (2 * i);
    % could use recursion with:
    % Ix(a+1,b)=Ix(a,b)-G(a+b)/(G(a+1)*G(b))*x^a*(1-x)^b and G(a+1)=a*G(a)
    e = a .* betainc(x(Qx), v(Qv)/2+i, w(Qw)/2);
    if max(e) < 1e-12, break; end
    F = F + e;
end


% Minimize sidelobe level of a uniform linear array via spectral factorization
% "FIR Filter Design via Spectral Factorization and Convex Optimization" example
% by S.-P. Wu, S. Boyd, and L. Vandenberghe
% (figures are generated)
%
% Designs a uniform linear antenna array using spectral factorization method where:
% - it minimizes sidelobe level outside the beamwidth of the pattern
% - it has a constraint on the maximum ripple around unit gain in the beamwidth
%
%   minimize   max |y(theta)|                   for theta in the stop-beamwidth
%       s.t.   1/delta <= |y(theta)| <= delta   for theta in the pass-beamwidth
%
% We first replace the look-angle variable theta with the "frequency"
% variable omega, defined by omega = -2*pi*d/lambda*cos(theta).
% This transforms the antenna pattern y(theta) into a standard discrete
% Fourier transform of array weights w. Then we apply another change of
% variables: we replace w with its auto-correlation coefficients r.
%
% Now the problem can be solved via spectral factorization approach:
%
%   minimize   max R(omega)                        for omega in the stopband
%       s.t.   (1/delta)^2 <= R(omega) <= delta^2  for omega in the passband
%              R(omega) >= 0                       for all omega
%
% where R(omega) is the squared magnitude of the y(theta) array response
% (and the Fourier transform of the autocorrelation coefficients r).
% Variables are coefficients r. delta is the allowed passband ripple.
% This is a convex problem (can be formulated as an LP after sampling).
%
% Written for CVX by Almir Mutapcic 02/02/06

%********************************************************************
% problem specs: a uniform line array with inter-element spacing d
%                antenna element locations are at d*[0:n-1]
%                (the array pattern will be symmetric around origin)
%********************************************************************
n = 20;               % number of antenna elements
lambda = 1;           % wavelength
d = 0.45*lambda;      % inter-element spacing

% passband direction from 30 to 60 degrees (30 degrees bandwidth)
% transition band is 15 degrees on both sides of the passband
theta_pass = 40;
theta_stop = 50;

% passband max allowed ripple
ripple = 0.1; % in dB (+/- around the unit gain)

%********************************************************************
% construct optimization data
%********************************************************************
% number of frequency samples
m = 30*n;

% convert passband and stopband angles into omega frequencies
omega_zero = -2*pi*d/lambda;
omega_pass = -2*pi*d/lambda*cos(theta_pass*pi/180);
omega_stop = -2*pi*d/lambda*cos(theta_stop*pi/180);
omega_pi   = +2*pi*d/lambda;

% build matrix A that relates R(omega) and r, ie, R = A*r
omega = linspace(-pi,pi,m)';
A = exp( -j*omega(:)*[1-n:n-1] );

% passband constraint matrix
Ap = A(omega >= omega_zero & omega <= omega_pass,:);

% stopband constraint matrix
As = A(omega >= omega_stop & omega <= omega_pi,:);

%********************************************************************
% formulate and solve the magnitude design problem
%********************************************************************
cvx_begin
  variable r(2*n-1,1) complex
  % minimize stopband attenuation
  minimize( max( real( As*r ) ) )
  subject to
    % passband ripple constraints
    (10^(-ripple/20))^2 <= real( Ap*r ) <= (10^(+ripple/20))^2;
    % nonnegative-real constraint for all frequencies
    % a bit redundant: the passband frequencies are already constrained
    real( A*r ) >= 0;
    % auto-correlation symmetry constraints
    imag(r(n)) == 0;
    r(n-1:-1:1) == conj(r(n+1:end));
cvx_end

% check if problem was successfully solved
if ~strfind(cvx_status,'Solved')
    return
end

% find antenna weights by computing the spectral factorization
w = spectral_fact(r);

% divided by 2 since this is in PSD domain
min_sidelobe_level = 10*log10( cvx_optval );
fprintf(1,'The minimum sidelobe level is %3.2f dB.\n\n',...
          min_sidelobe_level);

%********************************************************************
% plots
%********************************************************************
% build matrix G that relates y(theta) and w, ie, y = G*w
theta = [-180:180]';
G = kron( cos(pi*theta/180), [0:n-1] );
G = exp(2*pi*i*d/lambda*G);
y = G*w;

% plot array pattern
figure(1), clf
ymin = -40; ymax = 5;
plot([-180:180], 20*log10(abs(y)), ...
     [theta_stop theta_stop],[ymin ymax],'r--',...
     [-theta_pass -theta_pass],[ymin ymax],'r--',...
     [-theta_stop -theta_stop],[ymin ymax],'r--',...
     [theta_pass theta_pass],[ymin ymax],'r--');
xlabel('look angle'), ylabel('mag y(theta) in dB');
axis([-180 180 ymin ymax]);

% polar plot
figure(2), clf
zerodB = 50;
dBY = 20*log10(abs(y)) + zerodB;
plot(dBY.*cos(pi*theta/180), dBY.*sin(pi*theta/180), '-');
axis([-zerodB zerodB -zerodB zerodB]), axis('off'), axis('square')
hold on
plot(zerodB*cos(pi*theta/180),zerodB*sin(pi*theta/180),'k:') % 0 dB
plot( (min_sidelobe_level + zerodB)*cos(pi*theta/180), ...
      (min_sidelobe_level + zerodB)*sin(pi*theta/180),'k:')  % min level
text(-zerodB,0,'0 dB')
text(-(min_sidelobe_level + zerodB),0,sprintf('%0.1f dB',min_sidelobe_level));
plot([0 60*cos(theta_pass*pi/180)], [0 60*sin(theta_pass*pi/180)], 'k:')
plot([0 60*cos(-theta_pass*pi/180)],[0 60*sin(-theta_pass*pi/180)],'k:')
plot([0 60*cos(theta_stop*pi/180)], [0 60*sin(theta_stop*pi/180)], 'k:')
plot([0 60*cos(-theta_stop*pi/180)],[0 60*sin(-theta_stop*pi/180)],'k:')
hold off


function [ cluster, cluster_center, cluster_energy ] = ...
  cluster_energy_compute ( dim_num, point_num, cluster_num, point, ...
  cluster_center )

%*****************************************************************************80
%
%% CLUSTER_ENERGY_COMPUTE computes the energy of the clusters.
%
%  Discussion:
%
%    The cluster energy is defined as the sum of the distance
%    squared from each point to its cluster center.  It is the goal
%    of the H-means and K-means algorithms to find, for a fixed number
%    of clusters, a clustering that minimizes this energy
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 October 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the number of spatial dimensions.
%
%    Input, integer POINT_NUM, the number of data points.
%
%    Input, integer CLUSTER_NUM, the number of clusters.
%
%    Input, real  POINT(DIM_NUM,POINT_NUM), the data points.
%
%    Input, integer CLUSTER(POINT_NUM), the cluster to which each
%    data point belongs.
%
%    Input, real CLUSTER_CENTER(DIM_NUM,CLUSTER_NUM), the centers.
%
%    Output, real CLUSTER_ENERGY(CLUSTER_NUM), the energy
%    associated with each cluster.
%
  cluster_energy(1:cluster_num) = 0.0;

  for i = 1 : point_num

    j = cluster(i);

    point_energy = sum ( ...
      ( point(1:dim_num,i) - cluster_center(1:dim_num,j) ).^2 );

    cluster_energy(j) = cluster_energy(j) + point_energy;

  end

  return
end


function y = pmean(x,p)
%Calculates generalized mean
% x = vector subject to generalized mean calculations. Can be also matrix.
% p = parameter for generalized mean.
% y = generalized mean value.
y = (sum(x.^p,1)/size(x,1)).^(1/p);


function pdf = inverse_gaussian_pdf ( x, a, b )

%*****************************************************************************80
%
%% INVERSE_GAUSSIAN_PDF evaluates the Inverse Gaussian PDF.
%
%  Discussion:
%
%    The Inverse Gaussian PDF is also known as the Wald PDF
%    and the Inverse Normal PDF.
%
%    PDF(X)(A,B)
%      = SQRT ( B / ( 2 * PI * X**3 ) )
%        * EXP ( - B * ( X - A )**2 / ( 2.0D+00 * A**2 * X ) )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 September 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real X, the argument of the PDF.
%    0.0 < X
%
%    Input, real A, B, the parameters of the PDF.
%    0.0 < A,
%    0.0 < B.
%
%    Output, real PDF, the value of the PDF.
%
  if ( x <= 0.0 )
    pdf = 0.0;
  else
    pdf = sqrt ( b / ( 2.0 * pi * x^3 ) ) * ...
      exp ( - b * ( x - a )^2 / ( 2.0 * a^2 * x ) );
  end

  return
end


% Chapter 11 - Hamiltonian Systems, Lyapunov Functions, and Stability.
% Programs_11a - Surface and Contour Plots. Finding Vdot.
% Copyright Birkhauser 2013. Stephen Lynch.

% The double-well potential (Fig. 11.5(b)).
% Symbolic Math toolbox required.
ezsurfc('-x^2/2+x^4/4+y^2/2',[-1.5,1.5]);

% Calculating Vdot (Exercise 6).
clear
syms x y V
V=(1-4*x^2-y^2)^2;
xdot=-y*(1+x)/2+x*(1-4*x^2-y^2);
ydot=2*x*(1+x)+y*(1-4*x^2-y^2);
Vdot=factor(diff(V,x)*xdot+diff(V,y)*ydot)

% Phase portraits may be plotted using the M-files in Chapter 8.
% End of Programs_11a.


function [theta, J_history] = gradientDescent(X, y, theta, alpha, num_iters)
%GRADIENTDESCENT Performs gradient descent to learn theta
%   theta = GRADIENTDESCENT(X, y, theta, alpha, num_iters) updates theta by
%   taking num_iters gradient steps with learning rate alpha

% Initialize some useful values
m = length(y); % number of training examples
J_history = zeros(num_iters, 1);

for iter = 1:num_iters

    % ====================== YOUR CODE HERE ======================
    % Instructions: Perform a single gradient step on the parameter vector
    %               theta.
    %
    % Hint: While debugging, it can be useful to print out the values
    %       of the cost function (computeCost) and gradient here.
    %

    predictions =  X * theta;
    updates = X' * (predictions - y);
    theta = theta - alpha * (1/m) * updates;

    %theta = theta - alpha * (1/m) * sum(sqerrors) * X;

    %theta - (alpha/m) * (X' * (X * theta - y));

    %theta = theta - (alpha/m) * (X' * (X * theta - y));

    % ============================================================

    % Save the cost J in every iteration
    J_history(iter) = computeCost(X, y, theta);

end

end


% Section 11.8.4: Network rate optimization
% Boyd & Vandenberghe "Convex Optimization"
% Argyrios Zymnis - 05/03/08
%
% We consider a network with n flows and L links. Each flow i,
% moves along a fixed predetermined path (i.e. a subset of the links)
% and has an associated rate x_i. Each link j has an associated capacity
% c_j. The total rate of all flows travelling along a link cannot exceed
% the link capacity. We can describe these link capacity limits using the
% flow-link incidence matrix A \in \reals^{L \times n}, where
% A_{ij} = 1, if flow j passes through link i and 0 otherwise.
% The link capacity constraints can be expressed as A*x <= c
% In the network rate problem the variables are the flow rates x. The
% objective is to choose the flow rates to maximize a separate utility
% function U, given by
%           U(x) = U_1(x_1)+U_2(x_2)+...+U_n(x_n)
% The network rate optimization problem is then
%           maximize    U(x)
%           subject to  A*x <= c
% Here we use U_i(x_i) = log x_i for all i

% Input data
rand('state',1)
L = 20;
n = 10;
k = 7; %average links per flow
A = double(rand(L,n) <= k/L);
c = 0.9*rand(L,1)+0.1;

% Solve network rate problem
cvx_begin
    variable x(n);
    maximize(sum(log(x)))
    subject to
        A*x <= c;  %#ok
cvx_end
primal_obj = cvx_optval;

% Solve dual problem to obtain link prices
cvx_begin
    variable lambda(L);
    minimize(c'*lambda-sum(log(A'*lambda))-n)
    subject to
        lambda >= 0;  %#ok
cvx_end
dual_obj = cvx_optval;


% Chebychev design of an FIR filter given a desired H(w)
% "Filter design" lecture notes (EE364) by S. Boyd
% (figures are generated)
%
% Designs an FIR filter given a desired frequency response H_des(w).
% The design is judged by the maximum absolute error (Chebychev norm).
% This is a convex problem (after sampling it can be formulated as an SOCP).
%
%   minimize   max |H(w) - H_des(w)|     for w in [0,pi]
%
% where H is the frequency response function and variable is h
% (the filter impulse response).
%
% Written for CVX by Almir Mutapcic 02/02/06

%********************************************************************
% problem specs
%********************************************************************
% number of FIR coefficients (including the zeroth one)
n = 20;

% rule-of-thumb frequency discretization (Cheney's Approx. Theory book)
m = 15*n;
w = linspace(0,pi,m)'; % omega

%********************************************************************
% construct the desired filter
%********************************************************************
% fractional delay
D = 8.25;            % delay value
Hdes = exp(-1j*D*w);  % desired frequency response

% Gaussian filter with linear phase (uncomment lines below for this design)
% var = 0.05;
% Hdes = 1/(sqrt(2*pi*var))*exp(-(w-pi/2).^2/(2*var));
% Hdes = Hdes.*exp(-j*n/2*w);

%*********************************************************************
% solve the minimax (Chebychev) design problem
%*********************************************************************
% A is the matrix used to compute the frequency response
% A(w,:) = [1 exp(-j*w) exp(-j*2*w) ... exp(-j*n*w)]
A = exp( -1j*kron(w,0:n-1) );

% optimal Chebyshev filter formulation
cvx_begin
  variable h(n,1)
  minimize( max( abs( A*h - Hdes ) ) )
cvx_end

% check if problem was successfully solved
disp(['Problem is ' cvx_status])
if ~strfind(cvx_status,'Solved')
  h = [];
end

%*********************************************************************
% plotting routines
%*********************************************************************
% plot the FIR impulse reponse
figure(1)
stem(0:n-1,h)
xlabel('n')
ylabel('h(n)')

% plot the frequency response
H = exp(-1j*kron(w,0:n-1))*h;
figure(2)
% magnitude
subplot(2,1,1);
plot(w,20*log10(abs(H)),w,20*log10(abs(Hdes)),'--')
xlabel('w')
ylabel('mag H in dB')
axis([0 pi -30 10])
legend('optimized','desired','Location','SouthEast')
% phase
subplot(2,1,2)
plot(w,angle(H))
axis([0,pi,-pi,pi])
xlabel('w'), ylabel('phase H(w)')


function pdf = point_distance_3d_pdf ( x, a, b )

%*****************************************************************************80
%
%% POINT_DISTANCE_3D_PDF evaluates the point distance PDF in the 3D.
%
%  Discussion:
%
%    It is assumed that a set of points has been generated in 3D
%    according to a Poisson process.  The number of points in a region
%    of size VOLUME is a Poisson variate with mean value B * VOLUME.
%
%    For a point chosen at random, we may now find the nearest
%    Poisson point, the second nearest and so on.  We are interested
%    in the PDF that governs the expected behavior of the distances
%    of rank A = 1, 2, 3, ... with Poisson density B.
%
%  Formula:
%
%    PDF(X)(A,B) = 3 * ( (4/3) * B * PI )**A * X**( 3 * A - 1 )
%      * EXP ( - (4/3) * B * PI * X * X * X ) / ( A - 1 )!
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 September 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Daniel Zwillinger, editor,
%    CRC Standard Mathematical Tables and Formulae,
%    30th Edition,
%    CRC Press, 1996, pages 580.
%
%  Parameters:
%
%    Input, real X, the argument of the PDF.
%    0.0 <= X.
%
%    Input, integer A, indicates the degree of nearness of the point.
%    A = 1 means the nearest point, A = 2 the second nearest, and so on.
%    0 < A.
%
%    Input, real B, the Poisson point density.  0.0 < B.
%
%    Output, real PDF, the value of the PDF.
%
  if ( a < 1 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'POINT_DISTANCE_3D_PDF - Fatal error!\n' );
    fprintf ( 1, '  Input parameter A < 1.\n' );
    error ( 'POINT_DISTANCE_3D_PDF - Fatal error!' );
  end

  if ( b <= 0.0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'POINT_DISTANCE_3D_PDF - Fatal error!\n' );
    fprintf ( 1, '  Input parameter B <= 0.0.\n' );
    error ( 'POINT_DISTANCE_3D_PDF - Fatal error!' );
  end

  if ( x < 0.0 )
    pdf = 0.0;
  else
    pdf = 3.0 * ( ( 4.0 / 3.0 ) * b * pi )^a ...
      * x^( 3 * a - 1 ) * exp ( - ( 4.0 / 3.0 ) * b * pi * x^3 ) ...
      / i4_factorial ( a - 1 );
  end

  return
end


function [g,tfr]=pgauss(L,varargin)
%PGAUSS  Sampled, periodized Gaussian
%   Usage: g=pgauss(L);
%          g=pgauss(L,tfr);
%          g=pgauss(L,...);
%          [g,tfr]=pgauss( ... );
%
%   Input parameters:
%         L    : Length of vector.
%         tfr  : ratio between time and frequency support.
%
%   Output parameters:
%         g    : The periodized Gaussian.
%
%   `pgauss(L,tfr)` computes samples of a periodized Gaussian. The function
%   returns a regular sampling of the periodization of the function
%   $exp(-pi*(x.^2/tfr))$.
%
%   The $l^2$ norm of the returned Gaussian is equal to 1.
%
%   The parameter *tfr* determines the ratio between the effective support
%   of *g* and the effective support of the DFT of *g*. If $tfr>1$ then *g*
%   has a wider support than the DFT of *g*.
%
%   `pgauss(L)` does the same setting *tfr=1*.
%
%   `[g,tfr] = pgauss( ... )` will additionally return the time-to-frequency
%   support ratio. This is useful if you did not specify it (i.e. used the
%   `'width'` or `'bw'` flag).
%
%   The function is whole-point even. This implies that `fft(pgauss(L,tfr))`
%   is real for any *L* and *tfr*. The DFT of *g* is equal to
%   `pgauss(L,1/tfr)`.
%
%   In addition to the `'width'` flag, `pgauss` understands the following
%   flags at the end of the list of input parameters:
%
%     'fs',fs     Use a sampling rate of *fs* Hz as unit for specifying the
%                 width, bandwidth, centre frequency and delay of the
%                 Gaussian. Default is *fs=[]* which indicates to measure
%                 everything in samples.
%
%     'width',s   Set the width of the Gaussian such that it has an
%                 effective support of *s* samples. This means that
%                 approx. 96% of the energy or 79% of the area
%                 under the graph is contained within *s* samples.
%                 This corresponds to -6dB or to width at the
%                 half of the height.
%                 This is equivalent to calling `pgauss(L,pi*s^2/4L*log(2))`.
%
%     'atheight',ah  Used only in conjuction with 'width'. Forces the
%                    Gaussian to width *s* at the *ah* fraction of the
%                    height.
%
%     'bw',bw     As for the `'width'` argument, but specifies the width
%                 in the frequency domain. The bandwidth is measured in
%                 normalized frequencies, unless the `'fs'` value is given.
%
%     'cf',cf     Set the centre frequency of the Gaussian to *fc*.
%
%     'wp'        Output is whole point even. This is the default.
%
%     'hp'        Output is half point even, as most Matlab filter
%                 routines.
%
%     'delay',d   Delay the output by *d*. Default is zero delay.
%
%   In addition to these parameteres, `pgauss` accepts any of the flags
%   from |setnorm|. The output will be normalized as specified.
%
%   If this function is used to generate a window for a Gabor frame, then
%   the window giving the smallest frame bound ratio is generated by
%   `pgauss(L,a*M/L)`.
%
%   Examples:
%   ---------
%
%   This example creates a Gaussian function, and demonstrates that it is
%   its own Discrete Fourier Transform:::
%
%     g=pgauss(128);
%
%     % Test of DFT invariance: Should be close to zero.
%     norm(g-dft(g))
%
%   The next plot shows the Gaussian in the time domain:::
%
%     plot(fftshift(pgauss(128)));
%
%   The next plot shows the Gaussian in the frequency domain on a log scale:::
%
%     magresp(pgauss(128),'dynrange',100);
%
%   The next plot shows the Gaussian in the time-frequency plane:::
%
%     sgram(pgauss(128),'tc','nf','lin');
%
%   See also:  dgtlength, psech, firwin, pbspline, setnorm
%
%   Demos:  demo_pgauss
%
%   References: mazh93

% AUTHOR : Peter L. Søndergaard.

%   First reference on this found in mazh93 eq. 63

if nargin<1
  error('Too few input parameters.');
end;

if (prod(size(L,1))~=1 || ~isnumeric(L))
  error('L must be a scalar');
end;

if rem(L,1)~=0
  error('L must be an integer.')
end;

% Define initial value for flags and key/value pairs.
definput.import={'setnorm'};

definput.flags.centering={'wp','hp'};
definput.flags.delay={'nodelay','delay'};
definput.flags.width={'tfr','width','bw'};

definput.keyvals.tfr=1;
definput.keyvals.delay=0;
definput.keyvals.width=0;
definput.keyvals.fs=[];
definput.keyvals.cf=0;
definput.keyvals.bw=0;
definput.keyvals.atheight=[];

[flags,keyvals,tfr]=ltfatarghelper({'tfr'},definput,varargin);

if (prod(size(tfr,1))~=1 || ~isnumeric(tfr))
  error('tfr must be a scalar.');
end;

if ~isempty(keyvals.atheight) && ~flags.do_width
    error(['%s: Param. ''atheight'' must be used together with param.',...
           ' ''width''. '],upper(mfilename));
end

if isempty(keyvals.atheight)
    keyvals.atheight = 0.5;
end

if keyvals.atheight >= 1 || keyvals.atheight <=0
    error('%s: Param. ''atheight'' must be in the range ]0,1[.',...
           upper(mfilename));
end

fs=keyvals.fs;

if flags.do_wp
  cent=0;
else
  cent=0.5;
end;

if isempty(fs)

  if flags.do_width
     tfr=pi/(4*log(1/keyvals.atheight))*keyvals.width^2/L;
  end;

  if flags.do_bw
     tfr=L/(keyvals.bw*L/2)^2;
  end;

  delay_s=keyvals.delay;
  cf_s   =keyvals.cf;
else

  if flags.do_width
    tfr=(keyvals.width*fs)^2/L;
  end;

  if flags.do_bw
    tfr=L/(keyvals.bw/fs*L)^2;
  end;

  delay_s=keyvals.delay*fs;
  cf_s   =keyvals.cf/fs*L;
end;

g=comp_pgauss(L,tfr,cent-delay_s,cf_s);

g=setnorm(g,flags.norm);


function [J, grad] = costFunction(theta, X, y)
%COSTFUNCTION Compute cost and gradient for logistic regression
%   J = COSTFUNCTION(theta, X, y) computes the cost of using theta as the
%   parameter for logistic regression and the gradient of the cost
%   w.r.t. to the parameters.

% Initialize some useful values
m = length(y); % number of training examples

% You need to return the following variables correctly
J = 0;
grad = zeros(size(theta));

h = sigmoid(X*theta);

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the cost of a particular choice of theta.
%               You should set J to the cost.
%               Compute the partial derivatives and set grad to the partial
%               derivatives of the cost w.r.t. each parameter in theta
%
% Note: grad should have the same dimensions as theta
%

J = (-y'*log(h)-(1-y)'*log(1-h))/m;

grad = X'*(h-y)/m;

% =============================================================

end


function q = sphere_stereograph2 ( p, focus, center )

%*****************************************************************************80
%
%% SPHERE_STEREOGRAPH2 computes the stereographic image of points on a sphere.
%
%  Discussion:
%
%    We start with a sphere of center C.
%
%    F is a point on the sphere which is the focus of the mapping,
%    and the antipodal point 2*C-F is the point of tangency
%    to the sphere of a plane.
%
%    For any point P on the sphere, the stereographic projection Q of the
%    point is defined by drawing the line from F through P, and computing
%    Q as the intersection of this line with the plane.
%
%    The spatial dimension M is arbitrary, but should be at least 2.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 November 2010
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    C F Marcus,
%    The stereographic projection in vector notation,
%    Mathematics Magazine,
%    Volume 39, Number 2, March 1966, pages 100-102.
%
%  Parameters:
%
%    Input, real P(M,N), a set of points on the unit sphere.
%
%    Input, real FOCUS(M,1), the coordinates of the focus point.
%
%    Input, real CENTER(M,1), the coordinates of the center of the sphere.
%
%    Output, real Q(M,N), the coordinates of the image points,
%
  [ m, n ] = size ( p );

  ff = repmat ( focus, 1, n );

  s(1,1:n) = 2.0 * sum ( ( center - focus ).^2 ) ...
    ./ ( ( center - focus )' * ( p - ff ) );

  ss = repmat ( s, m, 1 );

  q = ss .* p + ( 1.0 - ss ) .* ff;

  return
end


function jac = p21_jac ( neqn, t, y )

%*****************************************************************************80
%
%% P21_JAC evaluates the jacobian for problem p21.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer NEQN, the number of equations.
%
%    Input, real T, Y(NEQN), the arguments of the jacobian.
%
%    Output, real JAC(NEQN,NEQN), the jacobian matrix.
%
  jac = zeros ( neqn, neqn );

  jac(1,1) = 0.0;
  jac(1,2) = 1.0;

  jac(2,1) = - 1.0 + 0.25 / ( t + 1.0 ).^2;
  jac(2,2) = - 1.0 / ( t + 1.0 );

  return
end


function [ r, center ] = circle_dia2imp_2d ( p1, p2 )

%*****************************************************************************80
%
%% CIRCLE_DIA2IMP_2D converts a diameter to an implicit circle in 2D.
%
%  Discussion:
%
%    The diameter form of a circle is:
%
%      P1 and P2 are the endpoints of a diameter.
%
%    The implicit form of a circle in 2D is:
%
%      ( X - CENTER(1) )^2 + ( Y - CENTER(2) )^2 = R^2
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 December 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real P1(2,1), P2(2,1), two points that are the
%    endpoints of a diameter of the circle.
%
%    Output, real R, the radius of the circle.
%
%    Output, real CENTER(2,1), the center of the circle.
%
  r = 0.5 * sqrt ( sum ( ( p2(1:2,1) - p1(1:2,1) ).^2 ) );

  center(1:2,1) = 0.5 * ( p1(1:2,1) + p2(1:2,1) );

  return
end


% P3.11
colordef white; clear;  clc;
M = 250;    k = -M:M;   w = (pi/M)*k;   % [0, pi] axis divided into 501 points.
w0 = pi/2;  figure(1);
n = -50:50;

h = (0.9).^(abs(n));
H = dtft(h,n,w);
subplot(3,2,1); plot(w/pi,abs(H),'k');
xlabel('frequency in pi units');    ylabel('|H|');  title('Magnitude Response');
subplot(3,2,2); plot(w/pi,angle(H)/pi,'k');
xlabel('frequency in pi units');    ylabel('\Theta');   title('Phase Response');

h = sinc(0.2*n).*((stepseq(-20,-50,50)-stepseq(20,-50,50)));
H = dtft(h,n,w);
subplot(3,2,3); plot(w/pi,abs(H),'k');
xlabel('frequency in pi units');    ylabel('|H|');  title('Magnitude Response');
subplot(3,2,4); plot(w/pi,angle(H)/pi,'k');
xlabel('frequency in pi units');    ylabel('\Theta');   title('Phase Response');

h = sinc(0.2*n).*((stepseq(0,-50,50)-stepseq(40,-50,50)));
H = dtft(h,n,w);
subplot(3,2,5); plot(w/pi,abs(H),'k');
xlabel('frequency in pi units');    ylabel('|H|');  title('Magnitude Response');
subplot(3,2,6); plot(w/pi,angle(H)/pi,'k');
xlabel('frequency in pi units');    ylabel('\Theta');   title('Phase Response');

figure(2);
h = ((0.5).^n+(0.4).^n).*stepseq(0,-50,50);
H = dtft(h,n,w);
subplot(3,2,1); plot(w/pi,abs(H),'k');
xlabel('frequency in pi units');    ylabel('|H|');  title('Magnitude Response');
subplot(3,2,2); plot(w/pi,angle(H)/pi,'k');
xlabel('frequency in pi units');    ylabel('\Theta');   title('Phase Response');

h = (0.5).^(abs(n)).*cos(0.1*pi*n);
H = dtft(h,n,w);
subplot(3,2,3); plot(w/pi,abs(H),'k');
xlabel('frequency in pi units');    ylabel('|H|');  title('Magnitude Response');
subplot(3,2,4); plot(w/pi,angle(H)/pi,'k');
xlabel('frequency in pi units');    ylabel('\Theta');   title('Phase Response');


function Y = inv_chol(L)
% Matrix Inversion using Cholesky Decomposition
%
% Finds the inverse of the matrix X, given its (lower triangular) Cholesky
% Decomposition; i.e. X = LL', according to the paper 'Matrix Inversion
% Using Cholesky Decomposition', Aravindh Krishnamoorthy, Deepak Menon,
% arXiv:1111.4144.
%

% Version 0.1, 2013-05-25, Aravindh Krishnamoorthy
% e-mail: aravindh.k@ieee.org

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Initializations
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
N = size(L, 1) ;
Y = zeros(N, N) ;
% Work with the upper triangular matrix
R = L' ;
% Construct the auxillary diagonal matrix S = 1/rii
S = inv(diag(diag(R))) ;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Algorithm
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for j=N:-1:1
    for i=j:-1:1
        Y(i,j) = S(i,j) - R(i,i+1:end)*Y(i+1:end,j) ;
        Y(i,j) = Y(i,j)/R(i,i) ;
        % Write out the symmetric element
        Y(j,i) = conj(Y(i,j)) ;
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Test
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% N = 4 ;
% X = complex(randn(N, N), randn(N, N)) ;
% X = X'*X ;
% L = chol(X, 'lower') ;
% I = inv_chol(L) ;
% norm(I-inv(X))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


function vol=elemvolume(node,elem,option)
%
% vol=elemvolume(node,elem,option)
%
% calculate the volume for a list of simplexes
%
% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% date: 2007/11/21
%
% input:
%    node:  node coordinates
%    elem:  element table of a mesh
%    option: if option='signed', the volume is the raw determinant,
%            else, the results will be the absolute values
%
% output:
%    vol:   volume values for all elements
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

if(size(elem,2)==size(node,2))
	enum=size(elem,1);
	vol=zeros(enum,1);
	acol=ones(3,1);
	for i=1:enum
		e1=det([node(elem(i,:),2),node(elem(i,:),3),acol]);
		e2=det([node(elem(i,:),3),node(elem(i,:),1),acol]);
		e3=det([node(elem(i,:),1),node(elem(i,:),2),acol]);
		vol(i)=sqrt(e1*e1+e2*e2+e3*e3)/2;
	end
	return;
end
dim=size(elem,2);
enum=size(elem,1);
vol=zeros(enum,1);
for i=1:enum
    detmat=[node(elem(i,:),:)';ones(1,dim)];
    vol(i)=det(detmat);
end
if(nargin==3 && strcmp(option,'signed'))
  vol=vol/prod(1:size(node,2));
else
  vol=abs(vol)/prod(1:size(node,2));
end


function [ i, j ] = i4_to_triangle ( k )

%*****************************************************************************80
%
%% I4_TO_TRIANGLE converts an integer to triangular coordinates.
%
%  Discussion:
%
%    Triangular coordinates are handy when storing a naturally triangular
%    array (such as the lower half of a matrix) in a linear array.
%
%    Thus, for example, we might consider storing
%
%    (1,1)
%    (2,1) (2,2)
%    (3,1) (3,2) (3,3)
%    (4,1) (4,2) (4,3) (4,4)
%
%    as the linear array
%
%    (1,1) (2,1) (2,2) (3,1) (3,2) (3,3) (4,1) (4,2) (4,3) (4,4)
%
%    Here, the quantities in parenthesis represent the natural row and
%    column indices of a single number when stored in a rectangular array.
%
%    In this routine, we are given the location K of an item in the
%    linear array, and wish to determine the row I and column J
%    of the item when stored in the triangular array.
%
%  First Values:
%
%     K  I  J
%
%     0  0  0
%     1  1  1
%     2  2  1
%     3  2  2
%     4  3  1
%     5  3  2
%     6  3  3
%     7  4  1
%     8  4  2
%     9  4  3
%    10  4  4
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 July 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer K, the linear index of the (I,J) element, which
%    must be nonnegative.
%
%    Output, integer I, J, the row and column indices.
%
  if ( k < 0 )

    fprintf ( 1, '\n' );
    fprintf ( 1, 'I4_TO_TRIANGLE - Fatal error!\n' );
    fprintf ( 1, '  K < 0.\n' );
    fprintf ( 1, '  K = %d\n', k );
    error ( 'I4_TO_TRIANGLE - Fatal error!' );

  elseif ( k == 0 )

    i = 0;
    j = 0;
    return

  end

  i = floor ( sqrt ( 2 * k ) );

  if ( i * i + i < 2 * k )
    i = i + 1;
  end

  j = k - ( i * ( i - 1 ) ) / 2;

  return
end


function c = tone2cent(t1,t2)
% MUSIC.TONE2CENT Returns the number of cents between two semitones.
%    C = MUSIC.TONE2CENT(T) returns the number of cents between T and middle C
%    (C4). T is a semitone interval defined relative to C4.
%
%    C = MUSIC.TONE2CENT(T1,T2) returns the number of cents between T1 and T2.
%    T1 and T2 are musical semitones defined relative to C4. T1 and T2 may be
%    vectors of the same size, or one may be scalar.
%
%    Examples
%       c = music.tone2cent(12);         % returns 1200
%       c = music.tone2cent(-3,-1);      % returns 200
%       c = music.tone2cent([-3 9],-1);  % returns [200 -1000]
%
%    See also music.tone2freq, music.tone2interval, music.tone2note.

%    Author: E. Johnson
%    Copyright 2010 The MathWorks, Inc.

if nargin < 2
    t2 = t1;
    t1 = 0;
end

f1 = music.tone2freq(t1);
f2 = music.tone2freq(t2);

% Could call MUSIC.FREQ2TONE but it is easy to inline this simple calclation.
c  = 1200 * log2( f2 ./ f1 );


function dist = sphere_distance2 ( lat1, lon1, lat2, lon2, r )

%*****************************************************************************80
%
%% SPHERE_DISTANCE2 computes great circle distances on a sphere.
%
%  Discussion:
%
%    This computation is written in terms of haversines, and can be more
%    accurate when measuring small angular distances.  It can be somewhat
%    inaccurate when the two points are antipodal.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 February 2009
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    "Great-circle distance",
%    Wikipedia.
%
%  Parameters:
%
%    Input, real LAT1, LON1, the latitude and longitude of
%    the first point.
%
%    Input, real LAT2, LON2, the latitude and longitude of
%    the second point.
%
%    Input, real R, the radius of the sphere.
%
%    Output, real DIST, the great circle distance between
%    the points, measured in the same units as R.
%
  s = ( sin ( ( lat1 - lat2 ) / 2.0 ) ).^2 ...
    + cos ( lat1 ) * cos ( lat2 ) * ( sin ( ( lon1 - lon2 ) / 2.0 ) ).^2;

  s = sqrt ( s );

  dist = 2.0 * r * asin ( s );

  return
end


function p = kspaceLineRecon(p, dy, dt, c, varargin)
%KSPACELINERECON    2D linear FFT reconstruction.
%
% DESCRIPTION:
%       kspaceLineRecon takes an acoustic pressure time-series p_ty
%       recorded over an evenly spaced array of sensor points on a line,
%       and constructs an estimate of the initial acoustic pressure
%       distribution that gave rise to those measurements using an
%       algorithm based on the FFT. The input p_ty must be indexed
%       p_ty(time step, sensor y position), where the sensor spacing is given
%       by dy, the temporal spacing given by dt, and the sound speed in the
%       propagation medium (which is assumed to be acoustically
%       homogeneous) is given by c. The output p_xy is indexed as
%       p_xy(x position, y position).
%
%       The code uses a k-space algorithm which performs (1) a Fourier
%       transform on the data p_ty along both t and y dimensions (into
%       wavenumber-frequency space, where the wavenumber component is along
%       the detector line), (2) a mapping, based on the dispersion relation
%       for a plane wave in an acoustically homogeneous medium, from
%       wavenumber-frequency space to wavenumber-wavenumber space (where
%       the second component is orthogonal to the detector line), and
%       finally (3) an inverse Fourier transform back from the wavenumber
%       domain to the spatial domain. The result is an estimate of the
%       initial acoustic pressure distribution from which the acoustic
%       waves originated.
%
%       Steps (1) and (3) can be performed efficiently using the fast
%       Fourier transform (FFT); they are therefore fastest when the number
%       of samples and number of detector points are both powers of 2. The
%       mapping in step (2) requires an interpolation of the data from an
%       evenly spaced grid of points in the wavenumber-frequency domain to
%       an evenly-spaced grid of points in the wavenumber-wavenumber
%       domain. The option 'Interp' may be used to choose the interpolation
%       method.
%
%       The physics of photoacoustics requires that the acoustic pressure
%       is initially non-negative everywhere. The estimate of the initial
%       pressure distribution generated by this code may have negative
%       regions due to artefacts arising from differences between the
%       assumed model and the real situation, e.g., homogeneous medium vs.
%       real, somewhat heterogeneous, medium; infinite measurement surface
%       vs. finite-sized region-of-detection, etc. A positivity (or
%       non-negativity) condition can be enforced by setting the optional
%       'PosCond' to true which simply sets any negative parts of the final
%       image to zero.
%
% USAGE:
%       p_xy = kspaceLineRecon(p_ty, dy, dt, c)
%       p_xy = kspaceLineRecon(p_ty, dy, dt, c, ...)
%
% INPUTS:
%       p_ty        - pressure time-series recorded over an evenly spaced
%                     array of sensor points on a line (indexed as t, y)
%       dy          - spatial step [m]
%       dt          - time step [s]
%       c           - acoustically-homogeneous sound speed [m/s]
%
% OPTIONAL INPUTS:
%       Optional 'string', value pairs that may be used to modify the
%       default computational settings.
%
%       'DataOrder' - String input which sets the data order (default =
%                     'ty'). Valid inputs are 'ty' and 'yt'
%       'Interp'    - string input controlling the interpolation method
%                     used by interp2 in the reconstruction (default =
%                     '*nearest')
%       'Plot'      - Boolean controlling whether a plot of the
%                     reconstructed estimate of the initial acoustic
%                     pressure distribution is produced (default = false).
%       'PosCond'   - Boolean controlling whether a positivity condition is
%                     enforced on the reconstructed estimate of the initial
%                     acoustic pressure distribution (default = false).
%
% OUTPUTS:
%       p_xy        - estimate of the initial acoustic pressure
%                     distribution (indexed as x, y)
%
% ABOUT:
%       author      - Bradley Treeby and Ben Cox
%       date        - 11th January 2009
%       last update - 13th August 2014
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox
%
% See also interp2, kspacePlaneRecon, makeGrid

% This file is part of k-Wave. k-Wave is free software: you can
% redistribute it and/or modify it under the terms of the GNU Lesser
% General Public License as published by the Free Software Foundation,
% either version 3 of the License, or (at your option) any later version.
%
% k-Wave is distributed in the hope that it will be useful, but WITHOUT ANY
% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
% FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
% more details.
%
% You should have received a copy of the GNU Lesser General Public License
% along with k-Wave. If not, see <http://www.gnu.org/licenses/>.

% Error: interp2 error in Matlab R2012b
matlab_ver = ver('matlab');
if strcmp(matlab_ver.Release, '(R2012b)')
    error('This function will not run in Matlab R2012b because of a bug in Matlab''s function interp2. It does work in prior and subsequent versions of Matlab.')
end

% start timer
tic;

% define defaults
num_req_inputs = 4;
data_order = 'ty';
interp_method = '*nearest';
plot_recon = false;
positivity_cond = false;

% replace with user defined values if provided
if nargin < num_req_inputs
    error('Incorrect number of inputs');
elseif ~isempty(varargin)
    for input_index = 1:2:length(varargin)
        switch varargin{input_index}
            case 'DataOrder'
                data_order = varargin{input_index + 1};
                if ~strcmp(data_order, 'ty') && ~strcmp(data_order, 'yt')
                    error('Unknown setting for optional input DataOrder');
                end
            case 'Interp'
                interp_method = varargin{input_index + 1};
            case 'Plot'
                plot_recon = varargin{input_index + 1};
            case 'PlotRecon'
                plot_recon = varargin{input_index + 1};
            case 'PosCond'
                positivity_cond = varargin{input_index + 1};
            otherwise
                error('Unknown optional input');
        end
    end
end

% reorder the data if needed (p_ty)
if strcmp(data_order, 'yt')
    p = p.';
end

% mirror the time domain data about t = 0 to allow the cosine transform to
% be computed using an FFT (p_ty)
p = [flipdim(p, 1); p(2:end, :)];

% extract the size of mirrored input data
[Nt, Ny] = size(p);

% update command line status
disp('Running k-Wave line reconstruction...');
disp(['  grid size: ' num2str(Ny) ' by ' num2str((Nt+1)/2) ' grid points']);
disp(['  interpolation mode: ' interp_method]);

% create a computational grid that is evenly spaced in w and ky, where
% Nx = Nt and dx = dt*c
kgrid = makeGrid(Nt, dt*c, Ny, dy);

% from the grid for kx, create a computational grid for w using the
% relation dx = dt*c; this represents the initial sampling of p(w, ky)
w = c*kgrid.kx;

% remap the computational grid for kx onto w using the dispersion
% relation w/c = (kx^2 + ky^2)^1/2. This gives an w grid that is
% evenly spaced in kx. This is used for the interpolation from p(w, ky)
% to p(kx, ky). Only real w is taken to force kx (and thus x) to be
% symmetrical about 0 after the interpolation.
w_new = (c*kgrid.k);

% calculate the scaling factor using the value of kx, where
% kx = sqrt( (w/c).^2 - kgrid.ky.^2 ) and then manually
% replacing the DC value with its limit (otherwise NaN results)
sf = c^2*sqrt( (w/c).^2 - kgrid.ky.^2)./(2*w);
sf(w == 0 & kgrid.ky == 0) = c/2;

% compute the FFT of the input data p(t, y) to yield p(w, ky) and scale
p = sf.*fftshift(fftn(fftshift(p)));

% remove unused variables
clear sf;

% exclude the inhomogeneous part of the wave
p(abs(w) < abs(c*kgrid.ky)) = 0;

% compute the interpolation from p(w, ky) to p(kx, ky)and then force to be
% symmetrical
p = interp2(kgrid.ky, w, p, kgrid.ky, w_new, interp_method);

% remove unused variables
clear kgrid w;

% set values outside the interpolation range to zero
p(isnan(p)) = 0;

% compute the inverse FFT of p(kx, ky) to yield p(x, y)
p = real(ifftshift(ifftn(ifftshift(p))));

% remove the left part of the mirrored data which corresponds to the
% negative part of the mirrored time data
p = p( (Nt + 1)/2:Nt, :);

% correct the scaling - the forward FFT is computed with a spacing of dt
% and the reverse requires a spacing of dy = dt*c, the reconstruction
% assumes that p0 is symmetrical about y, and only half the plane collects
% data (first approximation to correcting the limited view problem)
p = 2*2*p./c;

% enfore positivity condition
if positivity_cond
    disp('  applying positivity condition...');
    p(p < 0) = 0;
end

% update command line status
disp(['  computation completed in ' scaleTime(toc)]);

% plot the reconstruction
if plot_recon

    % allocate axis dimensions
    x_axis = [0 (Nt/2)*dt*c];
    y_axis = [0 Ny*dy];

    % select suitable axis scaling factor
    [x_sc, scale, prefix] = scaleSI(max([Ny*dy, (Nt/2)*dt*c]));

    % select suitable plot scaling factor
    plot_scale = max(p(:));

    % create the figure
    figure;
    imagesc(y_axis*scale, x_axis*scale, p, [-plot_scale, plot_scale]);
    axis image;
    colormap(getColorMap);
    xlabel(['Sensor Position [' prefix 'm]']);
    ylabel(['Depth [' prefix 'm]']);
    colorbar;
end


function a = prolate ( alpha, n )

%*****************************************************************************80
%
%% PROLATE returns the PROLATE matrix.
%
%  Formula:
%
%    If ( I == J )
%      A(I,J) = 2 * ALPHA
%    else
%      K = abs ( I - J ) + 1
%      A(I,J) = sin ( 2 * pi * ALPHA * K ) / ( pi * K )
%
%  Example:
%
%    N = 5, ALPHA = 0.25
%
%     0.5        0.0       -0.106103   0.0        0.0636620
%     0.0        0.5        0.0       -0.106103   0.0
%    -0.106103   0.0        0.5        0.0       -0.106103
%     0.0       -0.106103   0.0        0.5        0.0
%     0.0636620  0.0       -0.106103   0.0        0.5
%
%  Properties:
%
%    A is symmetric: A' = A.
%
%    Because A is symmetric, it is normal.
%
%    Because A is normal, it is diagonalizable.
%
%    A is persymmetric: A(I,J) = A(N+1-J,N+1-I).
%
%    A is centrosymmetric: A(I,J) = A(N+1-I,N+1-J).
%
%    A is Toeplitz: constant along diagonals.
%
%    If 0 < ALPHA < 0.5, then
%      A is positive definite,
%      the eigenvalues of A are distinct,
%      the eigenvalues lie in (0,1) and cluster around 0 and 1.
%
%    The family of matrices is nested as a function of N.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 October 2007
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    James Varah,
%    The Prolate Matrix,
%    Linear Algebra and Applications,
%    Volume 187, pages 269-278, 1993.
%
%  Parameters:
%
%    Input, real ALPHA, the parameter.
%
%    Input, integer N, the order of A.
%
%    Output, real A(N,N), the matrix.
%
  a = zeros ( n, n );

  for i = 1 : n

    for j = 1 : n

      if ( i == j )
        a(i,j) = 2.0 * alpha;
      else
        k = abs ( i - j ) + 1;
        angle = 2.0 * pi * alpha * k;
        a(i,j) = sin ( angle ) / ( pi * k );
      end

    end

  end

  return
end


function value = trinomial ( i, j, k )

%*****************************************************************************80
%
%% TRINOMIAL computes a trinomial coefficient.
%
%  Location:
%
%    http://people.sc.fsu.edu/~jburkardt/m_src/triangle_integrals/trinomial.m
%
%  Discussion:
%
%    The trinomial coefficient is a generalization of the binomial
%    coefficient.  It may be interpreted as the number of combinations of
%    N objects, where I objects are of type 1, J of type 2, and K of type 3.
%    and N = I + J + K.
%
%    T(I,J,K) = N! / ( I! J! K! )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 April 2015
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer I, J, K, the factors.
%    All should be nonnegative.
%
%    Output, integer VALLUE, the trinomial coefficient.
%

%
%  Each factor must be nonnegative.
%
  if ( i < 0 || j < 0 || k < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TRINOMIAL - Fatal error%\n' );
    fprintf ( 1, '  Negative factor encountered.\n' );
    error ( 'TRINOMIAL - Fatal error%' );
  end

  value = 1;

  t = 1;

  for l = 1 : i
%   value = value * t / l;
    t = t + 1;
  end

  for l = 1 : j
    value = value * t / l;
    t = t + 1;
  end

  for l = 1 : k
    value = value * t / l;
    t = t + 1;
  end

  return
end


function G = filterGauss( dims, mu, C, show )
% n-dimensional Gaussian filter.
%
% Creates an image of a Gaussian with arbitrary covariance matrix. The
% dimensionality and size of the filter is determined by dims (eg dims=[10
% 10] creates a 2D filter of size 10x10). If mu==[], it is calculated to be
% the center of the n-dim image.  C can be a full nxn covariance matrix, or
% an nx1 vector of variance.  In the latter case C is calculated as
% C=diag(C). If C=[]; then C=(dims/6).^2, ie it is transformed into a
% vector of variances such that along each dimension the variance is equal
% to (siz/6)^2.
%
% USAGE
%  G = filterGauss( dims, [mu], [C], [show] )
%
% INPUTS
%  dims    - n element vector of dimensions of final Gaussian
%  mu      - [] n element vector specifying the mean
%  C       - [] nxn cov matrix, nx1 set of vars, or variance
%  show    - [0] figure to use for optional display
%
% OUTPUTS
%  G       - image of the created Gaussian
%
% EXAMPLE
%  g = filterGauss( 21, [], 4, 1); %1D
%  sig=3; G = filterGauss( 4*[sig sig] + 1, [], [sig sig].^2, 2 ); %2D
%  R = rotationMatrix( [1,1,0], pi/4 );
%  C = R'*[10^2 0 0; 0 5^2 0; 0 0 16^2]*R;
%  G3 = filterGauss( [51,51,51], [], C, 3 ); %3D
%
% See also NORMPDF2
%
% Piotr's Image&Video Toolbox      Version 2.0
% Copyright 2012 Piotr Dollar.  [pdollar-at-caltech.edu]
% Please email me if you find bugs, or have suggestions or questions!
% Licensed under the Simplified BSD License [see external/bsd.txt]

nd = length( dims );
if( nargin<2 || isempty(mu)); mu=(dims+1)/2; end
if( nargin<3 || isempty(C)); C=(dims/6).^2; end
if( nargin<4 || isempty(show) ); show=0; end

if( length(mu)~=nd ); error('invalid mu'); end

if( nd==1 ) % fast special case
  xs = 1:dims(1);
  G = exp(-(xs-mu).*(xs-mu)/(2*C))';

else
  % make C have correct dimensions
  if( numel(C)==1 ); C=repmat(C,[1 nd]); end
  if( size(C,1)==1 || size(C,2)==1 ); C=diag(C); end
  if( any(size(C)~=nd)); error( 'invalid C'); end

  % get vector of grid locations
  temp = cell(1,nd);
  for d=1:nd; temp{d} = 1:dims(d); end
  [ temp{:}] = ndgrid( temp{:} );
  xs = zeros( nd, prod(dims) );
  for d=1:nd; xs( d, : ) = temp{d}(:)'; end

  % evaluate the Gaussian at those points
  G = normpdf2( xs, mu, C );
  if( nd>1 ); G = reshape( G, dims ); end
end

% suppress very small values and normalize
G(G<eps*max(G(:))*10) = 0;
G = G/sum(G(:));

% display
if( show );
  if( nd==3 )
    filterVisualize( G, show, .2 );
  else
    filterVisualize( G, show );
  end
end


%% Some parameters to set - make sure that your code works at image borders!
close all;
patchSize = 5;
sigma = 20; % standard deviation (different for each image!)
h = 0.55; %decay parameter
windowSize = 15; % --> it takes 99 seconds to run

%NOTE: for each image, please also read its CORRESPONDING 'clean' or
%reference image. We will need this later to do some analysis
%NOTE2: the noise level is different for each image (it is 20, 10, and 5 as
%indicated in the image file names)
%NOTE3 : all the functions to denoise the image work both with grayscale
%images and with RGB images

%Load the image to denoise and the refernce image
imageNoisy = imread('images/alleyNoisy_sigma20.png');
imageReference = imread('images/alleyReference.png');

% converting the image in grayscale is much faster roughly 3 times faster
imageNoisy = rgb2gray(imageNoisy);
imageReference = rgb2gray(imageReference);

% we can resize the image so the code can run even faster
%imageNoisy = imresize(imageNoisy, 0.5);
%imageReference = imresize(imageReference, 0.5);

% Implement the non-local means functions and compare the performances

%############################## SIGMA = 20 ######################
% tic
% filtered = nonLocalMeansWithoutIntegral(imageNoisy, sigma, h, patchSize, windowSize, false);
% toc
%
% figure('name', 'NL-Means Denoised Image with Naive Approach -- SIGMA = 20 h = 0.55');
% imshow(filtered);

tic
filtered = nonLocalMeans(imageNoisy, sigma, h, patchSize, windowSize, false);
toc

figure('name', 'NL-Means Denoised Image with Integral Images Approach -- SIGMA = 20 h = 1');
imshow(filtered);

h = 0.15;

% tic
% filtered = nonLocalMeansWithoutIntegral(imageNoisy, sigma, h, patchSize, windowSize, false);
% toc
%
% figure('name', 'NL-Means Denoised Image with Naive Approach -- SIGMA = 20 h = 0.25');
% imshow(filtered);

tic
filtered = nonLocalMeans(imageNoisy, sigma, h, patchSize, windowSize, false);
toc

figure('name', 'NL-Means Denoised Image with Integral Images Approach -- SIGMA = 20 h = 0.25');
imshow(filtered);

%############################### SIGMA = 5 ####################

imageNoisy = imread('images/townNoisy_sigma5.png');
imageReference = imread('images/townReference.png');

% converting the image in grayscale is much faster roughly 3 times faster
imageNoisy = rgb2gray(imageNoisy);
imageReference = rgb2gray(imageReference);

sigma = 5; % standard deviation (different for each image!)
h = 0.55; %decay parameter

% tic
% filtered = nonLocalMeansWithoutIntegral(imageNoisy, sigma, h, patchSize, windowSize, false);
% toc
%
% figure('name', 'NL-Means Denoised Image with Naive Approach -- SIGMA = 5 h = 0.55');
% imshow(filtered);

tic
filtered = nonLocalMeans(imageNoisy, sigma, h, patchSize, windowSize, false);
toc

figure('name', 'NL-Means Denoised Image with Integral Images Approach -- SIGMA = 5 h = 0.55');
imshow(filtered);

h = 0.25;

% tic
% filtered = nonLocalMeansWithoutIntegral(imageNoisy, sigma, h, patchSize, windowSize, false);
% toc
%
% figure('name', 'NL-Means Denoised Image with Naive Approach -- SIGMA = 5 h = 0.25');
% imshow(filtered);

tic
filtered = nonLocalMeans(imageNoisy, sigma, h, patchSize, windowSize, false);
toc

figure('name', 'NL-Means Denoised Image with Integral Images Approach -- SIGMA = 5 h = 0.25');
imshow(filtered);

%% Let's show your results!

%Show the denoised image
% figure('name', 'NL-Means Denoised Image');
% imshow(filtered);

%Show difference image
diff_image = abs(imageReference - filtered);
figure('name', 'Difference Image');
imshow(diff_image ./ max(max((diff_image))));

%Print some statistics ((Peak) Signal-To-Noise Ratio)
disp('For Noisy Input');
[peakSNR, SNR] = psnr(imageNoisy, imageReference);
disp(['SNR: ', num2str(SNR, 10), '; PSNR: ', num2str(peakSNR, 10)]);

disp('For Denoised Result');
[peakSNR, SNR] = psnr(filtered, imageReference);
disp(['SNR: ', num2str(SNR, 10), '; PSNR: ', num2str(peakSNR, 10)]);

%Feel free (if you like only :)) to use some other metrics (Root
%Mean-Square Error (RMSE), Structural Similarity Index (SSI) etc.)


function [tfr,t,f] = tfrmh(x,t,N,trace);
%TFRMH	Margenau-Hill time-frequency distribution.
%	[TFR,T,F]=TFRMH(X,T,N,TRACE) computes the Margenau-Hill
%	distribution of a discrete-time signal X,
%	or the cross Margenau-Hill representation between two signals.
%
%	X     : signal if auto-MH, or [X1,X2] if cross-MH.
%	T     : time instant(s)          (default : 1:length(X)).
%	N     : number of frequency bins (default : length(X)).
%	TRACE : if nonzero, the progression of the algorithm is shown
%                                        (default : 0).
%	TFR   : time-frequency representation. When called without
%               output arguments, TFRMH runs TFRQVIEW.
%	F     : vector of normalized frequencies.
%
%	Example :
%	 sig=fmlin(128,0.1,0.4); tfrmh(sig,1:128,128,1);
%
%	See also  all the time-frequency representations listed in
%	 the file CONTENTS (TFR*)

%	F. Auger, May-August 1994, July 1995.
%	Copyright (c) 1996 by CNRS (France).
%
%  This program is free software; you can redistribute it and/or modify
%  it under the terms of the GNU General Public License as published by
%  the Free Software Foundation; either version 2 of the License, or
%  (at your option) any later version.
%
%  This program is distributed in the hope that it will be useful,
%  but WITHOUT ANY WARRANTY; without even the implied warranty of
%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%  GNU General Public License for more details.
%
%  You should have received a copy of the GNU General Public License
%  along with this program; if not, write to the Free Software
%  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

if (nargin == 0),
 error('At least 1 parameter required');
end;
[xrow,xcol] = size(x);
if (nargin == 1),
 t=1:xrow; N=xrow; trace=0;
elseif (nargin == 2),
 N=xrow; trace=0;
elseif (nargin == 3),
 trace = 0;
end;

if (N<0),
 error('N must be greater than zero');
end;
[trow,tcol] = size(t);
if (xcol==0) | (xcol>2),
 error('X must have one or two columns');
elseif (trow~=1),
 error('T must only have one row');
elseif (2^nextpow2(N)~=N),
 fprintf('For a faster computation, N should be a power of two\n');
end;

tfr= zeros (N,tcol) ;
if trace, disp('Margenau-Hill distribution'); end;
for icol=1:tcol,
 ti= t(icol); tau=-min([N-ti,xrow-ti]):(ti-1);
 indices= rem(N+tau,N)+1;
 if trace, disprog(icol,tcol,10); end;
 tfr(indices,icol)=x(ti,1)*conj(x(ti-tau,xcol));
end;

tfr= real(fft(tfr));

if (nargout==0),
 tfrqview(tfr,x,t,'tfrmh');
elseif (nargout==3),
 if rem(N,2)==0,
  f=[0:N/2-1 -N/2:-1]'/N;
 else
  f=[0:(N-1)/2 -(N-1)/2:-1]'/N;
 end;
end;


function [x, y] = theta2xy(theta1, theta2, l1, l2)
% Angle to Position Conversion for 2 link SCARA robot
%
% [Inputs]
%	theta1      : angle1 [deg]
%   theta2      : angle2 [deg]
%	l1          : link1 length [m]
%	l2          : link2 length [m]
% [Outputs]
%	x		    : x coordinate of the edge of link2 [m]
%   y			: y coordinate of the edge of link2 [m]

% deg to rad conversion
theta1 = theta1 * pi / 180;
theta2 = theta2 * pi / 180;

% position
x = l1 * cos(theta1) + l2 * cos(theta1 + theta2);
y = l1 * sin(theta1) + l2 * sin(theta1 + theta2);


function z = cheby_t_poly_zero ( n )

%*****************************************************************************80
%
%% CHEBY_T_POLY_ZERO returns zeroes of Chebyshev polynomials T(n,x).
%
%  Discussion:
%
%    The I-th zero of T(n,x) is cos((2*I-1)*PI/(2*N)), I = 1 to N
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 March 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of the polynomial.
%
%    Output, real Z(N), the zeroes of T(N)(X).
%
  for i = 1 : n
    angle = ( 2 * i - 1 ) * pi / real ( 2 * n );
    z(i) = cos ( angle );
  end

  return
end


%UPQ Central image moments
%
% M = UPQ(IM, P, Q) is the PQ'th central moment of the image IM.  That is,
% the sum of I(x,y).(x-x0)^P.(y-y0)^Q where (x0,y0) is the centroid.
%
% Notes::
% - The central moments are invariant to translation.
%
% See also UPQ_POLY, MPQ, NPQ.

% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Machine Vision Toolbox for Matlab (MVTB).
%
% MVTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% MVTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with MVTB.  If not, see <http://www.gnu.org/licenses/>.

function m = upq(im, p, q)

    [X,Y] = imeshgrid(im);

	m00 = mpq(im, 0, 0);
	xc = mpq(im, 1, 0) / m00;
	yc = mpq(im, 0, 1) / m00;

    m = sum(sum( im.*(X-xc).^p.*(Y-yc).^q ) );


function barycentric_interp_1d_test02 ( prob, nd )

%*****************************************************************************80
%
%% BARYCENTRIC_INTERP_1D_TEST02 tests LAGCHEBY2_INTERP_1D.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 August 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer PROB, the problem index.
%
%    Input, integer ND, the number of data points to use.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'BARYCENTRIC_INTERP_1D_TEST02:\n' );
  fprintf ( 1, '  Interpolate data from TEST_INTERP_1D problem #%d.\n', prob );
  fprintf ( 1, '  Use Chebyshev Type 2 spacing for data points.\n' );
  fprintf ( 1, '  Number of data points = %d\n', nd );
%
%  Define the data.
%
  a =  0.0;
  b = +1.0;
  xd = r8vec_cheby2space ( nd, a, b );
  yd = p00_f ( prob, nd, xd );

  if ( nd < 10 )
    r8vec2_print ( nd, xd, yd, '  Data array:' );
  end
%
%  #1:  Does the interpolant match the function at the interpolation points?
%
  ni = nd;
  xi = xd;
  yi = lagcheby2_interp_1d ( nd, xd, yd, ni, xi );

  int_error = norm ( yi - yd ) / ni;

  fprintf ( 1, '\n' );
  fprintf ( 1, '  L2 interpolation error averaged per interpolant node = %g\n', int_error );
%
%  #2: Plot the data.
%
  ni = 500;
  xi = r8vec_linspace ( ni, a, b );
  yi = lagcheby2_interp_1d ( nd, xd, yd, ni, xi );

  clf
  hold on
  plot ( xd, yd, 'b.', 'MarkerSize', 30 );
  plot ( xi, yi, 'r-', 'LineWidth', 3 );
  grid on
  xlabel ( '<---X--->' );
  ylabel ( '<---Y--->' );
  title ( sprintf ( 'Barycentric Lagrange Chebyshev2 Interpolant for %d nodes', nd ) )

  filename = sprintf ( 'p%02d_lagcheby2_%02d.png', prob, nd );
  print ( '-dpng', filename );
  fprintf ( 1, '  Created plot file "%s".\n', filename );

  return
end


function cdf = lorentz_cdf ( x )

%*****************************************************************************80
%
%% LORENTZ_CDF evaluates the Lorentz CDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 February 1999
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real X, the argument of the CDF.
%
%    Output, real CDF, the value of the CDF.
%
  cdf = 0.5 + atan ( x ) / pi;

  return
end


function [J, grad] = costFunction(theta, X, y)
%COSTFUNCTION Compute cost and gradient for logistic regression
%   J = COSTFUNCTION(theta, X, y) computes the cost of using theta as the
%   parameter for logistic regression and the gradient of the cost
%   w.r.t. to the parameters.

% Initialize some useful values
m = length(y); % number of training examples

% You need to return the following variables correctly
J = 0;
grad = zeros(size(theta));

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the cost of a particular choice of theta.
%               You should set J to the cost.
%               Compute the partial derivatives and set grad to the partial
%               derivatives of the cost w.r.t. each parameter in theta
%
% Note: grad should have the same dimensions as theta
%

h = sigmoid(X * theta);

J = (1 / m) * sum( (-y .* log(h)) - ((1 - y) .* log( 1 - h )) );

grad = (1 / m) * X' * (h - y);

% =============================================================

end


function pn = plane_imp_point_near_3d ( a, b, c, d, p )

%*****************************************************************************80
%
%% PLANE_IMP_POINT_NEAR_3D: nearest point on a implicit plane to a point in 3D.
%
%  Discussion:
%
%    The implicit form of a plane in 3D is:
%
%      A * X + B * Y + C * Z + D = 0
%
%    The normal N to the plane is (A,B,C).
%
%    The line defined by (XN-P(1))/A = (YN-P(2))/B = (ZN-P(3))/C = T
%    goes through P and is parallel to N.
%
%    Solving for the point (XN,YN,ZN) we get
%
%      XN = A*T+P(1)
%      YN = B*T+P(2)
%      ZN = C*T+P(3)
%
%    Now place these values in the equation for the plane:
%
%      A*(A*T+P(1)) + B*(B*T+P(2)) + C*(C*T+P(3)) + D = 0
%
%    and solve for T:
%
%      T = (-A*P(1)-B*P(2)-C*P(3)-D) / (A * A + B * B + C * C )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 March 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real A, B, C, D, the implicit plane parameters.
%
%    Input, real P(3), the coordinates of the point.
%
%    Output, real PN(3), the nearest point on the plane.
%
  dim_num = 3;

  if ( plane_imp_is_degenerate_3d ( a, b, c ) )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'PLANE_IMP_POINT_NEAR_3D - Fatal error!\n' );
    fprintf ( 1, '  A = B = C = 0.\n' );
    error ( 'PLANE_IMP_POINT_NEAR_3D - Fatal error!' );
  end

  t = - ( a * p(1) + b * p(2) + c * p(3) + d ) / ( a * a + b * b + c * c );

  pn(1) = p(1) + a * t;
  pn(2) = p(2) + b * t;
  pn(3) = p(3) + c * t;

  return
end


function d = mahalanobis(varargin)
%MAHALANOBIS Computes the Mahalanobis distance.
%   D = MAHALANOBIS(Y, X) computes the Mahalanobis distance between
%   each vector in Y to the mean (centroid) of the vectors in X, and
%   outputs the result in vector D, whose length is size(Y, 1).  The
%   vectors in X and Y are assumed to be organized as rows.  The
%   input data can be real of complex. The outputs are real
%   quantities.
%
%   D = MAHALANOBIS(Y, CX, MX) computes the Mahalanobis distance
%   between each vector in Y and the given mean vector, MX. The
%   results are output in vector D, whose length is size(Y, 1).  The
%   vectors in Y are assumed to be organized as the rows of this
%   array. The input data can be real or complex. The outputs are
%   real quantities. In addition to the mean vector MX, the
%   covariance matrix CX of a population of vectors X also must be
%   provided. Use function COVMATRIX (Section 11.5) to compute MX and
%   CX.

%   Copyright 2002-2004 R. C. Gonzalez, R. E. Woods, & S. L. Eddins
%   Digital Image Processing Using MATLAB, Prentice-Hall, 2004
%   $Revision: 1.5 $  $Date: 2003/10/26 23:19:44 $

% Reference: Acklam, P. J. [2002]. "MATLAB Array Manipulation Tips
% and Tricks." Available at
%     home.online.no/~pjacklam/matlab/doc/mtt/index.html
% or at
%     www.prenhall.com/gonzalezwoodseddins

param = varargin; % Keep in mind that param is a cell array.
Y = param{1};
ny = size(Y, 1); % Number of vectors in Y.

if length(param) == 2
   X = param{2};
   % Compute the mean vector and covariance matrix of the vectors
   % in X.
   [Cx, mx] = covmatrix(X);
elseif length(param) == 3 % Cov. matrix and mean vector provided.
   Cx = param{2};
   mx = param{3};
else
   error('Wrong number of inputs.')
end
mx = mx(:)'; % Make sure that mx is a row vector.

% Subtract the mean vector from each vector in Y.
Yc = Y - mx(ones(ny, 1), :);

% Compute the Mahalanobis distances.
d = real(sum(Yc/Cx.*conj(Yc), 2));


function partest(varargin)
%This function calculate the performance, based on Bayes theorem, of a
%clinical test.
%
% Syntax: 	PARTEST(X,ALPHA)
%
%     Input:
%           X is the following 2x2 matrix.
%           ALPHA - significance level for confidence intervals (default = 0.05).
%
%....................Affected(D+)..Healthy(D-)
%                    _______________________
%Positive Test(T+)  |   True    |  False    |
%                   | positives | positives |
%                   |___________|___________|
%                   |  False    |   True    |
%Negative Test(T-)  | negatives | negatives |
%                   |___________|___________|
%
%     Outputs:
%           - Prevalence
%           - Sensibility
%           - Specificity
%           - False positive and negative proportions
%           - False discovery and discovery rates
%           - Youden's Index and Number Needed to Diagnose (NDD)
%           - Positive predictivity
%           - Positive Likelihood Ratio
%           - Negative predictivity
%           - Negative Likelihood Ratio
%           - Predictive Summary Index (PSI) and Number Needed to Screen (NNS)
%           - Test Accuracy
%           - Mis-classification Rate
%           - F-Measure
%           - Test bias
%           - Error odds ratio
%           - Diagnostic odds ratio
%           - Discriminant Power
%
%      Example:
%
%
%           Calling on Matlab the function: partest
%           it will use a default matrix x=[731 270;78 1500] and alpha=0.05
%
%           Answer is:
%
%DIAGNOSTIC TEST PERFORMANCE PARAMETERS
% ----------------------------------------------------------------------------------------------------
% Prevalence: 31.4% (29.6% - 33.2%)
%
% Sensitivity (probability that test is positive on unhealthy subject): 90.4% (89.1% - 91.5%)
% False negative proportion: 9.6% (8.5% - 10.9%)
% False discovery rate: 27.0% (25.3% - 28.7%)
%
% Specificity (probability that test is negative on healthy subject): 84.7% (83.3% - 86.1%)
% False positive proportion: 15.3% (13.9% - 16.7%)
% False omission rate: 4.9% (4.2% - 5.9%)
%
% Youden's Index (a perfect test would have a Youden's index of +1): 0.7510
% Number Needed to Diagnose (NND): 1.33
% Around 14 persons need to be tested to return 10 positive tests for the presence of disease
%
% Precision or Predictivity of positive test
% (probability that a subject is unhealthy when test is positive): 73.0% (71.3% - 74.7%)
% Positive Likelihood Ratio: 5.9 (5.7 - 6.2)
% Moderate increase in possibility of disease presence
%
% Predictivity of negative test
% (probability that a subject is healthy when test is negative): 95.1% (94.1% - 95.8%)
% Negative Likelihood Ratio: 0.1138 (0.1094 - 0.1183)
% Moderate increase in possibility of disease absence
%
% Predictive Summary Index: 0.6808
% Number Needed to Screen (NNS): 1.47
% Around 15 persons need to be screened to avoid 10 events (i.e. death) for the presence of disease
%
% Accuracy or Potency: 86.5% (85.1% - 87.8%)
% Mis-classification Rate: 13.5% (12.2% - 14.9%)
% F-measure: 80.8% (79.2% - 82.3%)
%
% Test bias: 1.2373 (0.9474 - 1.6160)
% Test overestimates the phenomenon
% Error odds ratio: 1.6869 (1.2916 - 2.2032)
% Diagnostic odds ratio: 52.0655 (39.8649 - 68.0002)
% Discriminant Power: 2.2
%      A test with a discriminant value of 1 is not effective in discriminating between affected and unaffected individuals.
%      A test with a discriminant value of 3 is effective in discriminating between affected and unaffected individuals.
%
%
%           Created by Giuseppe Cardillo
%           giuseppe.cardillo-edta@poste.it
%
% To cite this file, this would be an appropriate format:
% Cardillo G. (2006). Clinical test performance: the performance of a
% clinical test based on the Bayes theorem.
% http://www.mathworks.com/matlabcentral/fileexchange/12705

%Input Error handling
args=cell(varargin);
nu=numel(args);
if nu>2
    error('Warning: Max two input data are required')
end
default.values = {[731 270;78 1500],0.05};
default.values(1:nu) = args;
[x alpha] = deal(default.values{:});

if nu>=1
    if isvector(x)
        error('Warning: PARTEST requires a 2x2 input matrix')
    end
    if ~all(isfinite(x(:))) || ~all(isnumeric(x(:))) || ~isequal(x,round(x))
        error('Warning: all matrix values must be numeric integer and finite')
    end
    [r,c] = size(x);
    if (r ~= 2 || c ~= 2)
        error('Warning: PARTEST requires a 2x2 input matrix')
    end
    clear r c
end
if nu>1
    if ~isscalar(alpha) || ~isnumeric(alpha) || ~isfinite(alpha) || isempty(alpha)
        error('Warning: it is required a numeric, finite and scalar ALPHA value.');
    end
    if alpha <= 0 || alpha >= 1 %check if alpha is between 0 and 1
        error('Warning: ALPHA must be comprised between 0 and 1.')
    end
end
clear args default nu

global z N

z=-realsqrt(2)*erfcinv(2-alpha);
cs=sum(x); %columns sum
rs=sum(x,2); %rows sums
N=sum(x(:)); %numbers of elements
d=diag(x); %true positives and true negatives

clc
disp('DIAGNOSTIC TEST PERFORMANCE PARAMETERS')
disp(repmat('-',1,100))
%Prevalence
%the prevalence of disease is estimated all D+/N
pr=(cs(1)/N);
%95% confidence interval critical value for Prevalence
prci=newcombe(pr);
fprintf('Prevalence: %0.1f%% (%0.1f%% - %0.1f%%)\n',pr*100,prci(1).*100,prci(2).*100)
disp(' ')

%Sensitivity and Specificity
%The Sensitivity is the probability that the test is positive on sick subjects: P(T+|D+)
%The Specificity is the probability that the test is negative on healthy subjects: P(T-|D-)
%In Matlab both parameters are obtained with only one instruction:
SS=d./cs'; %Sensitivity and Specificity
%Of course the false proportion is the complement to 1
fp=1-SS; %false proportions
%The false discovery rate is the probability that the disease is absent when the test is positive: P(D-|T+)
%The false omission rate is the probability that the disease is present when the test is negative: P(D+|T-)
fd=diag(rot90(x))./rs; %false discovery and omission rate

% 95% confidence intervals
Seci=newcombe(SS(1)); Spci=newcombe(SS(2));
fnci=newcombe(fp(1)); fpci=newcombe(fp(2));
fdci=newcombe(fd(1)); foci=newcombe(fd(2));
fprintf('Sensitivity (probability that test is positive on unhealthy subject): %0.1f%% (%0.1f%% - %0.1f%%)\n',SS(1)*100,Seci(1).*100,Seci(2).*100)
fprintf('False negative proportion: %0.1f%% (%0.1f%% - %0.1f%%)\n',fp(1)*100,fnci(1).*100,fnci(2).*100)
fprintf('False discovery rate: %0.1f%% (%0.1f%% - %0.1f%%)\n',fd(1)*100,fdci(1).*100,fdci(2).*100)
disp(' ')
fprintf('Specificity (probability that test is negative on healthy subject): %0.1f%% (%0.1f%% - %0.1f%%)\n',SS(2)*100,Spci(1).*100,Spci(2).*100)
fprintf('False positive proportion: %0.1f%% (%0.1f%% - %0.1f%%)\n',fp(2)*100,fpci(1).*100,fpci(2).*100)
fprintf('False omission rate: %0.1f%% (%0.1f%% - %0.1f%%)\n',fd(2)*100,foci(1).*100,foci(2).*100)
disp(' ')

%Youden's Index
%Youden's J statistics (also called Youden's index) is a single statistic that
%captures the performance of a diagnostic test. The use of such a single index
%is "not generally to be recommended". It is equal to the risk difference for a
%dichotomous test and it defined as: J = Sensitivity + Specificity - 1.
%A perfect test has J=1.
J=sum(SS)-1; %Youden's index
fprintf('Youden''s Index (a perfect test would have a Youden''s index of +1): %0.4f\n', J)

%The number needed to diagnose is defined as the number of patients that
%need to be tested to give one correct positive test.
NND=1/J; %Number needed to Diagnose (NND)
fprintf('Number Needed to Diagnose (NND): %0.2f\n',NND);
fprintf('Around %i persons need to be tested to return 10 positive tests for the presence of disease\n',ceil(NND*10))
disp(' ')

%Positive and Negative predictivity
%Positive predictivity is the probability that a subject is sick when test is positive: P(D+|T+)
%Negative predictivity is the probability that a subject is healthy when test is negative: P(D-|T-)
%Positive predictivity=Precision
%In Matlab both parameters are obtained with only one instruction:
PNp=d./rs; %Positive and Negative predictivity
% 95% confidence interval critical value for Positive and Negative predictivity
Ppci=newcombe(PNp(1));
Npci=newcombe(PNp(2));
%Positive and Negative Likelihood Ratio
%When we decide to order a diagnostic test, we want to know which test (or
%tests) will best help us rule-in or rule-out disease in our patient.  In the
%language of clinical epidemiology, we take our initial assessment of the
%likelihood of disease (“pre-test probability”), do a test to help us shift our
%suspicion one way or the other, and then determine a final assessment of the
%likelihood of disease (“post-test probability”).
%Likelihood ratios tell us how much we should shift our suspicion for a
%particular test result. Because tests can be positive or negative, there are at
%least two likelihood ratios for each test.  The “positive likelihood ratio”
%(LR+) tells us how much to increase the probability of disease if the test is
%positive, while the “negative likelihood ratio” (LR-) tells us how much to
%decrease it if the test is negative.
%You can also define the LR+ and LR- in terms of sensitivity and specificity:
%LR+ = sensitivity / (1-specificity)
%LR- = (1-sensitivity) / specificity
plr=SS(1)/fp(2); %Positive Likelihood Ratio
plrci=LRci(plr,x);
nlr=fp(1)/SS(2); %Negative Likelihood Ratio
nlrci=LRci(nlr,x);

fprintf('Precision or Predictivity of positive test\n')
fprintf('(probability that a subject is unhealthy when test is positive): %0.1f%% (%0.1f%% - %0.1f%%)\n', PNp(1)*100,Ppci(1).*100,Ppci(2).*100)
fprintf('Positive Likelihood Ratio: %0.1f (%0.1f - %0.1f)\n',plr,plrci(1),plrci(2))
dlr(plr)
disp(' ')
fprintf('Predictivity of negative test\n')
fprintf('(probability that a subject is healthy when test is negative): %0.1f%% (%0.1f%% - %0.1f%%)\n', PNp(2)*100,Npci(1).*100,Npci(2).*100)
if nlr<1e-4 || nlrci(1)<1e-4
    fprintf('Negative Likelihood Ratio: %0.4e (%0.4e - %0.4e)\n',nlr,nlrci(1),nlrci(2))
else
    fprintf('Negative Likelihood Ratio: %0.4f (%0.4f - %0.4f)\n',nlr,nlrci(1),nlrci(2))
end
dlr(nlr)
disp(' ')

%Predictive Summary Index (similar to Youden's Index)
PSI=sum(PNp)-1;
NNS=1/PSI; %Number needed to screen
fprintf('Predictive Summary Index: %0.4f\n', PSI)
fprintf('Number Needed to Screen (NNS): %0.2f\n',NNS);
fprintf('Around %i persons need to be screened to avoid 10 events (i.e. death) for the presence of disease\n',ceil(NNS*10))
disp(' ')

%Accuracy and Mis-classification rate
%Diagnostic accuracy (or Power) is defined as the proportion of all tests
%that give a correct result. The Mis-classification rate is its complement to 1.
%In statistics, the F1 score (also F-score or F-measure) is a measure of a
%test's accuracy. It considers both the Precision (positive predictivity)
%and the Sensitivity of the test to compute the score:
%P is the number of correct results divided by the number of all returned results
%S is the number of correct results divided by the number of results that should
%have been returned.
%The F1 score can be interpreted as a weighted average of the Precision and
%Sensitivity, where an F1 score reaches its best value at 1 and worst score at 0.
acc=trace(x)/N; %Accuracy
accci=newcombe(acc);
mcr=1-acc; %Mis-classification rate
mcrci=newcombe(mcr);
FMeasure=harmmean([SS(1) PNp(1)]); %F-measure
FMci=newcombe(FMeasure);
fprintf('Accuracy or Potency: %0.1f%% (%0.1f%% - %0.1f%%)\n',acc*100,accci(1).*100,accci(2).*100)
fprintf('Mis-classification Rate: %0.1f%% (%0.1f%% - %0.1f%%)\n',mcr*100,mcrci(1).*100,mcrci(2).*100)
fprintf('F-measure: %0.1f%% (%0.1f%% - %0.1f%%)\n',FMeasure*100,FMci(1).*100,FMci(2).*100)
disp(' ')

orse=realsqrt(sum(1./x(:))); %standard error of log(OR)
cv=([-1 1].*(z*orse));

%Test Bias (TB)
%A test which shows provable and systematic differences in the results of people
%based on group membership. For example, a test might be considered biased if
%members of one particular gender or race consistently and systematic have
%statistically different results from the rest of the testing population.
%It is defined as (T+)/(D+)=(TP+FP)/(TP+FN)
%A perfect test has a TB=1;
%If TB<1 the test underestimates the disease because there are more affected than positive test
%If TB>1 the test overestimates the disease because there are more positive test than affected
TB=rs(1)/cs(1); %Test Bias
orci=exp(reallog(TB)+cv); %OR confidence interval
fprintf('Test bias: %0.4f (%0.4f - %0.4f)\n',TB,orci(1),orci(2))
if TB>1
    disp('Test overestimates the phenomenon')
elseif TB<1
    disp('Test underestimates the phenomenon')
else
    disp('There is not test bias')
end

%Error Odds Ratio.
%Indicates if the probability of being wrongly classified is highest in the
%diseased or in the non-diseased group. If the error odds is higher than one the
%probability is highest in the diseased group (and the specificity of the test
%is better than the sensitivity), if the value is lower than one the probability
%of an incorrect classification is highest in the non-diseased group (and the
%sensitivity of the test is better than the specificity).
%It is defined as (Sensitivity/(1-Sensitivity))/(Specificity/(1-Specificity));
EOR=(SS(1)/fp(1))/(SS(2)/fp(2)); %Error odds ratio
orci=exp(reallog(EOR)+cv); %OR confidence interval
fprintf('Error odds ratio: %0.4f (%0.4f - %0.4f)\n',EOR,orci(1),orci(2))

%Diagnostic Odds Ratio.
%Diagnostic odds ratio is defined as how much more likely will the test
%make a correct diagnosis than an incorrect diagnosis in patients with the
%disease (Scott et al. 2008).
%Often used as a measure of the discriminative power of the test. Has the value
%one if the test does not discriminate between diseased and not diseased. Very
%high values above one means that a test discriminates well. Values lower than
%one mean that there is something wrong in the application of the test.
%It is defined as (Sensitivity/(1-Sensitivity))/((1-Specificity)/Specificity);
DOR=(SS(1)/fp(1))/(fp(2)/SS(2)); %Diagnostic odds ratio
orci=exp(reallog(DOR)+cv); %OR confidence interval
fprintf('Diagnostic odds ratio: %0.4f (%0.4f - %0.4f)\n',DOR,orci(1),orci(2))

%Discriminant power
%The discriminant power for a test, also termed the test effectiveness, is a
%measure of how well a test distinguishes between affected and unaffected
%persons. It is the sum of logs of Sensivity and Specificity over own false
%proportion, scaled by the standard deviation of the logistic normal
%distribution curve (square root of 3 divided by π). Test effectiveness is
%interpreted as the standardized distance between the means for both populations.
%A test with a discriminant value of 1 is not effective in discriminating between affected and unaffected individuals.
%A test with a discriminant value of 3 is effective in discriminating between affected and unaffected individuals.
dpwr=(realsqrt(3)/pi)*sum(log(SS./fp)); %Discriminant power
fprintf('Discriminant Power: %0.1f\n',dpwr)
disp([blanks(5) 'A test with a discriminant value of 1 is not effective in discriminating between affected and unaffected individuals.'])
disp([blanks(5) 'A test with a discriminant value of 3 is effective in discriminating between affected and unaffected individuals.'])

%Display graphs
xg=cs./N;
figure
hold on
H=zeros(1,4);
H(1)=fill(xg(1)+[0 xg(2) xg(2) 0],SS(2)+[0 0 fp(2) fp(2)],'r');
H(2)=fill([0 xg(1) xg(1) 0],fp(1)+[0 0 SS(1) SS(1)],'g');
H(3)=fill([0 xg(1) xg(1) 0],[0 0 fp(1) fp(1)],'y');
H(4)=fill(xg(1)+[0 xg(2) xg(2) 0],[0 0 SS(2) SS(2)],'b');
hold off
axis square
title('PARTEST GRAPH')
xlabel('Subjects proportion')
ylabel('Parameters proportion')
legend(H,'False Positive','True Positive (Sensibility)','False Negative','True Negative (Specificity)','Location','NorthEastOutside')

%The rose plot is a variation of the common pie chart. For both, we have k data
%points where each point denotes a frequency or a count. Pie charts and rose
%plots both use the area of segments of a circle to convey amounts.
%The pie chart uses a common radius and varies the central angle according to
%the data. That is, the angle is proportional to the frequency. So if the i-th
%point has count X and the total count is N, the i-th angle is 360*(X/N).
%For the rose plot, the angle is constant (i.e., divide 360 by the number of
%groups, k) and it is the square root of the radius that is proportional to the
%data.
%According to Wainer (Wainer (1997), Visual Revelations: Graphical Tales of Fate
%and Deception from Napolean Bonaporte to Ross Perot, Copernicus, Chapter 11.),
%the use of a common angle is the strength of the rose plot since it allows us
%to easily compare a sequence of rose plots (i.e., the corresponding segments in
%different rose plots are always in the same relative position).
%In particular, this makes rose plots an effective technique for displaying the
%data in contingency tables.
%As an interesting historical note, Wainer points out that rose plots were used
%by Florence Nightingale (she referred to them as coxcombs).
%color={'r','g','y','b'};
H=roseplot([fp(2) SS(1) fp(1) SS(2)]);
title('ROSEPLOT PARTEST GRAPH')
legend(H,'False Positive','True Positive (Sensibility)','False Negative','True Negative (Specificity)','Location','NorthEastOutside')
return
end

function dlr(lr) %Likelihood dialog
if lr==1
    disp('Test is not suggestive of the presence/absence of disease')
    return
end

if lr>10 || lr<0.1
    p1='Large (often conclusive)';
elseif (lr>5 && lr<=10) || (lr>0.1 && lr<=0.2)
    p1='Moderate';
elseif (lr>2 && lr<=5) || (lr>0.2 && lr<=0.5)
    p1='Low';
elseif (lr>1 && lr<=2) || (lr>0.5 && lr<=1)
    p1='Poor';
end

p2=' increase in possibility of disease ';

if lr>1
    p3='presence';
elseif lr<1
    p3='absence';
end
disp([p1 p2 p3])
return
end

function H=roseplot(x)
color={'r','g','y','b'};
k=length(x); H=zeros(1,k);
ang=(0:1:k)./k.*2.*pi;
figure
axis square
hold on
for I=1:k
    theta=[ang(I) linspace(ang(I),ang(I+1),500) ang(I+1)];
    rho=[0 repmat(realsqrt(x(I)),1,500) 0];
    [xg,yg]=pol2cart(theta,rho);
    H(I)=patch(xg,yg,color{I});
end
hold off
return
end

function ci=newcombe(p)
global z N
a=2*N*p+z^2;
b=z*realsqrt((z^2-2-1/N+4*p*(N*(1-p)+1)));
c=(2*(N+z^2));
%Of course, the critical interval lower bound cannot be less than 0 and the
%upper bound cant be greater than 1 and so:
ci(1)=max([0 (a-b-1)/c]);
ci(2)=min([1 (a+b+1)/c]);
return
end

function ci=LRci(lr,x)
global z
a=log(lr); b=realsqrt(sum(1./diag(x))-sum(1./sum(x,2)))*z;
ci=exp([a-b a+b]);
return
end


function [theta, J_history] = gradientDescent(X, y, theta, alpha, num_iters)
%GRADIENTDESCENT Performs gradient descent to learn theta
%   theta = GRADIENTDESCENT(X, y, theta, alpha, num_iters) updates theta by
%   taking num_iters gradient steps with learning rate alpha

% Initialize some useful values
m = length(y); % number of training examples
J_history = zeros(num_iters, 1);

for iter = 1:num_iters

    % ====================== YOUR CODE HERE ======================
    % Instructions: Perform a single gradient step on the parameter vector
    %               theta.
    %
    % Hint: While debugging, it can be useful to print out the values
    %       of the cost function (computeCost) and gradient here.
    %

    predictions =  X * theta;
    updates = X' * (predictions - y);
    theta = theta - alpha * (1/m) * updates;
    %theta = theta - alpha * (1/m) * sum(sqerrors) * X;
    %theta - (alpha/m) * (X' * (X * theta - y));
    %theta = theta - (alpha/m) * (X' * (X * theta - y));

    % ============================================================

    % Save the cost J in every iteration
    J_history(iter) = computeCost(X, y, theta);

end

end


% Example 7.2: Maximum entropy distribution
% Section 7.2, Figures 7.2-7.3
% Boyd & Vandenberghe, "Convex Optimization"
% Originally by Lieven Vandenberghe
% Adapted for CVX by Michael Grant 4/11/06
%
% We consider a probability distribution on 100 equidistant points in the
% interval [-1,1]. We impose the following prior assumptions:
%
%    -0.1 <= E(X) <= +0.1
%    +0.5 <= E(X^2) <= +0.6
%    -0.3 <= E(3*X^3-2*X) <= -0.2
%    +0.3 <= Pr(X<0) <= 0.4
%
% Along with the constraints sum(p) == 1, p >= 0, these constraints
% describe a polyhedron of probability distrubtions. In the first figure,
% the distribution that maximizes entropy is computed. In the second
% figure, we compute upper and lower bounds for Prob(X<=a_i) for each
% point -1 <= a_i <= +1 in the distribution, as well as the maximum
% entropy CDF.

%
% Represent the polyhedron as follows:
%     A * p <= b
%     sum( p ) == 1
%     p >= 0
%

n  = 100;
a  = linspace(-1,1,n);
a2 = a .^ 2;
a3 = 3 * ( a.^ 3 ) - 2 * a;
ap = +( a < 0 );
A  = [ a   ; -a  ; a2 ; -a2  ; a3 ; -a3 ; ap ; -ap ];
b  = [ 0.1 ; 0.1 ;0.5 ; -0.5 ; -0.2 ; 0.3 ; 0.4 ; -0.3 ];

%
% Compute the maximum entropy distribution
%

cvx_expert true
cvx_begin
    variables pent(n)
    maximize( sum(entr(pent)) )
    sum(pent) == 1;
    A * pent <= b;
cvx_end

%
% Compute the bounds on Prob(X<=a_i), i=1,...,n
%

Ubnds = zeros(1,n);
Lbnds = zeros(1,n);
for t = 1 : n,
    cvx_begin quiet
        variable p( n )
        minimize sum( p(1:t) )
        p >= 0;
        sum( p ) == 1;
        A * p <= b;
    cvx_end
    Lbnds(t) = cvx_optval;
    cvx_begin quiet
        variable p( n )
        maximize sum( p(1:t) )
        p >= 0;
        sum( p ) == 1;
        A * p <= b;
    cvx_end
    Ubnds(t) = cvx_optval;
    disp( sprintf( '%g <= Prob(x<=%g) <= %g', Lbnds(t), a(t), Ubnds(t) ) );
end

%
% Generate the figures
%

figure( 1 )
stairs( a, pent );
xlabel( 'x' );
ylabel( 'PDF( x )' );

figure( 2 )
stairs( a, cumsum( pent ) );
grid on;
hold on
d = stairs(a, Lbnds,'r-');  set(d,'Color',[0 0.5 0]);
d = stairs(a, Ubnds,'r-');  set(d,'Color',[0 0.5 0]);
d = plot([-1,-1], [Lbnds(1), Ubnds(1)],'r-');
set(d,'Color',[0 0.5 0]);
axis([-1.1 1.1 -0.1 1.1]);
xlabel( 'x' );
ylabel( 'CDF( x )' );
hold off


function [points,weights] = FibonacciGaussian(N,mu,P)
%%FIBONACCIGAUSSIAN Creates a grid of points based on a transformation of a
%                   Fibonacci grid as given in [1].
%
%INPUT:
% N: The number of points to sample.
% mu: The D-by-1 vector indicating the Gaussian mean.
% P: The D-by-D covariance matrix. This must be positive definite.
%
%OUTPUT:
% points: A D-by-N matrix containing sample points for the given Gaussian.
% weights: A collection of weights representing the Gaussian PDF at each
%          sample point.
%
%EXAMPLE 1: Generates a collection of sample points and their respective
%           Gaussian weights in 1D and plots them.
% mu = 5;
% P = 2;
% [points, weights] = FibonacciGaussian(100,mu,P);
% stem(points(1,:),weights,'k',"filled","MarkerEdgeColor",'b')
%
%EXAMPLE 2: Generates a collection of sample points and their respective
%         Gaussian weights in 2D and plots them.
% mu = [5;3];
% P = [2,-0.7;-0.7,1];
% [points, weights] = FibonacciGaussian(100,mu,P);
% scatter(points(1,:),points(2,:),'k',"filled","MarkerEdgeColor",'b',"CData",weights)
% hold on
% drawEllipse(mu,P\eye(2),[],'r',"LineWidth",2)
% hold off
%
%EXAMPLE 3: Generates a collection of sample points and their respective
%           Gaussian weights in 3D and plots them.
% mu = [5;3;4];
% P = [2,-0.7,0.1;-0.7,1,-0.3;0.1,-0.3,2];
% [points, weights] = FibonacciGaussian(100,mu,P);
% scatter3(points(1,:),points(2,:),points(3,:),'k',"filled","MarkerEdgeColor",'b',"CData",1e3*weights)
% hold on
% drawEllipse(mu,P\eye(3),[],"FaceAlpha",0.1,"EdgeAlpha",0.1)
% hold off
%
%REFERENCE:
%[1] D. Frisch and U. D. Hanebeck, "Deterministic gaussian sampling with
%    generalized fibonacci grids," in 2021 IEEE 24th International
%    Conference on Information Fusion (FUSION), IEEE, 2021, pp. 1-8.
%
%December 2022 Codie T. Lewis, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.
D = size(mu,1);
points = FibonacciGrid(N,D);
points = sqrt(2)*erfinv(2*points-1);
nu = sqrt(sum(points.^2,2)/N);
for idx = 1:D
    points(idx,:) = points(idx,:)/nu(idx);
end
[V,E] = eig(P);
points = V*sqrt(abs(E))*points+mu;
weights = GaussianD.PDF(points,mu,P);
end
%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


function y = mtrapezlogpdf(x,a,u,v,b)
%MTRAPEZLOGPDF Multivariate trapezoidal probability log pdf.
%   Y = MTRAPEZLOGPDF(X,A,U,V,B) returns the logarithm of the pdf of the
%   multivariate trapezoidal distribution with external bounds A and B and
%   internal points U and V, evaluated at the values in X. The multivariate
%   trapezoidal pdf is the product of univariate trapezoidal pdfs in each
%   dimension.
%
%   For each dimension i, the univariate trapezoidal pdf is defined as:
%
%                 |       __________
%                 |      /|        |\
%         p(X(i)) |     / |        | \
%                 |    /  |        |  \
%                 |___/___|________|___\____
%                    A(i) U(i)     V(i) B(i)
%                             X(i)
%
%   X can be a matrix, where each row is a separate point and each column
%   is a different dimension. Similarly, A, B, C, and D can also be
%   matrices of the same size as X.
%
%   The log pdf is typically preferred in numerical computations involving
%   probabilities, as it is more stable.
%
%   See also MTRAPEZPDF, MTRAPEZRND.

% Luigi Acerbi 2022

[N,D] = size(x);

if D > 1
    if isscalar(a); a = a*ones(1,D); end
    if isscalar(u); u = u*ones(1,D); end
    if isscalar(v); v = v*ones(1,D); end
    if isscalar(b); b = b*ones(1,D); end
end

if size(a,2) ~= D || size(u,2) ~= D || size(v,2) ~= D || size(b,2) ~= D
    error('mtrapezpdf:SizeError', ...
        'A, B, C, D should be scalars or have the same number of columns as X.');
end

if size(a,1) == 1; a = repmat(a,[N,1]); end
if size(u,1) == 1; u = repmat(u,[N,1]); end
if size(v,1) == 1; v = repmat(v,[N,1]); end
if size(b,1) == 1; b = repmat(b,[N,1]); end

y = -inf(size(x));
lnf = log(0.5) + log(b - a + v - u) + log(u - a);

for ii = 1:D
    idx = x(:,ii) >= a(:,ii) & x(:,ii) < u(:,ii);
    y(idx,ii) = log(x(idx,ii) - a(idx,ii)) - lnf(idx,ii);

    idx = x(:,ii) >= u(:,ii) & x(:,ii) < v(:,ii);
    y(idx,ii) = log(u(idx,ii)-a(idx,ii)) - lnf(idx,ii);

    idx = x(:,ii) >= v(:,ii) & x(:,ii) < b(:,ii);
    y(idx,ii) = log(b(idx,ii) - x(idx,ii)) - log(b(idx,ii) - v(idx,ii)) + log(u(idx,ii)-a(idx,ii)) - lnf(idx,ii);
end

y = sum(y,2);


function [r, R, S] = imnoise3(M, N, C, A, B)
%IMNOISE3 Generates periodic noise.
%    [r, R, S] = IMNOISE3(M, N, C, A, B), generates a spatial
%    sinusoidal noise pattern, r, of size M-by-N, its Fourier
%    transform, R, and spectrum, S.  The remaining parameters are:
%
%    C is a K-by-2 matrix with K pairs of freq. domain coordinates (u,
%    v) that define the locations of impulses in the freq. domain. The
%    locations are with respect to the frequency rectangle center at
%    (floor(M/2) + 1, floor(N/2) + 1).  The impulse locations are spe-
%    cified as increments with respect to the center. For ex, if M =
%    N = 512, then the center is at (257, 257). To specify an impulse
%    at (280, 300) we specify the pair (23, 43); i.e., 257 + 23 = 280,
%    and 257 + 43 = 300. Only one pair of coordinates is required for
%    each impulse.  The conjugate pairs are generated automatically.
%
%    A is a 1-by-K vector that contains the amplitude of each of the
%    K impulse pairs. If A is not included in the argument, the
%    default used is A = ONES(1, K).  B is then automatically set to
%    its default values (see next paragraph).  The value specified
%    for A(j) is associated with the coordinates in C(j, 1:2).
%
%    B is a K-by-2 matrix containing the Bx and By phase components
%    for each impulse pair.  The default values for B are B(1:K, 1:2)
%    = 0.

%   Copyright 2002-2004 R. C. Gonzalez, R. E. Woods, & S. L. Eddins
%   Digital Image Processing Using MATLAB, Prentice-Hall, 2004
%   $Revision: 1.5 $  $Date: 2004/11/04 22:32:42 $

% Process input parameters.
[K, n] = size(C);
if nargin == 3
   A(1:K) = 1.0;
   B(1:K, 1:2) = 0;
elseif nargin == 4
   B(1:K, 1:2) = 0;
end

% Generate R.
R = zeros(M, N);
for j = 1:K
   u1 = M/2 + 1 + C(j, 1); v1 = N/2 + 1 + C(j, 2);
   R(u1, v1) = i * (A(j)/2) * exp(i*2*pi*C(j, 1) * B(j, 1)/M);
   % Complex conjugate.
   u2 = M/2 + 1 - C(j, 1); v2 = N/2 + 1 - C(j, 2);
   R(u2, v2) = -i * (A(j)/2) * exp(i*2*pi*C(j, 2) * B(j, 2)/N);
end

% Compute spectrum and spatial sinusoidal pattern.
S = abs(R);
r = real(ifft2(ifftshift(R)));


%  Generate an n-column convolution matirx of
%  An n-column convolution matrix of p is the matrix for the
%  linear transformation L(f) = p*f  for polynomial f of degree n-1.
%  If f is the coefficient vector of f, and C is the convolution matrix,
%  then C*f is the coefficient vector of p*f.
%
%    Syntax:  C = ConvolutionMatrix(p,n)
%
%    Input:   p --- (string or vector) the univariate polynomial
%             n --- (integer) the column dimension of the convolution matrix
%
%   Output:   C --- the convolution matrix
%
%   Example:  >> p = '1+3*x^4-6*x^8';
%             >> C = ConvolutionMatrix(p,3)
%             C =
%             -6     0     0
%              0    -6     0
%              0     0    -6
%              0     0     0
%              3     0     0
%              0     3     0
%              0     0     3
%              0     0     0
%              1     0     0
%              0     1     0
%              0     0     1