function [ n_data_new, n, c ] = phi_values ( n_data )

%*****************************************************************************80
%
%% PHI_VALUES returns some values of the PHI function.
%
%  Definition:
%
%    PHI(N) is the number of integers between 1 and N which are
%    relatively prime to N.  I and J are relatively prime if they
%    have no common factors.  The function PHI(N) is known as
%    "Euler's totient function".
%
%    By convention, 1 and N are relatively prime.
%
%  First values:
%
%     N  PHI(N)
%
%     1    1
%     2    1
%     3    2
%     4    2
%     5    4
%     6    2
%     7    6
%     8    4
%     9    6
%    10    4
%    11   10
%    12    4
%    13   12
%    14    6
%    15    8
%    16    8
%    17   16
%    18    6
%    19   18
%    20    8
%
%  Formula:
%
%    PHI(U*V) = PHI(U) * PHI(V) if U and V are relatively prime.
%
%    PHI(P**K) = P**(K-1) * ( P - 1 ) if P is prime.
%
%    PHI(N) = N * Product ( P divides N ) ( 1 - 1 / P )
%
%    N = Sum ( D divides N ) PHI(D).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 May 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Milton Abramowitz and Irene Stegun,
%    Handbook of Mathematical Functions,
%    US Department of Commerce, 1964.
%
%  Parameters:
%
%    Input, integer N_DATA, indicates the index of the previous test data
%    returned, or is 0 if this is the first call.  For repeated calls,
%    set the input value of N_DATA to the output value of N_DATA_NEW
%    from the previous call.
%
%    Output, integer N_DATA_NEW, the index of the test data.
%
%    Output, integer N, the argument of the PHI function.
%
%    Output, integer C, the value of the PHI function.
%
  n_max = 20;
  c_vec = [ ...
      1,   1,   2,   2,   4,   2,   6,   4,   6,   4, ...
      8,   8,  16,  20,  16,  40, 148, 200, 200, 648 ];
  n_vec = [ ...
      1,   2,   3,   4,   5,   6,   7,   8,   9,  10, ...
     20,  30,  40,  50,  60, 100, 149, 500, 750, 999 ];

  n_data_new = n_data;

  if ( n_data_new < 0 )
    n_data_new = 0;
  end

  n_data_new = n_data_new + 1;

  if ( n_max < n_data_new )
    n_data_new = 0;
    n = 0;
    c = 0;
  else
    n = n_vec(n_data_new);
    c = c_vec(n_data_new);
  end

  return
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Author: Nicholas A. Battista
% Institution: The College of New Jersey (TCNJ)
% Created: March 20, 2018
% Date of Last Revision: March 22, 2018
%
% Written for use in MAT 331: Numerical Analysis
%
% PURPOSE:  -To compute the error ssociated with applying Trapezoid Rule to
%            two different integral cases:
%                (1) a periodic integrand on a periodic integration domain
%                (2) non-periodic integrand
%
%           -To demonstrate exponential convergence of Trap. Rule in Case (1)
%            above
%
% Inputs:
%
% Returns:
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function Trap_Rule_Error()

% Number of subintervals to test
NVec = [1e0:1e0:9e0 1e1:1e1:9e1 1e2:1e2:9e2 1e3:1e3:9e3 1e4:1e4:9e4 1e5:1e5:9e5 1e6:1e6:9e6];

%
% Storage Initialization
ErrVecPeriodic = zeros(length(NVec));
ErrVecNonPeriodic = ErrVecPeriodic;

%
% Compute Integral Approximation for Different #'s of Subintervals
%
for i=1:length(NVec)

   flag = 1; % For Periodic
   ErrVecPeriodic(i) = Trap_Rule( NVec(i), 0, 1, flag);

   flag = 0; % For Non-Periodic
   ErrVecNonPeriodic(i) = Trap_Rule( NVec(i), 0, 1, flag);

end

%
% Print Convergence Rate Information to Screen
slopeNonPeriodic = give_Me_Slope( ErrVecNonPeriodic,40,50 );
fprintf('\nConvergence Rate for Periodic Functions Appears to be Exponential, e.g.,\n');
fprintf('     we see a linear relationship between log(error) and # of subintervals, N\n');
fprintf('\nConvergence Rate for Non-Periodic Functions Appears to be: %d\n\n',slopeNonPeriodic);

%
% PLOT THE ABSOLUTEL ERROR -> GIVE CONVERGENCE PLOTS!
%
fs = 18;
ms = 30;
figure(1) % PERIODIC CASE
semilogy(NVec(1:45),ErrVecPeriodic(1:45),'b.','MarkerSize',ms); hold on;
%loglog(NVec(1:45),ErrVecPeriodic(1:45),'b.','MarkerSize',ms); hold on;
title('Periodic Case');
ylabel('Absolute Error');
xlabel('Number of Sub-Intervals');
set(gca,'FontSize',fs);

figure(2) % NON-PERIODIC CASE
loglog(NVec,ErrVecNonPeriodic,'b.','MarkerSize',ms); hold on;
title('Non-Periodic Case');
ylabel('Absolute Error');
xlabel('Number of Sub-Intervals');
set(gca,'FontSize',fs);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION: computes the absolute error using the trapezoid rule for a
%           particular number of subintervals, N.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function err = Trap_Rule(N,a,b,flagCase)

% Uniformly spaced integration nodes
x = a:(b-a)/N:b;

% Compute trapezoid rule for periodic function
int = 0;
for i=1:N
   int = int + (b-a)/(2*N)*( f(x(i),flagCase) + f(x(i+1),flagCase) );
end

%
% Return Error for Particular Case
%
if flagCase == 1

    % PERIODIC CASE
    intExactPeriodic = 0.132214293037990;
    err = abs( int - intExactPeriodic );

else

    % NON-PERIODIC CASE
    intExactNonPeriodic = 0.455122322888408;
    err = abs( int - intExactNonPeriodic );

end

% PLOT!
%x=a:0.001:b;
%for i=1:length(x)
%    plot( x(i) , f(x(i)), '*'); hold on;
%end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION: returns integrand function value
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function val = f(x,flagCase)

%
% Return Function Value for Particular Case
%
if flagCase == 1

    % PERIODIC: f(x) = (cos(2*pi*x))^2 / ( 1 + e^(sin(2*pi*x)) )^2;
    val = ( cos(2*pi*x) )^2 / ( 1 + exp( sin(2*pi*x) ) )^2;

else

    % NON-PERIODIC: f(x) = (x^2+3)(cos(2*pi*x))^2 / ( 1 + e^(sin(2*pi*x)) )^2;
    val = (x^2+3)*(cos(2*pi*x))^2 / ( 1 + exp(sin(2*pi*x)) )^2;

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION: give me slope of convergence plot
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function m = give_Me_Slope( errVec, val1, val2 )

m = ( log( errVec(val1) ) - log( errVec(val2) ) ) / (log(val1) - log(val2));


function line = medianLine(varargin)
%MEDIANLINE Create a median line between two points
%
%   L = medianLine(P1, P2);
%   Create the median line of points P1 and P2, that is the line containing
%   all points located at equal distance of P1 and P2.
%
%   L = medianLine(PTS);
%   Creates the median line of 2 points, given as a 2*2 array. Array has
%   the form:
%   [ [ x1 y1 ] ; [ x2 y2 ] ]
%
%   L = medianLine(EDGE);
%   Creates the median of the edge. Edge is a 1*4 array, containing [X1 Y1]
%   coordinates of first point, and [X2 Y2], the coordinates of the second
%   point.
%
%   Example
%   % Draw the median line of two points
%     P1 = [10 20];
%     P2 = [30 50];
%     med = medianLine(P1, P2);
%     figure; axis square; axis([0 100 0 100]);
%     drawEdge([P1 P2], 'linewidth', 2, 'color', 'k');
%     drawLine(med)
%
%   % Draw the median line of an edge
%     P1 = [50 60];
%     P2 = [80 30];
%     edge = createEdge(P1, P2);
%     figure; axis square; axis([0 100 0 100]);
%     drawEdge(edge, 'linewidth', 2)
%     med = medianLine(edge);
%     drawLine(med)
%
%
%   See also:
%   lines2d, createLine, orthogonalLine
%
%   ---------
%   author : David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 31/10/2003.
%

% history
% 2010-08-06 vectorize and change behaviour for N-by-4 inputs

nargs = length(varargin);

if nargs == 1
    tab = varargin{1};
    if size(tab, 2)==2
        % input is an array of two points
        x0 = tab(1,1);
        y0 = tab(1,2);
        dx = tab(2,1)-x0;
        dy = tab(2,2)-y0;
    else
        % input is an edge
        x0 = tab(:, 1);
        y0 = tab(:, 2);
        dx = tab(:, 3) - tab(:, 1);
        dy = tab(:, 4) - tab(:, 2);
    end

elseif nargs==2
    % input is given as two points, or two point arrays
    p1 = varargin{1};
    p2 = varargin{2};
    x0 = p1(:, 1);
    y0 = p1(:, 2);
    dx = bsxfun(@minus, p2(:, 1), x0);
    dy = bsxfun(@minus, p2(:, 2), y0);

else
    error('Too many input arguments');
end

% compute median using middle point of the edge, and the direction vector
% rotated by 90 degrees counter-clockwise
line = [bsxfun(@plus, x0, dx/2), bsxfun(@plus, y0, dy/2), -dy, dx];


function M = softMin( D, sigma )
% Calculates the softMin of a vector.
%
% Let D be a vector.  Then the softMin of D is defined as:
%   s = exp(-D/sigma^2) / sum( exp(-D/sigma^2) )
% The softMin is a way of taking a dissimilarity (distance) vector D and
% converting it to a similarity vector s, such that sum(s)==1. If D is an
% NxK array, is is treated as N K-dimensional vectors, and the return is
% likewise an NxK array.  This is useful if D is a distance matrix,
% generated by the likes of pdist2.
%
% Note that as sigma->0, softMin's behavior tends toward that of the
% standard min function.  That is the softMin of a vector D has all zeros
% with a single 1 in the location of the smallest value of D. For example,
% "softMin([.2 .4 .1 .3],eps)" returns "[0 0 1 0]".  As sigma->inf, then
% softMin(D,sigma) tends toward "ones(1,n)/n", where n==length(D).
%
% If D contains the squared euclidean distance between a point y and k
% points xi, then there is a probabilistic interpretation for softMin.  If
% we think of the k points representing equal variant gaussians each with
% mean xi and std sigma, then the softMin returns the relative probability
% of y being generated by each gaussian.
%
% USAGE
%  M = softMin( D, sigma )
%
% INPUTS
%  D       - NxK dissimilarity matrix
%  sigma   - controls 'softness' of softMin
%
% OUTPUTS
%  M       - the softMin (indexes into D)
%
% EXAMPLE - 1
%  C = [0 0; 1 0; 0 1; 1 1]; x=[.7,.3; .1 .2];
%  D = pdist2( x, C ), M = softMin( D, .25 )
%
% EXAMPLE - 2
%  fplot( 'softMin( [0.5 0.2 .4], x )', [0 5] );
%  xlabel('sigma'); ylabel('assignments')
%
% See also PDIST2, SOFTMAX
%
% 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]

if( sigma==0 ) % special case, make fast
  [~, inds] = min(D,[],2); [n, k] = size(D);
  M = subsToArray( [(1:n)' inds], ones(n,1), [n k] );

else % general case
  M = exp( -D / sigma^2 );
  M(isinf(M))=1e50;
  sumM = sum( M, 2 );
  sumMzero = (sumM==0);
  if( any(sumMzero) )
    [~, inds] = min(D,[],2); [n, k] = size(D);
    Mhard = subsToArray( [(1:n)' inds], ones(n,1), [n k] );
    M( sumMzero, : ) = Mhard( sumMzero, : );
    sumM = sum( M, 2 );
  end
  M = M ./ sumM( :, ones(1,size(M,2)) );
end


% book : Signals and Systems Laboratory with MATLAB
% authors : Alex Palamides & Anastasia Veloni
%
%
%

% analytical computation of the convolution between
% x(t)=1,0<t<2 and h(t)=1-t,0<t<1

 tx1=-2:.1:0;
 tx2=0:.1:2;
 tx3=2:.1:4;
 tx=[tx1 tx2 tx3];
 x1=zeros(size(tx1));
 x2=ones(size(tx2));
 x3=zeros(size(tx3));
 x=[x1 x2 x3];

 th1=-2:.1:0;
 th2=0:.1:1;
 th3=1:.1:4;
 th=[th1 th2 th3];
 h1=zeros(size(th1));
 h2=1-th2;
 h3=zeros(size(th3));
 h=[h1 h2 h3];

 plot(tx,x,th,h,':*')
 ylim([-.1 1.1])
 legend('x(\tau)','h(\tau)')
 grid

 %reflection
 figure
 plot(tx,x,-th,h,':*')
 legend('x(\tau)','h(-\tau)')
 ylim([-.1 1.1])

 %shifting
 figure
 t=-2;
 plot(tx,x,-th+t,h,':*')
 ylim([-.1 1.1])
 legend('x(\tau)','h(t-\tau)')

 %zero-overlap
 figure
 t=-2;
 plot(tx,x,-th+t,h,':*')
 ylim([-.1 1.1])
 legend('x(\tau)','h(t-\tau)')

 %partial-overlap
 figure
 t= 0.5;
 plot(tx,x,-th+t,h,':*')
 ylim([-.1 1.1])
 legend('x(\tau)','h(t-\tau)')

 T=1;
 r=0:.1:t;
 a=1/T*r+1-t/T;
 hold on; area(r,a);
 hold off;

%complete-overlap
 figure
 t=1.6;
 plot(tx,x,-th+t,h,':*')
 ylim([-.1 1.1])
 legend('x(\tau)','h(t-\tau)')

 r=t-T:.1:t;
 a=1/T*r+1-t/T;
 hold on; area(r,a);
 hold off;

%partial-overlap
 figure
 t=2.4;
 plot(tx,x,-th+t,h,':*')
 ylim([-.1 1.1])
 legend('x(\tau)','h(t-\tau)')

 r=t-T:.1:2;
 a=1/T*r+1-t/T;
 hold on; area(r,a);
 hold off;

 %zero-overlap
 figure
 t=3.6;
 plot(tx,x,-th+t,h,':*')
 ylim([-.1 1.1])
 legend('x(\tau)','h(t-\tau)')

%convolution calculation
 syms t r
 f=1-t+r;
 y=int(f,r,0,t)

 y=int(f,r,t-1,t)
 simplify(y)

 y=int(f,r,t-1,2)

 t1=0:.1:1;
 t2=1:.1:2;
 t3=2:.1:3;
 y1=t1-(t1.^2)/2;
 y2=0.5*ones(size(t2));
 y3=0.5*((3-t3).^2);

 figure
 plot(t1,y1,t2,y2,'.',t3,y3,':')
 ylim([0 0.6])
 title('Output signal y(t)');


function [X_norm, mu, sigma] = featureNormalize(X)
%FEATURENORMALIZE Normalizes the features in X
%   FEATURENORMALIZE(X) returns a normalized version of X where
%   the mean value of each feature is 0 and the standard deviation
%   is 1. This is often a good preprocessing step to do when
%   working with learning algorithms.

% You need to set these values correctly
X_norm = X;
mu = zeros(1, size(X, 2));
sigma = zeros(1, size(X, 2));

% ====================== YOUR CODE HERE ======================
% Instructions: First, for each feature dimension, compute the mean
%               of the feature and subtract it from the dataset,
%               storing the mean value in mu. Next, compute the
%               standard deviation of each feature and divide
%               each feature by it's standard deviation, storing
%               the standard deviation in sigma.
%
%               Note that X is a matrix where each column is a
%               feature and each row is an example. You need
%               to perform the normalization separately for
%               each feature.
%
% Hint: You might find the 'mean' and 'std' functions useful.
%

rowsz = size(X, 1);
colsz = size(X, 2);
mu = mean(X);
sigma = std(X);
mu_matrix = (ones(size(X))) * ((ones(colsz, 1) * mu) .* eye(colsz));
sigma_matrix = ((ones(colsz, 1) * (1./sigma)) .* eye(colsz));
X_norm = (X-mu_matrix) * sigma_matrix;

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

end


function [y, Dy, DDy, DDDy] = chebyshevInterpolate(f,t,d)
%
% This function uses barycentric interpolation to evaluate a chebyshev
% polynomial. Technical details are taken from the book: Approximation
% Theory and Approximation Practice by Lloyd Trefethen. The core equation
% that I use can be found as Theorem 5.2 in this book, and is called
% Barycentric Interpolation.
%
% Written by Matthew Kelly
% October 27, 2013
%   Updated: November 8, 2013
% Cornell University
%
% This function computes the value of the chebyshev polynomial that is
% defined by the vector f, at the inputs t. It can also be used to return
% the first and second derivatives of y with respect to t.
%
% INPUTS:
%   f = [KxN] value of the chebyshev polynomial at each of the chebyshev
%       points (these can be computed using chebyshevPoints.m). Each row
%       represents a single set of chebyshev node values for a single
%       state.
%   t = [1xM] vector of inputs to be evaluated (monotonically increasing)
%   d = [1x2] vector speficying the domain of the polynomial
%
% OUTPUTS:
%   y = [KxM] the value of the interpolant at each point in t
%   Dy = first derivative of y with respect to t
%   DDy = second derivative of y with respect to t
%   DDDy = third derivative of y with respect to t
%
% What is happening here, in plain english:
%
%   There are several Chebyshev points (or nodes) that are spread out
%   across the interval d using a special grid spacing. We will call these
%   points x. For each of the points in x, there is a corresponding value
%   of the chebyshev function, we'll call it f.
%
%   Let's say that we want to find the value of the approximation for some
%   input that is not in x. This can be done using a interpolation of the
%   values in f:
%                   y = c(t,x).*f
%
%   Note that the weighting terms are a function of both the desired input
%   and the chebyshev points. It turns out that there is a more stable and
%   efficient way to calculate this interpolation, which is roughly of the
%   form:
%                   y = (k(t,x).*f)/sum(k(t,x))
%
%   This code evaluates k(t,x) which it then uses to evaluate and return y.
%
%
% NOTE - The base algorithm (described above) is not defined for points in
% t that are close to the chebyshev nodes in x. If a point in t matches a
% point in x, then an additional claculation is required. If a point in t
% is very close to a gridpoint, then there is a slight loss of accuracy,
% which is more pronounced.
%

%Check to see if the t vector is on the proper domain:
if min(t) < d(1) || max(t) > d(2)
   disp('WARNING - the input to chebyshevInterpolate does not lie on the domain that was specified for the function')
   disp('    --> This can lead to unpredictable outputs and is not suggested.')
end

%Get the chebyshev points
[k,n] = size(f);
x = chebyshevPoints(n,d);
ONE1 = ones(k,1);
ONE2 = ones(1,length(t));

%Loop through each chebyshev node.
num = zeros(k,length(t));
den = zeros(k,length(t));
for i=1:n
    val = ONE1*(1./(t-x(i)));
    if mod(i,2)==1, val=-val; end;
    if i==1 || i==n
        num = num + 0.5*(f(:,i)*ONE2).*val;
        den = den + 0.5*(val);
    else
        num = num + (f(:,i)*ONE2).*val;
        den = den + val;
    end
end

%compute the solution:
y = num./den;

%Check for any values that were too close to nodes and correct them
nanIdx = isnan(y);
if sum(sum(nanIdx))>0
    nanRowIdx = max(nanIdx,[],1);
    y(:,nanRowIdx) = interp1(x',f',t(nanRowIdx)')';
end

%%%% Derivative Calculations %%%%
if nargout == 2
    Df = chebyshevDerivative(f,d);
    Dy = chebyshevInterpolate(Df,t,d);
elseif nargout == 3
    [Df, DDf] = chebyshevDerivative(f,d);
    Dy = chebyshevInterpolate(Df,t,d);
    DDy = chebyshevInterpolate(DDf,t,d);
elseif nargout == 4
    [Df, DDf, DDDf] = chebyshevDerivative(f,d);
    Dy = chebyshevInterpolate(Df,t,d);
    DDy = chebyshevInterpolate(DDf,t,d);
    DDDy = chebyshevInterpolate(DDDf,t,d);
end

end

% %  % This block of code provides a more efficient way of computing the
% %  % derivative of the function for very high order polynomial fits.
% %  %
% %  % It turns out that computing the differentiation matrix, which is done in
% %  % chebyshevDerivative, is an order n^2 calculation, which takes a long
% %  % time to compute for high order fits. This code is faster, but it is
% %  % not as accurate, especially near (or on) the gridpoints.
% %  %
% %  % To implement this code, put it between the lines:
% %  %    --> %%%% Derivative Calculations %%%%
% %  %    --> if nargout == 2
% %  %          CODE HERE
% %  %    --> end
% %  % Note that this would prevent the code from calculating higher order
% %  % derivatives.
% %
% %
% %
% %     %Loop through each chebyshev node again, slightly different math
% %     numDer = zeros(1,length(t));
% %     denDer = zeros(1,length(t));
% %     for i=1:n
% %         val = 1./(t-x(i)).^2;
% %         if mod(i,2)==1, val=-val; end;
% %         if i==1 || i==n
% %             numDer = numDer - 0.5*f(i).*(val);
% %             denDer = denDer - 0.5*(val);
% %         else
% %             numDer = numDer - f(i).*val;
% %             denDer = denDer - val;
% %         end
% %     end
% %
% %     %Compute the derivative of the approximation
% %     Dy = (numDer.*den - num.*denDer)./(den.^2);
% %
% %     %Check for any values that were to close to nodes
% %     %    -> NOTE - It is expensive to call chebyshevDerivative because it
% %     %       it computes a huge matrix just to take one or two derivatives.
% %     %    -> If speed is more important than accuracy, replace the contents
% %     %       of the folloging if statement with the code in comments after
% %     %       the end of the function. This uses a 4th order accurate central
% %     %       difference to compute the derivative.
% %     %
% %     nanIdx = isnan(Dy);
% %     nanSum = sum(nanIdx);
% %     if nanSum>0
% %
% %  %Use a 4th order central difference to get any values that were Nan
% %
% %         %This was determined experimentally:
% %         %  --> Too Small - run into machine precision
% %         %  --> Too Big - doesn't capture local shape well
% %         SMALL_NUMBER = 10^(-2*log10(length(f)));
% %
% %         %Get a vector of times that we need function values at
% %         timeDiff = [...
% %             t(nanIdx) - 2*SMALL_NUMBER;
% %             t(nanIdx) - SMALL_NUMBER;
% %             t(nanIdx) + SMALL_NUMBER;
% %             t(nanIdx) + 2*SMALL_NUMBER];
% %         timeDiffVec = reshape(timeDiff,4*nanSum,1)';
% %
% %         %Get the values of the function at each point in timeDiff
% %         funcDiffVec = chebyshevInterpolate(f, timeDiffVec,d)';
% %         funcDiff = reshape(funcDiffVec,4,nanSum);
% %
% %         %From Wikipedia: Finite difference coefficient
% %         %http://en.wikipedia.org/wiki/Finite_difference_coefficient
% %         coeff = [1/12, -2/3, 2/3, -1/12];
% %
% %         %Correct the Nan values
% %         Dy(nanIdx) = sum(coeff*funcDiff,1)/SMALL_NUMBER;
% %     end


function volume = sphere_volume_nd ( dim_num, r )

%*****************************************************************************80
%
%% SPHERE_VOLUME_ND computes the volume of an implicit sphere in ND.
%
%  Discussion:
%
%    An implicit sphere in ND satisfies the equation:
%
%      sum ( ( X(1:N) - CENTER(1:N) )**2 ) = R**2
%
%    where R is the radius and CENTER is the center.
%
%    Results for the first few values of N are:
%
%    DIM_NUM  Volume
%    -     -----------------------
%    2                PI    * R**2
%    3     (4/3)    * PI    * R**3
%    4     (1/2)    * PI**2 * R**4
%    5     (8/15)   * PI**2 * R**5
%    6     (1/6)    * PI**3 * R**6
%    7     (16/105) * PI**3 * R**7
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    07 February 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the dimension of the space.
%
%    Input, real R, the radius of the sphere.
%
%    Output, real VOLUME, the volume of the sphere.
%
  volume = r^dim_num * sphere_unit_volume_nd ( dim_num );

  return
end


% IM = mkSquare(SIZE, PERIOD, DIRECTION, AMPLITUDE, PHASE, ORIGIN, TWIDTH)
%      or
% IM = mkSine(SIZE, FREQ, AMPLITUDE, PHASE, ORIGIN, TWIDTH)
%
% Compute a matrix of dimension SIZE (a [Y X] 2-vector, or a scalar)
% containing samples of a 2D square wave, with given PERIOD (in
% pixels), DIRECTION (radians, CW from X-axis, default = 0), AMPLITUDE
% (default = 1), and PHASE (radians, relative to ORIGIN, default = 0).
% ORIGIN defaults to the center of the image.  TWIDTH specifies width
% of raised-cosine edges on the bars of the grating (default =
% min(2,period/3)).
%
% In the second form, FREQ is a 2-vector of frequencies (radians/pixel).

% Eero Simoncelli, 6/96.

% TODO: Add duty cycle.  Allow soft threshold (using rcosFn)

function [res] = mkSquare(sz, per_freq, dir_amp, amp_phase, phase_orig, orig_twidth, twidth)

%------------------------------------------------------------
%% OPTIONAL ARGS:

if (prod(size(per_freq)) == 2)
  frequency = norm(per_freq);
  direction = atan2(per_freq(1),per_freq(2));
  if (exist('dir_amp') == 1)
    amplitude = dir_amp;
  else
    amplitude = 1;
  end
  if (exist('amp_phase') == 1)
    phase = amp_phase;
  else
    phase = 0;
  end
  if (exist('phase_orig') == 1)
    origin = phase_orig;
  end
  if (exist('orig_twidth') == 1)
    transition = orig_twidth;
  else
    transition = min(2,2*pi/(3*frequency));
  end
  if (exist('twidth') == 1)
    error('Too many arguments for (second form) of mkSine');
  end
else
  frequency = 2*pi/per_freq;
  if (exist('dir_amp') == 1)
    direction = dir_amp;
  else
    direction = 0;
  end
  if (exist('amp_phase') == 1)
    amplitude = amp_phase;
  else
    amplitude = 1;
  end
  if (exist('phase_orig') == 1)
    phase = phase_orig;
  else
    phase = 0;
  end
  if (exist('orig_twidth') == 1)
    origin = orig_twidth;
  end
  if (exist('twidth') == 1)
    transition = twidth;
  else
    transition = min(2,2*pi/(3*frequency));
  end

end

%------------------------------------------------------------

if (exist('origin') == 1)
  res = sin(mkRamp(sz, direction, frequency, phase, origin));
else
  res = sin(mkRamp(sz, direction, frequency, phase));
end

[Xtbl,Ytbl] = rcosFn(2*sin(frequency*transition/2),0,[-amplitude amplitude]);

res = pointOp(res,Ytbl,Xtbl(1),Xtbl(2)-Xtbl(1),0);

% OLD threshold version:
%res = amplitude * (mod(res,2*pi) < pi);


function [ x, y, seed ] = circle_segment_sample_from_height ( r, h, n, seed )

%*****************************************************************************80
%
%% CIRCLE_SEGMENT_SAMPLE_FROM_HEIGHT samples points from a circle segment.
%
%  Discussion:
%
%    Begin with a circle of radius R.  Choose two points P1 and P2 on the
%    circle, and draw the chord P1:P2.  This chord divides the circle
%    into two pieces, each of which is called a circle segment.
%    Consider one of the pieces.  The "angle" of this segment is the angle
%    P1:C:P2, where C is the center of the circle.  Let Q be the point on
%    the chord P1:P2 which is closest to C.  The "height" of the segment
%    is the distance from Q to the perimeter of the circle.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 May 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real R, the radius of the circle.
%    0 < R.
%
%    Input, real H, the height of the circle segment.
%    0 <= H <= 2 * R.
%
%    Input, integer N, the number of sample points.
%
%    Input/output, integer SEED, a seed for the random number generator.
%
%    Output, real X(N,1), Y(N,1), the sample points.
%
  area = circle_segment_area_from_height ( r, h );
%
%  Pick CDF's randomly.
%
  if ( seed == 0 )
    u = rand ( n, 1 );
  else
    [ u, seed ] = r8vec_uniform_01 ( n, seed );
  end
%
%  Choose points randomly by choosing ordered areas randomly.
%
  area2(1:n,1) = u(1:n,1) * area;
%
%  Each area corresponds to a height H2.  Find it.
%
  h2 = zeros ( n, 1 );
  for i = 1 : n
    h2(i,1) = circle_segment_height_from_area ( r, area2(i,1) );
  end
%
%  Determine the half-width WH of the segment for each H2.
%
  wh(1:n,1) = sqrt ( h2(1:n,1) .* ( 2.0 * r - h2(1:n,1) ) );
%
%  Choose an X position randomly in [-WH,+WH].
%
  if ( seed == 0 )
    u = rand ( n, 1 );
  else
    [ u, seed ] = r8vec_uniform_01 ( n, seed );
  end

  x(1:n,1) = ( 2.0 * u(1:n,1) - 1.0 ) .* wh(1:n,1);
%
%  Our circle center is at (0,0).  Our height of H2 is subtracted
%  from the height R at the peak of the circle.  Determine the Y
%  coordinate using this fact.
%
  y(1:n,1) = r - h2(1:n,1);

  return
end


function value = i4_factorial2 ( n )

%*****************************************************************************80
%
%% I4_FACTORIAL2 computes the double factorial N!!
%
%  Formula:
%
%    FACTORIAL2( N ) = Product ( N * (N-2) * (N-4) * ... * 2 )  (N even)
%                    = Product ( N * (N-2) * (N-4) * ... * 1 )  (N odd)
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 January 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the argument of the double factorial function.
%    If N is less than 1, the value is returned as 1.
%
%    Output, integer VALUE, the value of N!!.
%
  if ( n < 1 )
    value = 1;
    return
  end

  value = 1;

  while ( 1 < n )
    value = value * n;
    n = n - 2;
  end

  return
end


function area = circle_segment_area_from_angle ( r, theta )

%*****************************************************************************80
%
%% CIRCLE_SEGMENT_AREA_FROM_ANGLE computes the area of a circle segment.
%
%  Discussion:
%
%    Begin with a circle of radius R.  Choose two points P1 and P2 on the
%    circle, and draw the chord P1:P2.  This chord divides the circle
%    into two pieces, each of which is called a circle segment.
%    Consider one of the pieces.  The "angle" of this segment is the angle
%    P1:C:P2, where C is the center of the circle.  Let Q be the point on
%    the chord P1:P2 which is closest to C.  The "height" of the segment
%    is the distance from Q to the perimeter of the circle.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 May 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real R, the radius of the circle.
%    0 < R.
%
%    Input, real THETA, the angle of the circle segment.
%
%    Output, real AREA, the area of the circle segment.
%
  area = r * r * ( theta - sin ( theta ) ) / 2.0;

  return
end


% COST function.
% It shows how accurate our model is based on current model parameters.
function [cost] = cost_function(X, y, theta, lambda)
    % Input:
    % X - input features - (m x n) matrix.
    % theta - our model parameters - (n x 1) vector.
    % y - a vector of correct output - (m x 1) vector.
    % lambda - regularization parameter.
    %
    % Output:
    % cost - number that represents the cost (error) of our model with specified parameters theta.
    %
    % Where:
    % m - number of training examples,
    % n - number of features.

    % Get the size of the trainging set.
    m = size(X, 1);

    % Get the difference between predictions and correct output values.
    differences = hypothesis(X, theta) - y;

    % Calculate regularization parameter.
    % Remember that we should not regularize the parameter theta_zero.
    theta_cut = theta(2:end, 1);
    regularization_param = lambda * (theta_cut' * theta_cut);

    % Calculate current predictions cost.
    cost = (1 / 2 * m) * (differences' * differences + regularization_param);
end


function [X_norm, mu, sigma] = featureNormalize(X)
%FEATURENORMALIZE Normalizes the features in X
%   FEATURENORMALIZE(X) returns a normalized version of X where
%   the mean value of each feature is 0 and the standard deviation
%   is 1. This is often a good preprocessing step to do when
%   working with learning algorithms.

% You need to set these values correctly
X_norm = X;
mu = zeros(1, size(X, 2));
sigma = zeros(1, size(X, 2));

% ====================== YOUR CODE HERE ======================
% Instructions: First, for each feature dimension, compute the mean
%               of the feature and subtract it from the dataset,
%               storing the mean value in mu. Next, compute the
%               standard deviation of each feature and divide
%               each feature by it's standard deviation, storing
%               the standard deviation in sigma.
%
%               Note that X is a matrix where each column is a
%               feature and each row is an example. You need
%               to perform the normalization separately for
%               each feature.
%
% Hint: You might find the 'mean' and 'std' functions useful.
%

mu = mean(X);
sigma = std(X);
X_norm = (X - repmat(mu, [size(X,1), 1]))./repmat(sigma, [size(X,1), 1]);

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

end


function val=erfComplex(z)
%%ERFCOMPLEX Evaluate the error function in a manner valid for complex
%            arguemnts. Matlab's built-in function erf cannot handle
%            complex arguments. The error function is defined as
%            (2/pi)*integral_0^z exp(-t^2) dt.
%
%INPUTS: z A scalar, vector, or matrix of values at which one wishes to
%          evaluate the error function.
%
%OUTPUTS: val A matrix having the same dimensions as z in which the values
%             of the scaled error function are computed for the values in
%             z.
%
%For values of abs(z)<0.08, six terms of the maclaurin series in [1] are
%used. These should be sufficient for convergence. For larger values, the
%Faddeeva function is used through the relation
%erf(z)=1-exp(-z^2)*Faddeeva(1i*z);
%
%REFERENCES:
%[1] Weisstein, Eric W. "Erf." From MathWorld--A Wolfram Web Resource
%    http://mathworld.wolfram.com/Erf.html
%
%November 2016 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

numVals=numel(z);

zList=z;
val=zeros(size(z));

for curVal=1:numVals
    z=zList(curVal);
    y=imag(z);
    %If the argument is real, the built-in erf function is faster.
    if(y==0)
        x=real(z);
        val(curVal)=erf(x);
        continue;
    end

    if(abs(z)<0.08)
        %Use the Maclaurin series. For abs(z)<0.08, convergence occurs
        %within 6 terms.
        NMax=6;
        z2=z^2;

        %Initialize to the n=0 term
        sumVal=z;
        prodVal=z;
        for n=1:NMax
            prodVal=prodVal*z2*(1-2*n)/(n*(1+2*n));
            sumVal=sumVal+prodVal;
        end

        val(curVal)=2/sqrt(pi)*sumVal;
    else%Compute using the Faddeeva function.
        val(curVal)=1-exp(-z^2)*Faddeeva(1i*z);
    end
end
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 [J, grad] = costFunctionReg(theta, X, y, lambda)
%COSTFUNCTIONREG Compute cost and gradient for logistic regression with regularization
%   J = COSTFUNCTIONREG(theta, X, y, lambda) computes the cost of using
%   theta as the parameter for regularized 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

predictions =  sigmoid(X*theta);

leftPart = -y' * log(predictions);

rightPart = (1 - y') * log(1 - predictions);

thetaZero = theta;

thetaZero(1) = 0;

lambaCostPart = (lambda / (2 * m)) * sum(thetaZero .^ 2);

lambdaGradPart = lambda / m * thetaZero;

J = (1 / m) * (leftPart - rightPart) + lambaCostPart;

grad = ((1/m) * (X' * (predictions - y))) + lambdaGradPart;

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

end


function value = pyramid_grid_size ( n )

%*****************************************************************************80
%
%% PYRAMID_GRID_SIZE sizes a pyramid grid.
%
%  Discussion:
%
%    0:  x
%
%    1:  x  x
%        x  x
%
%    2:  x  x  x
%        x  x  x
%        x  x  x
%
%    3:  x  x  x  x
%        x  x  x  x
%        x  x  x  x
%        x  x  x  x
%
%    N  Size
%
%    0     1
%    1     5 = 1 + 4
%    2    14 = 1 + 4 + 9
%    3    30 = 1 + 4 + 9 + 16
%    4    55 = 1 + 4 + 9 + 16 + 25
%    5    91 = 1 + 4 + 9 + 16 + 25 + 36
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 August 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of subintervals.
%
%    Output, integer VALUE, the number of
%    nodes in the grid of size N.
%
  np1 = n + 1;

  value = ( np1 * ( np1 + 1 ) * ( 2 * np1 + 1 ) ) / 6;

  return
end


function volume = sphere_volume_nd ( dim_num, r )

%*****************************************************************************80
%
%% SPHERE_VOLUME_ND computes the volume of an implicit sphere in ND.
%
%  Discussion:
%
%    An implicit sphere in ND satisfies the equation:
%
%      sum ( ( X(1:N) - CENTER(1:N) )^2 ) = R * R
%
%    where R is the radius and CENTER is the center.
%
%    Results for the first few values of N are:
%
%    DIM_NUM  Volume
%    -     -----------------------
%    2                PI   * R^2
%    3     (4/3)    * PI   * R^3
%    4     (1/2)    * PI^2 * R^4
%    5     (8/15)   * PI^2 * R^5
%    6     (1/6)    * PI^3 * R^6
%    7     (16/105) * PI^3 * R^7
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    03 April 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the dimension of the space.
%
%    Input, real R, the radius of the sphere.
%
%    Output, real VOLUME, the volume of the sphere.
%
  volume = r^dim_num * sphere_unit_volume_nd ( dim_num );

  return
end


function varargout = cyl2cart(varargin)
%CYL2CART  Convert cylindrical to cartesian coordinates
%
%   CART = cyl2cart(CYL)
%   convert the 3D cylindrical coordinates of points CYL (given by
%   [THETA R Z] where THETA, R, and Z have the same size) into cartesian
%   coordinates CART, given by [X Y Z].
%   The transforms is the following :
%   X = R*cos(THETA);
%   Y = R*sin(THETA);
%   Z remains inchanged.
%
%   CART = cyl2cart(THETA, R, Z)
%   provides coordinates as 3 different parameters
%
%   Example
%   cyl2cart([-1 0 2])
%   gives : 4.7124    1.0000     2.0000
%
%   See also angles3d, cart2pol, cart2sph2, cart2cyl
%
%
% ------
% Author: David Legland
% e-mail: david.legland@jouy.inra.fr
% Created: 2006-03-23
% Copyright 2006 INRA - CEPIA Nantes - MIAJ (Jouy-en-Josas).

% process input parameters
if length(varargin)==1
    var = varargin{1};
    theta = var(:,1);
    r = var(:,2);
    z = var(:,3);
elseif length(varargin)==3
    theta = varargin{1};
    r = varargin{2};
    z = varargin{3};
end

% convert coordinates
dim = size(theta);
x = reshape(r(:).*cos(theta(:)), dim);
y = reshape(r(:).*sin(theta(:)), dim);

% process output parameters
if nargout==0 ||nargout==1
    if length(dim)>2 || dim(2)>1
        varargout{1} = {x y z};
    else
        varargout{1} = [x y z];
    end
elseif nargout==3
    varargout{1} = x;
    varargout{2} = y;
    varargout{3} = z;
end


function [J, grad] = costFunctionReg(theta, X, y, lambda)
%COSTFUNCTIONREG Compute cost and gradient for logistic regression with regularization
%   J = COSTFUNCTIONREG(theta, X, y, lambda) computes the cost of using
%   theta as the parameter for regularized 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

J = 1 / m * (- y' * log(sigmoid(X * theta)) - (1.- y)' * log(1.- sigmoid(X * theta))) + lambda / (2 * m) * theta(2:end,end)' * theta(2:end,end);

grad(1,1) = 1 / m * (X(:,1)' * (sigmoid(X * theta) - y))
grad(2:end,1) = (1 / m * (X(:,2:end)' * (sigmoid(X * theta) - y)) + lambda / m * theta(2:end));

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

end


function k = triangle_to_i4 ( i, j )

%*****************************************************************************80
%
%% TRIANGLE_TO_I4 converts a triangular coordinate to an integer.
%
%  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.
%
%    Thus, our goal is, given the row I and column J of the data,
%    to produce the value K which indicates its position in the linear
%    array.
%
%    The triangular numbers are the indices associated with the
%    diagonal elements of the original array, T(1,1), T(2,2), T(3,3)
%    and so on.
%
%  Formula:
%
%    K = J + ( (I-1) * I ) / 2
%
%  First Values:
%
%     I  J  K
%
%     0  0  0
%     1  1  1
%     2  1  2
%     2  2  3
%     3  1  4
%     3  2  5
%     3  3  6
%     4  1  7
%     4  2  8
%     4  3  9
%     4  4 10
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 July 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer I, J, the row and column indices.  I and J must
%    be nonnegative, and J must not be greater than I.
%
%    Output, integer K, the linear index of the (I,J) element.
%
  if ( i < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TRIANGLE_TO_I4 - Fatal error!\n' );
    fprintf ( 1, '  I < 0.\n' );
    fprintf ( 1, '  I = %d\n', i );
    error ( 'TRIANGLE_TO_I4 - Fatal error!' );
  elseif ( j < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TRIANGLE_TO_I4 - Fatal error!\n' );
    fprintf ( 1, '  J < 0.\n' );
    fprintf ( 1, '  J = %d\n', j );
    error ( 'TRIANGLE_TO_I4 - Fatal error!' );
  elseif ( i < j )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TRIANGLE_TO_I4 - Fatal error!\n' );
    fprintf ( 1, '  I < J.\n' );
    fprintf ( 1, '  I = %d\n', i );
    fprintf ( 1, '  J = %d\n', j );
    error ( 'TRIANGLE_TO_I4 - Fatal error!' );
  end

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

  return
end


function [ n_data, n, c ] = catalan_values ( n_data )

%*****************************************************************************80
%
%% CATALAN_VALUES returns some values of the Catalan numbers.
%
%  Discussion:
%
%    In Mathematica, the function can be evaluated by:
%
%      Binomial[2*n,n] / ( n + 1 )
%
%  First values:
%
%     C(0)     1
%     C(1)     1
%     C(2)     2
%     C(3)     5
%     C(4)    14
%     C(5)    42
%     C(6)   132
%     C(7)   429
%     C(8)  1430
%     C(9)  4862
%    C(10) 16796
%
%  Formula:
%
%    C(N) = (2*N)! / ( (N+1) * (N!) * (N!) )
%         = 1 / (N+1) * COMB ( 2N, N )
%         = 1 / (2N+1) * COMB ( 2N+1, N+1).
%
%  Recursion:
%
%    C(N) = 2 * (2*N-1) * C(N-1) / (N+1)
%    C(N) = sum ( 1 <= I <= N-1 ) C(I) * C(N-I)
%
%  Discussion:
%
%    The Catalan number C(N) counts:
%
%    1) the number of binary trees on N vertices;
%    2) the number of ordered trees on N+1 vertices;
%    3) the number of full binary trees on 2N+1 vertices;
%    4) the number of well formed sequences of 2N parentheses;
%    5) the number of ways 2N ballots can be counted, in order,
%       with N positive and N negative, so that the running sum
%       is never negative;
%    6) the number of standard tableaus in a 2 by N rectangular Ferrers diagram;
%    7) the number of monotone functions from [1..N} to [1..N} which
%       satisfy f(i) <= i for all i;
%    8) the number of ways to triangulate a polygon with N+2 vertices.
%
%  Example:
%
%    N = 3
%
%    ()()()
%    ()(())
%    (()())
%    (())()
%    ((()))
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 September 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Milton Abramowitz and Irene Stegun,
%    Handbook of Mathematical Functions,
%    US Department of Commerce, 1964.
%
%    Stephen Wolfram,
%    The Mathematica Book,
%    Fourth Edition,
%    Wolfram Media / Cambridge University Press, 1999.
%
%  Parameters:
%
%    Input/output, integer N_DATA.  The user sets N_DATA to 0 before the
%    first call.  On each call, the routine increments N_DATA by 1, and
%    returns the corresponding data; when there is no more data, the
%    output value of N_DATA will be 0 again.
%
%    Output, integer N, the order of the Catalan number.
%
%    Output, integer C, the value of the Catalan number.
%
  n_max = 11;

  c_vec = [ ...
    1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796 ];

  n_vec = [ ...
     0,  1,  2,  3,  4, 5,  6,  7,  8,  9,  10 ];

  if ( n_data < 0 )
    n_data = 0;
  end

  n_data = n_data + 1;

  if ( n_max < n_data )
    n_data = 0;
    n = 0;
    c = 0;
  else
    n = n_vec(n_data);
    c = c_vec(n_data);
  end

  return
end


function centroid = polygon_centroid_2d ( n, v )

%*****************************************************************************80
%
%% POLYGON_CENTROID_2D computes the centroid of a polygon in 2D.
%
%  Discussion:
%
%    Denoting the centroid coordinates by CENTROID, then
%
%      CENTROID(1) = Integral ( Polygon interior ) x dx dy / Area ( Polygon )
%      CENTROID(2) = Integral ( Polygon interior ) y dx dy / Area ( Polygon ).
%
%    Green's theorem states that for continuously differentiable functions
%    M(x,y) and N(x,y),
%
%      Integral ( Polygon boundary ) ( M dx + N dy ) =
%      Integral ( Polygon interior ) ( dN/dx - dM/dy ) dx dy.
%
%    Using M(x,y) = 0 and N(x,y) = x**2/2, we get:
%
%      CENTROID(1) = 0.5 * Integral ( Polygon boundary ) x**2 dy
%                  / Area ( Polygon ),
%
%    which becomes
%
%      CENTROID(1) = 1/6 sum ( 1 <= I <= N )
%        ( X(I+1) + X(I) ) * ( X(I) * Y(I+1) - X(I+1) * Y(I))
%        / Area ( Polygon )
%
%    where, when I = N, the index "I+1" is replaced by 1.
%
%    A similar calculation gives us a formula for CENTROID(2).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 May 2005
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Gerard Bashein and Paul Detmer,
%    Centroid of a Polygon,
%    Graphics Gems IV,
%    edited by Paul Heckbert,
%    AP Professional, 1994.
%
%  Parameters:
%
%    Input, integer N, the number of sides of the polygon.
%
%    Input, real V(2,N), the coordinates of the vertices.
%
%    Output, real CENTROID(2,1), the coordinates of the centroid.
%
  area = 0.0;
  centroid(1:2,1) = 0.0;

  for i = 1 : n

    if ( i < n )
      ip1 = i + 1;
    else
      ip1 = 1;
    end

    temp = ( v(1,i) * v(2,ip1) - v(1,ip1) * v(2,i) );

    area = area + temp;

    centroid(1:2,1) = centroid(1:2,1) + ( v(1:2,ip1) + v(1:2,i) )' * temp;

  end

  area = area / 2.0;

  if ( area == 0.0 )
    centroid(1:2,1) = v(1:2,1);
  else
    centroid(1:2,1) = centroid(1:2,1) / ( 6.0 * area );
  end

  return
end


function[f]=fourier(varargin)
%FOURIER  Returns the Fourier frequencies for a given length time series.
%
%   F=FOURIER(M) returns the one-sided (or positive) Fourier frequencies
%   for a time series of length M.
%
%   F is a radian or angular frequency so that the Nyquist is at PI.
%
%   F=FOURIER(M,'two') instead returns the two-sided Fourier frequencies.
%   The default behavior is equivalent to F=FOURIER(M,'one').
%
%   F=FOURIER(DT,M) uses sample rate DT in calculating the frequencies, so
%   that the Nyquist will be at PI/DT.
%
%   Note that the highest resolved frequency, MAX(F), differs for even or
%   odd M.  For even M, it is the Nyquist PI/DT, but for odd M the Nyquist
%   is not resolved and the highest resolved frequency is (M-1)/M * PI/DT.
%
%   For the one-sided option, F has length FLOOR(M/2)+1, or M/2+1 for even
%   M, and (M+1)/2 for odd M.  For the two-sided option, F has length M.
%   __________________________________________________________________
%
%   Array input
%
%   F=FOURIER(M) also works if M an array instead of a scalar.  In this
%   case, F is a cell array with LENGTH(M) elements.
%
%   F=FOURIER(DT,M) with M being an array works provided DT is either a
%   scalar or an array of the same length as M.
%   __________________________________________________________________
%
%   See also CENTEREDTIMES.
%
%   Usage: f=fourier(M);
%          f=fourier(dt,M);
%          f=fourier(dt,M,'two');
%   __________________________________________________________________
%   This is part of JLAB --- type 'help jlab' for more information
%   (C) 2011--2019 J.M. Lilly --- type 'help jlab_license' for details

if strcmpi(varargin{1}, '--t')
    fourier_test,return
end

str='one';
if ischar(varargin{end})
    str=varargin{end}(1:3);
    varargin=varargin(1:end-1);
end

if length(varargin)==1
    N=varargin{1};
    dt=1;
else
    dt=varargin{1};
    N=varargin{2};
end

if length(N)==1
    f=fourier_one(dt,N,str);
else
    if length(dt)==1
        dt=dt+zeros(size(N));
    elseif length(dt)~=length(N)
        error('If N is an array, DT must either be a scalar or an array of the same length.')
    end
    for i=1:length(N)
        f{i,1}=fourier_one(dt,N(i),str);
    end
end

function[f]=fourier_one(dt,N,str)

if strcmpi(str,'one')
    f=2*pi*(0:floor(N/2))'./N;
else
    f=2*pi*(0:N-1)'./N;
    index=find(f>pi);
    f(index)=f(index)-2*pi;
end

% if iseven(N)
%     f=(0:1./N:1/2)';
% elseif isodd(N)
%     f=(0:1./N:1/2*frac(N-1,N))';
% end

f=f./dt;

function[]=fourier_test

reporttest('FOURIER is length N/2+1 for even N',length(fourier(10))==6);
reporttest('FOURIER is length (N+1)/2 for odd N',length(fourier(11))==6);

%Even and odd length frequencies behave differently, which you can see with
%abs(fft(cos(pi*[1:10]'))).^2
%abs(fft(cos(pi*[1:11]'))).^2
%abs(fft(cos((10/11)*pi*[1:11]'))).^2


function h=sgsf_2d(x,y,px,py,flag_coupling)
%Function:
%       2-D Savitzky-Golay smoothing filter (i.e., the polynomial smoothing
%       filter, or the least-squares smoothing filter)
%       See Ref. [1] for details on the 1-D Savitzky-Golay smoothing filter.
%       One can also refer to the following URL where a program of
%       1-D Savitzky-Golay smoothing (and differentiation) filter is given:
%       http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=4038&objectType=file
%       See Ref. [2] and [3] for details on the 2-D Savitzky-Golay smoothing filter.
%Usage:
%       h=sgsf_2d(x,y,px,py,flag_coupling)
%       x    = x data point, e.g., -3:3
%       y    = y data point, e.g., -2:2
%       px    =x polynomial order       default=1
%       py    =y polynomial order       default=1
%       flag_coupling  = with or without the consideration of the coupling terms, between x and y. default=0
%Example:
%       sgsf_2d(-3:3,-3:3,2,2)
%       sgsf_2d(-3:3,-3:3,2,2,1)
%Author:
%       Jianwen Luo <luojw@bme.tsinghua.edu.cn, luojw@ieee.org> 2003-12-15
%       Department of Biomedical Engineering, Department of Electrical Engineering
%       Tsinghua University, Beijing 100084, P. R. China
%Reference
%[1]A. Savitzky and M. J. E. Golay, "Smoothing and Differentiation of Data by Simplified Least Squares Procedures,"
%   Analytical Chemistry, vol. 36, pp. 1627-1639, 1964.
%[2]K. L. Ratzlaff and J. T. Johnson, "Computation of Two-Dimensional Polynomial Least-Squares Convolution Smoothing Integers,"
%   Analytical Chemistry, vol. 61, pp. 1303-1305, 1989.
%[3]J. E. Kuo, H. Wang, and S. Pickup, "Multidimensional Least-Squares Smoothing Using Orthogonal Polynomials,"
%   Analytical Chemistry, vol. 63, pp. 630-635, 1991.

if nargin<5
    flag_coupling=0;
end

if nargin<4
    py=1;
end

if nargin<3
    px=1;
end

[x,y]=meshgrid(x,y);
[ly,lx]=size(x);

x=x(:);
y=y(:);

A=[];

if flag_coupling
    for kx=px:-1:0
        for ky=py:-1:0
            A=[A x.^kx.*y.^ky];
        end
    end
else
    for k=px:-1:1
        A=[A x.^k];
    end
    for k=py:-1:0
        A=[A y.^k];
    end
end

h=inv(A'*A)*A';
h=h(size(h,1),:);
h=reshape(h,ly,lx);


function [g, c, tmp, m]=kMeansCluster(m,k,isRand)
%%%%%%%%%%%%%%%%
%
% kMeansCluster - Simple k means clustering algorithm
% Author: Kardi Teknomo, Ph.D.
%
% Purpose: classify the objects in data matrix based on the attributes
% Criteria: minimize Euclidean distance between centroids and object points
% For more explanation of the algorithm, see http://people.revoledu.com/kardi/tutorial/kMean/index.html
% Output: matrix data plus an additional column represent the group of each object
%
% Example: m = [ 1 1; 2 1; 4 3; 5 4]  or in a nice form
%          m = [ 1 1;
%                2 1;
%                4 3;
%                5 4]
%          k = 2
% kMeansCluster(m,k) produces m = [ 1 1 1;
%                                   2 1 1;
%                                   4 3 2;
%                                   5 4 2]
% Input:
%   m      - required, matrix data: objects in rows and attributes in columns
%   k      - optional, number of groups (default = 1)
%   isRand - optional, if using random initialization isRand=1, otherwise input any number (default)
%            it will assign the first k data as initial centroids
%
% Local Variables
%   f      - row number of data that belong to group i
%   c      - centroid coordinate size (1:k, 1:maxCol)
%   g      - current iteration group matrix size (1:maxRow)
%   i      - scalar iterator
%   maxCol - scalar number of rows in the data matrix m = number of attributes
%   maxRow - scalar number of columns in the data matrix m = number of objects
%   temp   - previous iteration group matrix size (1:maxRow)
%   z      - minimum value (not needed)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin<3,        isRand=0;   end
if nargin<2,        k=1;        end
tmp = [];

[maxRow, maxCol]=size(m);
if maxRow<=k,
    y=[m, 1:maxRow];
else

	% initial value of centroid
    if isRand,
        p = randperm(size(m,1));      % random initialization
        for i=1:k
            c(i,:)=m(p(i),:)
    	end
    else
        for i=1:k
           c(i,:)=m(i,:);        % sequential initialization
    	end
    end

	temp=zeros(maxRow,1);   % initialize as zero vector

	while 1,
        d=DistMatrix(m,c);  % calculate objcets-centroid distances
        [z,g]=min(d,[],2);  % find group matrix g
        if g==temp,
            break;          % stop the iteration
        else
            temp=g;         % copy group matrix to temporary variable
        end
        for i=1:k
            f=find(g==i);
            if f            % only compute centroid if f is not empty
                c(i,:)=mean(m(find(g==i),:),1);
            end
        end
	end

	y=[m,g];

end

%The Matlab function kMeansCluster above call function DistMatrix as shown in the code below. It works for multi-dimensional Euclidean distance. Learn about other type of distance here.

    function d=DistMatrix(A,B)
                 %%%%%%%%%%%%%%%%%%%%%%%%%
                 % DISTMATRIX return distance matrix between points in A=[x1 y1 ... w1] and in B=[x2 y2 ... w2]
                 % Copyright (c) 2005 by Kardi Teknomo,  http://people.revoledu.com/kardi/
                 %
                 % Numbers of rows (represent points) in A and B are not necessarily the same.
                 % It can be use for distance-in-a-slice (Spacing) or distance-between-slice (Headway),
                 %
                 % A and B must contain the same number of columns (represent variables of n dimensions),
                 % first column is the X coordinates, second column is the Y coordinates, and so on.
                 % The distance matrix is distance between points in A as rows
                 % and points in B as columns.
                 % example: Spacing= dist(A,A)
                 % Headway = dist(A,B), with hA ~= hB or hA=hB
                 %          A=[1 2 3; 4 5 6; 2 4 6; 1 2 3]; B=[4 5 1; 6 2 0]
                 %          dist(A,B)= [ 4.69   5.83;
                 %                       5.00   7.00;
                 %                       5.48   7.48;
                 %                       4.69   5.83]
                 %
                 %          dist(B,A)= [ 4.69   5.00     5.48    4.69;
                 %                       5.83   7.00     7.48    5.83]
                 %%%%%%%%%%%%%%%%%%%%%%%%%%%
                 [hA,wA]=size(A);
                 [hB,wB]=size(B);
                 if wA ~= wB,  error(' second dimension of A and B must be the same'); end
                 for k=1:wA
                      C{k}= repmat(A(:,k),1,hB);
                      D{k}= repmat(B(:,k),1,hA);
                 end
                 S=zeros(hA,hB);
                 for k=1:wA
                      S=S+(C{k}-D{k}').^2;
                 end
                 d=sqrt(S);


function S = cylinderSurfaceArea(cyl)
%CYLINDERSURFACEAREA  Surface area of a cylinder.
%
%   S = cylinderSurfaceArea(CYL)
%   Computes the surface area of the cylinder defined by:
%   CYL = [X1 Y1 Z1  X2 Y2 Z2  R],
%   where [X1 Y1 Z1] and [X2 Y2 Z2] are the coordinates of the cylinder
%   extremities, and R is the cylinder radius.
%   The surface area of the cylinder comprises the surface area of the two
%   disk-shape end caps.
%
%   Example
%     cyl = [0 0 0  1 0 0  1];
%     cylinderSurfaceArea(cyl)
%     ans =
%        12.5664
%     % equals to 4*pi
%
%   See also
%     geom3d, ellipsoidSurfaceArea, intersectLineCylinder

% ------
% Author: David Legland
% E-mail: david.legland@inra.fr
% Created: 2017-11-02, using Matlab 9.3.0.713579 (R2017b)
% Copyright 2017-2022 INRA - Cepia Software Platform

H = distancePoints3d(cyl(:, 1:3), cyl(:, 4:6));
R = cyl(:,7);

S1 = 2*pi*R .* H;
S2 = 2 * (pi * R.^2);

S = S1 + S2;


function [Zpca T U mu eigVecs] = myPCA(Z,r)
%--------------------------------------------------------------------------
% Syntax:       Zpca = myPCA(Z,r);
%               [Zpca T U mu] = myPCA(Z,r);
%               [Zpca T U mu eigVecs] = myPCA(Z,r);
%
% Inputs:       Z is an (d x n) matrix containing n samples of a
%               d-dimensional random vector
%
%               r is the desired number of principal components
%
% Outputs:      Zpca is a (r x n) matrix containing the r principal
%               components - scaled to variance 1 - of the input samples
%
%               U and T are the PCA transformation matrices such that
%               Zr = U / T * Zpca + repmat(mu,1,n);
%               is the r-dimensional PCA approximation of Z
%
%               mu is the (d x 1) sample mean of Z
%
%               eigVecs is a (d x r) matrix containing the scaled
%               eigenvectors of the sample covariance of Z
%
% Description:  This function performs principal component analysis (PCA)
%               on the input samples
%
% Author:       Brian Moore
%               brimoor@umich.edu
%
% Date:         April 26, 2015
%--------------------------------------------------------------------------

% Center data
[Zc mu] = myCenter(Z);

% Compute truncated SVD
%[U S V] = svds(Zc,r); % Equivalent, but usually slower than svd()
[U S V] = svd(Zc,'econ');
U = U(:,1:r);
S = S(1:r,1:r);
V = V(:,1:r);

% Compute principal components
Zpca = S * V';
%Zpca = U' * Zc; % Equivalent but slower

% Whiten data, if desired
%[Zpca T] = myWhiten(Zpca);
T = eye(r); % No whitening

% Return scaled eigenvectors, if necessary
if (nargout >= 5)
    [~,n] = size(Z);
    eigVecs = bsxfun(@times,U,diag(S)' / sqrt(n));
end


% EUCL: Calculates the euclidean distances among a set of points, or between a
%       reference point and a set of points, or among all possible pairs of two
%       sets of points, in P dimensions.  Returns a single distance for two points.
%
%     Syntax: dists = eucl(crds1,crds2)
%
%        crds1 = [N1 x P] matrix of point coordinates.  If N=1, it is taken to
%                   be the reference point.
%        crds2 = [N2 x P] matrix of point coordinates.  If N=1, it is taken to
%                   be the reference point.
%        -----------------------------------------------------------------------
%        dists = [N1 x N1] symmetric matrix of pairwise distances (if only crds1
%                   is specified);
%                [N1 x 1]  col vector of euclidean distances (if crds1 & ref
%                   are specified);
%                [1 x N2]  row vector of euclidean distances (if ref & crds2
%                   are specified);
%                [N1 x N2] rectangular matrix of pairwise distances (if crds1
%                   & crds2 are specified);
%                [1 x 1]   scalar (if crds1 is a [2 x P] matrix or ref1 & ref2
%                   are specified);
%

% RE Strauss, 5/4/94
%   10/28/95 - output row (rather than column) vector for the (reference
%               point)-(set of points) case; still outputs column vector for the
%               (set of points)-(reference point) case.
%   10/30/95 - for double for-loops, put one matrix-col access in outer loop
%               to increase speed.
%   10/12/96 - vectorize inner loop to increase speed.
%    6/12/98 - allow for P=1.
%   11/11/03 - initialize dists to NaN for error return.

function dists = eucl(crds1,crds2)
  if (~nargin) help eucl; return; end;
  dists = NaN;

  if (nargin < 2)                     % If only crds1 provided,
    [N,P] = size(crds1);
    if (N<2)
      error('  EUCL: need at least two points');
    end;

    crds1 = crds1';                     % Transpose crds
    dists = zeros(N,N);                 % Calculate pairwise distances

    for i = 1:N-1
      c1 = crds1(:,i) * ones(1,N-i);
      if (P>1)
        d = sqrt(sum((c1-crds1(:,(i+1:N))).^2));
      else
        d = abs(c1-crds1(:,(i+1:N)));
      end;
      dists(i,(i+1:N)) = d;
      dists((i+1:N),i) = d';
    end;
    if (N==2)                            % Single distance for two points
      dists = dists(1,2);
    end;

  else                                % If crds1 & crds2 provided,
    [N1,P1] = size(crds1);
    [N2,P2] = size(crds2);
    if (P1~=P2)
      error('  EUCL: sets of coordinates must be of same dimension');
    else
      P = P1;
    end;

    crds1 = crds1';                     % Transpose crds
    crds2 = crds2';

    if (N1>1 & N2>1)                    % If two matrices provided,
      dists = zeros(N1,N2);               % Calc all pairwise distances between them
      for i = 1:N1
        c1 = crds1(:,i) * ones(1,N2);
        if (P>1)
          d = sqrt(sum((c1-crds2).^2));
        else
          d = abs(c1-crds2);
        end;
        dists(i,:) = d;
      end;
    end;

    if (N1==1 & N2==1)                  % If two vectors provided,
      dists = sqrt(sum((crds1-crds2).^2));  % Calc scalar
    end;

    if (N1>1 & N2==1)                   % If matrix & reference point provided,
      crds1 = crds1 - (ones(N1,1)*crds2')'; % Center points on reference point
      if (P>1)                              % Calc euclidean distances in P-space
         dists = sqrt(sum(crds1.^2))';
      else
         dists = abs(crds1)';
      end;
    end;                                    % Return column vector

    if (N1==1 & N2>1)                   % If reference point & matrix provided,
      crds2 = crds2 - (ones(N2,1)*crds1')'; % Center points on reference point
      if (P>1)                              % Calc euclidean distances in P-space
        dists = sqrt(sum(crds2.^2));
      else
        dists = abs(crds2);
      end;
    end;                                    % Return row vector
  end;

  return;


function area = triangleArea(pt1, pt2, pt3)
%TRIANGLEAREA Signed area of a triangle.
%
%   AREA = triangleArea(P1, P2, P3)
%   Computes area of the triangle whose vertices are given by P1, P2 and
%   P3. Each vertex is a 1-by-2 row vector.
%
%   AREA = triangleArea(PTS)
%   Concatenates vertex coordinates in a 3-by-2 array. Each row of the
%   array contains coordinates of one vertex.
%
%
%   Example
%   % Compute area of a Counter-Clockwise (CCW) oriented triangle
%     triangleArea([10 10], [30 10], [10 40])
%     ans =
%         300
%
%   % Compute area of a Clockwise (CW) oriented triangle
%     triangleArea([10 40], [30 10], [10 10])
%     ans =
%         -300
%
%   See also
%   polygonArea, triangleArea3d

% ------
% Author: David Legland
% E-mail: david.legland@grignon.inra.fr
% Created: 2011-08-23, using Matlab 7.9.0.529 (R2009b)
% Copyright 2011-2022 INRA - Cepia Software Platform

% if data is given as one array, split vertices
if nargin == 1
    pt2 = pt1(2,:);
    pt3 = pt1(3,:);
    pt1 = pt1(1,:);
end

% compute individual vectors
v12 = bsxfun(@minus, pt2, pt1);
v13 = bsxfun(@minus, pt3, pt1);

% compute area from cross product
area = (v13(:,2) .* v12(:,1) - v13(:,1) .* v12(:,2)) / 2;


%SOLVELP  Solve given (non-integer) linear programming problem using the Simplex Algorithm
%
%     [z, res] = cv.solveLP(Func, Constr)
%     [...] = cv.solveLP(..., 'OptionName', optionValue, ...)
%
% ## Input
% * __Func__ This row-vector corresponds to `c` in the LP problem formulation
%   (see below). It should contain 32- or 64-bit floating-point numbers. As a
%   convenience, column-vector may be also submitted, in the latter case it is
%   understood to correspond to `c'`.
% * __Constr__ m-by-n+1 matrix, whose rightmost column corresponds to `b` in
%   formulation above and the remaining to `A`. It should contain 32 or 64-bit
%   floating-point numbers.
%
% ## Output
% * __z__ The solution will be returned here as a column-vector, it
%   corresponds to `x` in the formulation above. It will contain 64-bit
%   floating-point numbers.
% * __res__ Return code. One of:
%   * __Unbounded__ problem is unbounded (target function can achieve
%     arbitrary high values)
%   * __Unfeasible__ problem is unfeasible (there are no points that satisfy
%     all the constraints imposed)
%   * __Single__ there is only one maximum for target function
%   * __Multi__ there are multiple maxima for target function, the arbitrary
%     one is returned
%
% What we mean here by "linear programming problem" (or LP problem, for short)
% can be formulated as:
%
%     Maximize c*x
%       subject to  A*x <= b
%                   x >= 0
%
% Where `c` is fixed 1-by-n row-vector, `A` is fixed m-by-n matrix, `b` is
% fixed m-by-1 column vector and `x` is an arbitrary n-by-1 column vector,
% which satisfies the constraints.
%
% Simplex algorithm is one of many algorithms that are designed to handle this
% sort of problems efficiently. Although it is not optimal in theoretical
% sense (there exist algorithms that can solve any problem written as above in
% polynomial type, while simplex method degenerates to exponential time for
% some special cases), it is well-studied, easy to implement and is shown to
% work well for real-life purposes.
%
% The particular implementation is taken almost verbatim from:
%
% > Introduction to Algorithms, 3rd edition
% > by T. H. Cormen, C. E. Leiserson, R. L. Rivest and Clifford Stein.
%
% In particular, the [Bland's rule](https://en.wikipedia.org/wiki/Bland%27s_rule)
% is used to prevent cycling.
%
% See also: linprog
%


% IM = mkR(SIZE, EXPT, ORIGIN)
%
% Compute a matrix of dimension SIZE (a [Y X] 2-vector, or a scalar)
% containing samples of a radial ramp function, raised to power EXPT
% (default = 1), with given ORIGIN (default = (size+1)/2, [1 1] =
% upper left).  All but the first argument are optional.

% Eero Simoncelli, 6/96.

function [res] = mkR(sz, expt, origin)

sz = sz(:);
if (size(sz,1) == 1)
  sz = [sz,sz];
end

% -----------------------------------------------------------------
% OPTIONAL args:

if (exist('expt') ~= 1)
  expt = 1;
end

if (exist('origin') ~= 1)
  origin = (sz+1)/2;
end

% -----------------------------------------------------------------

[xramp,yramp] = meshgrid( [1:sz(2)]-origin(2), [1:sz(1)]-origin(1) );

res = (xramp.^2 + yramp.^2).^(expt/2);


function value = zeta ( p )

%*****************************************************************************80
%
%% ZETA estimates the Riemann Zeta function.
%
%  Discussion:
%
%    For 1 < P, the Riemann Zeta function is defined as:
%
%      ZETA ( P ) = Sum ( 1 <= N < Infinity ) 1 / N**P
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 September 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Daniel Zwillinger, editor,
%    CRC Standard Mathematical Tables and Formulae,
%    30th Edition,
%    CRC Press, 1996.
%
%  Parameters:
%
%    Input, real P, the power to which the integers are raised.
%    P must be greater than 1.  For integral P up to 20, a
%    precomputed value of ZETA is returned; otherwise the infinite
%    sum is approximated.
%
%    Output, real VALUE, an approximation to the Riemann
%    Zeta function.
%
  if ( p <= 1.0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'ZETA - Fatal error!\n' );
    fprintf ( 1, '  Exponent P <= 1.0.\n' );
    error ( 'ZETA - Fatal error!' );
  elseif ( p == 2.0 )
    value = pi^2 / 6.0;
  elseif ( p == 3.0 )
    value = 1.2020569032;
  elseif ( p == 4.0 )
    value = pi^4 / 90.0;
  elseif ( p == 5.0 )
    value = 1.0369277551;
  elseif ( p == 6.0 )
    value = pi^6 / 945.0;
  elseif ( p == 7.0 )
    value = 1.0083492774;
  elseif ( p == 8.0 )
    value = pi^8 / 9450.0;
  elseif ( p == 9.0 )
    value = 1.0020083928;
  elseif ( p == 10.0 )
    value = pi^10 / 93555.0;
  elseif ( p == 11.0 )
    value = 1.0004941886;
  elseif ( p == 12.0 )
    value = 1.0002460866;
  elseif ( p == 13.0 )
    value = 1.0001227133;
  elseif ( p == 14.0 )
    value = 1.0000612482;
  elseif ( p == 15.0 )
    value = 1.0000305882;
  elseif ( p == 16.0 )
    value = 1.0000152823;
  elseif ( p == 17.0 )
    value = 1.0000076372;
  elseif ( p == 18.0 )
    value = 1.0000038173;
  elseif ( p == 19.0 )
    value = 1.0000019082;
  elseif ( p == 20.0 )
    value = 1.0000009540;
  else

    zsum = 0.0;
    n = 0;

    while ( 1 )

      n = n + 1;
      zsum_old = zsum;
      zsum = zsum + 1.0 / n^p;

      if ( zsum <= zsum_old )
        break
      end

    end

    value = zsum;

  end

  return
end


function [theta] = normalEqn(X, y)
%NORMALEQN Computes the closed-form solution to linear regression
%   NORMALEQN(X,y) computes the closed-form solution to linear
%   regression using the normal equations.

theta = zeros(size(X, 2), 1);

% ====================== YOUR CODE HERE ======================
% Instructions: Complete the code to compute the closed form solution
%               to linear regression and put the result in theta.
%

% ---------------------- Sample Solution ----------------------

theta = pinv(X' * X) * X' * y;

% -------------------------------------------------------------

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

end


function Z = projectData(X, U, K)
%PROJECTDATA Computes the reduced data representation when projecting only
%on to the top k eigenvectors
%   Z = projectData(X, U, K) computes the projection of
%   the normalized inputs X into the reduced dimensional space spanned by
%   the first K columns of U. It returns the projected examples in Z.
%

% You need to return the following variables correctly.
Z = zeros(size(X, 1), K);

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the projection of the data using only the top K
%               eigenvectors in U (first K columns).
%               For the i-th example X(i,:), the projection on to the k-th
%               eigenvector is given as follows:
%                    x = X(i, :)';
%                    projection_k = x' * U(:, k);
%

for i = 1:size(X, 1)
    x = X(i, :)';
    Z(i, :) = x' * U(:, 1:K);
end

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

end


function h=hermfun(t,j)
%HERMFUN  Orthonormal Hermite functions. [with F. Rekibi]
%
%   H=HERMFUN(T,N) generates the fisrt N+1 orthonormal Hermite functions
%   [H0,...HN] on a time axis specfied by the column vector T.
%
%   HERMFUN uses the expression of Simons et al. 2003.
%
%   Note that H(:,1) is the zeroth-order Hermite function, which is equal
%   to a Gaussian.  H(:,2) is the first-order function, and so forth.
%
%   See also HERMPOLY.
%
%   'hermfun --f' generates a sample figure; compare with the Hermite
%   function figure at
%
%     http://en.wikipedia.org/wiki/Hermite_polynomials#Definition
%
%   Usage:  h=hermfun(t,n);
%   _________________________________________________________________
%   This is part of JLAB --- type 'help jlab' for more information
%   (C) 2004--2015 F. Rekibi and J. M. Lilly
%                         --- type 'help jlab_license' for details

% 05.08.07  JML fixed bug to include N+1 columns

%   'hermfun --f' generates a sample figure; compare with Figure 2
%   of Simons, van der Hilst, and Zuber (2003), JGR 108 B5.

if strcmpi(t,'--f')
  type makefigs_hermfun
  makefigs_hermfun;
  return
end

if size(t,1)==1
    t=t';
end

H=hermpoly(t,j);

E=exp(-t.^2/2)*ones(1,j+1);
HE=H.*E;

h=zeros(length(t),j);
for k=1:j+1
	h(:,k)=HE(:,k)*frac(1,pi^(1/4))*frac(1,sqrt(2^(k-1)*factorial(k-1)));
end


function intVal=ellipIntInc1Kind(phi,m)
%%ELLIPINTINC1KIND Evaluate Legendre's incomplete elliptical integral of
%                  the first kind. This is the integral from 0 to phi of
%                  (1-m*sin(theta)^2)^(-1/2) dtheta. Alternatively, this
%                  can be written as the integral from 0 to x of
%                  ((1-t^2)*(1-m*t^2))^(-1/2) dt where x=sin(phi). This
%                  integral is sometimes referred to as F.
%
%INPUTS: phi A scalar or matrix of the real upper bounds of integration.
%            These can be positive, negative or zero.
%          m A value between 0 and 1. The integral diverges when m=1 and
%            phi=pi/2.
%
%OUTPUTS: intVal The values of the incomplete elliptic integral of the
%                first kind evaluated at each entry in phi.
%
%The expression used to implement the function comes from [1], whereby
%negative values are handled by switching the sign of the result. The above
%algorithm also only considers values with magnitudes up to pi/2. To get
%the correct result, however, for larger values, the value up to pi/2
%(times the number of multiples of the value up to pi/2) is added to a
%fractional part with magnitude less than pi/2. Note however, that due to
%the odd symmetry of sin(x)^2, if the integer part is odd, then the
%computation subtracts the fractional part from pi/2 and the value added is
%the value of the complete integral MINUS the modified fractional part.
%
%REFERENCES:
%[1] B. C. Carlson, "Numerical computation of real or complex elliptic
%    integrals," Numerical Algorithms, vol. 10, no. 1, pp. 13-26, 1995.
%
%September 2014 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

numItems=length(phi(:));
intVal=zeros(size(phi));

for curItem=1:numItems
    phiCur=phi(curItem);

    phiSign=sign(phiCur);
    phiCur=abs(phiCur);

    %Separate out the multiples of pi/2 from the rest of the values.
    intPart=fix(phiCur/(pi/2));
    if(intPart>0)
        completeVal=symIntFirstKind(0,1-m,1);
        phiCur=phiCur-intPart*(pi/2);
    else
        completeVal=0;
    end

    %The test deals with precision limitations that would prevent the other
    %integral from converging.
    if(phiCur<eps)
        intVal(curItem)=phiSign*intPart*completeVal;
    else
        %Deal with the odd symmetry of sin(theta)^2
        if(mod(intPart,2)==0)
            c=csc(phiCur)^2;
            delta=symIntFirstKind(c-1,c-m,c);

            intVal(curItem)=phiSign*(intPart*completeVal+delta);
        else
            phiCur=pi/2-phiCur;

            c=csc(phiCur)^2;
            delta=symIntFirstKind(c-1,c-m,c);

            intVal(curItem)=phiSign*(intPart*completeVal+(completeVal-delta));
        end
    end
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 An = slnorm(A, p, d)
%SLNORM Compute the Lp-norms
%
% $ Syntax $
%   - An = slnorm(A)
%   - An = slnorm(A, p)
%   - An = slnorm(A, [], d)
%   - An = slnorm(A, p, d)
%
% $ Arguments $
%   - A:        the input array
%   - p:        the order of the norm (default = 2)
%   - d:        the dimension of subarrays (default = 1, column vectors)
%   - An:       the resultant array
%
% $ Description $
%   - An = slnorm(A) computes the L2 norm of column vectors of A. If A is
%     an array of size d1 x d2 x ... dn, then An would be of size
%     1 x d2 x ... dn. Each value of An is the L2 norm of corresponding
%     column vector.
%
%   - An = slnorm(A, p) computes the Lp norm of column vectors of A. If A
%     is an array of size d1 x d2 x ... dn, then An would be of size
%     1 x d2 x ... dn. Each value of An is the Lp norm of corresponding
%     column vector.
%
%   - An = slnorm(A, [], d) computes the L2 norm of sub-arrays along the
%     dimensions specified by d. For example, if A is a d1 x d2 x ... dn
%     array, and d = [1, 2], then An would be an array of size
%     1 x 1 x d3 x ... x dn. Each value of An is the square root of square-
%     sum of values in corresponding plane.
%
%   - An = slnorm(A, p, d) computes the Lp norm of sub-arrays along the
%     dimensions specified by d.
%
% $ Remarks $
%   # Lp norm is the pth order-root of the sum of p-th power of all values
%     in a subspace.
%   # p can be inf or -inf. If p = inf, then the Lp norm is simply the
%     maximum magnitude value; while if p = -inf, then the Lp norm is the
%     minimum magnitude value.
%
% $ History $
%   - Created by Dahua Lin on Nov 19th, 2005
%

%% parse and verify input arguments
if nargin < 2 || isempty(p)
    p = 2;
end
if nargin < 3 || isempty(d)
    d = 1;
end
if ~isscalar(p)
    error('sltoolbox:notscalar', 'p should be a scalar');
end
if p == 0
    error('sltoolbox:zeroerr', 'p should not be zero');
end

%% compute
An = abs(A);
if p == 1
    An = slsum(An, d);
elseif p == 2
    An = sqrt(slsum(An .* An ,d));
elseif p == inf
    An = slmax(An, d);
elseif p == (-inf)
    An = slmin(An, d);
else
    An = slsum(An.^p, d) .^ (1/p);
end


function area = annulus_area_2d ( r1, r2 )

%*****************************************************************************80
%
%% ANNULUS_AREA_2D computes the area of a circular annulus in 2D.
%
%  Discussion:
%
%    A circular annulus with center (XC,YC), inner radius R1 and
%    outer radius R2, is the set of points (X,Y) so that
%
%      R1**2 <= (X-XC)**2 + (Y-YC)**2 <= R2**2
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 August 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real R1, R2, the inner and outer radii of the annulus.
%
%    Output, real AREA, the area of the annulus.
%
  area = pi * ( r2 + r1 ) * ( r2 - r1 );

  return
end


function [ x, w ] = nco_nested_rule ( n )

%*****************************************************************************80
%
%% NCO_NESTED_RULE computes the nested Newton Cotes Open rule.
%
%  Discussion:
%
%    Nested version of Newton Cotes Open rule on [-1,+1].
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    03 February 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of the rule.
%
%    Output, real X(N), W(N), the points and weights.
%

%
%  Get N equally spaced points that do not include [ 0, 1];
%
  x = vdc_sequence ( n );
%
%  Linear transformation from [0,1] to [-1,+1].
%
  x = 2.0 * x - 1.0;
%
%  Compute the weights.
%
  x_min = -1.0;
  x_max = +1.0;

  w = nc_compute ( n, x_min, x_max, x );

  return
end


function trans = createRotationOz(varargin)
%CREATEROTATIONOZ Create the 4x4 matrix of a 3D rotation around z-axis.
%
%   TRANS = createRotationOz(THETA);
%   Returns the transform matrix corresponding to a rotation by the angle
%   THETA (in radians) around the Oz axis. A rotation by an angle of PI/2
%   would transform the vector [1 0 0] into the vector [0 1 0].
%
%   The returned matrix has the form:
%   [cos(THETA) -sin(THETA)  0  0]
%   [sin(THETA)  cos(THETA)  0  0]
%   [    0           0       1  0]
%   [    0           0       0  1]
%
%   TRANS = createRotationOz(ORIGIN, THETA);
%   TRANS = createRotationOz(X0, Y0, Z0, THETA);
%   Also specifies origin of rotation. The result is similar as performing
%   translation(-X0, -Y0, -Z0), rotation, and translation(X0, Y0, Z0).
%
%
%   See also
%   transforms3d, transformPoint3d, createRotationOx, createRotationOy
%

% ------
% Author: David Legland
% E-mail: david.legland@inrae.fr
% Created: 2004-04-06
% Copyright 2004-2022 INRA - TPV URPOI - BIA IMASTE

% default values
dx = 0;
dy = 0;
dz = 0;
theta = 0;

% get input values
if length(varargin) == 1
    % only one argument -> rotation angle
    theta = varargin{1};

elseif length(varargin) == 2
    % origin point (as array) and angle
    var = varargin{1};
    dx = var(1);
    dy = var(2);
    dz = var(3);
    theta = varargin{2};

elseif length(varargin) == 4
    % origin (x and y) and angle
    dx = varargin{1};
    dy = varargin{2};
    dz = varargin{3};
    theta = varargin{4};
end

% compute coefs
cot = cos(theta);
sit = sin(theta);

% create transformation
trans = [...
    cot -sit 0 0;...
    sit  cot 0 0;...
    0 0 1 0;...
    0 0 0 1];

% add the translation part
t = [1 0 0 dx;0 1 0 dy;0 0 1 dz;0 0 0 1];
trans = t * trans / t;


function hits = buffon_simulate ( a, l, trial_num )

%*****************************************************************************80
%
%% BUFFON_SIMULATE simulates a Buffon needle experiment.
%
%  Discussion:
%
%    In the Buffon needle experiment, we suppose that the plane has been
%    ruled by vertical lines with a spacing of A units, and that a
%    needle of length L is dropped "at random" onto this grid.
%
%    Because of the various symmetries, we may assume that this eye of
%    this needle lands in the first infinite strip, and we may further
%    assume that its Y coordinate is 0.  Thus, we have
%    the eye as (X1,Y1) with 0 <= X1 <= A and Y1 = 0.
%
%    ANGLE, the angle that the needle makes is taken to be uniformly random.
%    The point of the needle, (X2,Y2), therefore lies at
%
%      (X2,Y2) = ( X1+L*cos(ANGLE), Y1+L*sin(ANGLE) )
%
%    The needle will have crossed at least one grid line if any of the
%    following are true:
%
%      X2 <= 0, A <= X2.
%
%    The probability of a crossing on a single trial is
%
%      P(A,L) = ( 2 * L ) / ( PI * A )
%
%    and therefore, a record of the number of hits for a given number of
%    trials can be used as a very roundabout way of estimating PI.
%
%    Note that this routine will try to generate 4 * TRIAL_NUM random
%    double precision values at one time, using automatic arrays.
%    When I tried this with TRIAL_NUM = 1,000,000, the program failed,
%    because of internal system limits on such arrays.
%
%    Such a problem could be avoided by using a DO loop running through
%    each trial individually, but this tend to run much more slowly than
%    necessary.
%
%    Since this routine invokes the FORTRAN90 random number generator,
%    the user should initialize the random number generator, particularly
%    if it is desired to control whether the sequence is to be varied
%    or repeated.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real A, the horizontal spacing between the
%    vertical grid lines.  0 <= A.
%
%    Input, real L, the length of the needle.
%
%    Input, integer TRIAL_NUM, the number of times the needle is
%    to be dropped onto the grid.
%
%    Output, integer BUFFON_SIMULATE, the number of times the needle
%    crossed at least one line of the grid of cells.
%
%  Local Parameters:
%
%    Local, integer BATCH_SIZE, specifies the number of trials to be done
%    in a single batch.  Setting BATCH_SIZE to 1 will be very slow.
%    Replacing it by TRIAL_NUM would be fine except that your system
%    may have a limit on the size of automatic arrays.  We have set a default
%    value of 10,000 here which should be large enough to be efficient
%    but small enough not to annoy the system.
%
  batch_size = 10000;

  hits = 0;

  for batch = 1 : batch_size: trial_num

    n = min ( batch_size, trial_num + 1 - batch );
%
%  Randomly choose the location (X1,Y1) of the eye of the needle
%  in [0,0]x[A,0], and the angle the needle makes.
%
    x1(1:n) = a * rand ( 1, n );
    angle(1:n) = 2.0D+00 * pi * rand ( 1, n );
%
%  Compute the location of the point of the needle.
%  We only need to know the value of X2, not Y2!
%
    x2(1:n) = x1(1:n) + l * cos ( angle(1:n) );
%
%  Count the end locations that lie outside the cell.
%
    hits = hits + length ( find ( x2(1:n) <= 0.0 | a <= x2(1:n) ) );

  end

  return
end


function trans = createRotationOx(varargin)
%CREATEROTATIONOX Create the 4x4 matrix of a 3D rotation around x-axis.
%
%   TRANS = createRotationOx(THETA);
%   Returns the transform matrix corresponding to a rotation by the angle
%   THETA (in radians) around the Ox axis. A rotation by an angle of PI/2
%   would transform the vector [0 1 0] into the vector [0 0 1].
%
%   The returned matrix has the form:
%   [1      0            0      0]
%   [0  cos(THETA) -sin(THETA)  0]
%   [0  sin(THETA)  cos(THETA)  0]
%   [0      0            0      1]
%
%   TRANS = createRotationOx(ORIGIN, THETA);
%   TRANS = createRotationOx(X0, Y0, Z0, THETA);
%   Also specifies origin of rotation. The result is similar as performing
%   translation(-X0, -Y0, -Z0), rotation, and translation(X0, Y0, Z0).
%
%   See also
%   transforms3d, transformPoint3d, createRotationOy, createRotationOz
%

% ------
% Author: David Legland
% E-mail: david.legland@inrae.fr
% Created: 2005-02-18
% Copyright 2005-2022 INRA - TPV URPOI - BIA IMASTE

% default values
dx = 0;
dy = 0;
dz = 0;
theta = 0;

% get input values
if length(varargin) == 1
    % only one argument -> rotation angle
    theta = varargin{1};

elseif length(varargin) == 2
    % origin point (as array) and angle
    var = varargin{1};
    dx = var(1);
    dy = var(2);
    dz = var(3);
    theta = varargin{2};

elseif length(varargin) == 4
    % origin (x and y) and angle
    dx = varargin{1};
    dy = varargin{2};
    dz = varargin{3};
    theta = varargin{4};
end

% compute coefs
cot = cos(theta);
sit = sin(theta);

% create transformation
trans = [...
    1 0 0 0;...
    0 cot -sit 0;...
    0 sit cot 0;...
    0 0 0 1];

% add the translation part
t = [1 0 0 dx;0 1 0 dy;0 0 1 dz;0 0 0 1];
trans = t * trans / t;


function y=polyValGen(p,x,direction)
%%POLYVALGEN Return the value of a scalar polynomial evaluated at the point
%       or points given in x. The polynomial can be specified in the format
%       y=p(1)*x^N+p(2)*x^(N-1)+...+p(N)*x+p(N+1)
%       or in the format
%       y=p(N+1)*x^N+p(N)*x^(N-1)+...+p(2)*x+p(1)
%       as specified by the direction option. This function is similar to
%       polyval, but allows one to choose between the formats without
%       calling flip to reverse the order of the elements in p.
%
%INPUTS: p An NX1 or 1XN set of real or complex polynomial coefficients;
%          wN>=1.
%        x A real or complex scalar point or a matrix of points at which
%          the scalar polynomial should be evaluated.
% direction An optional parameter specifying which of the two polynomial
%          formats is used. Possible values are:
%          0 (The default if omitted or an empty matrix is passed) p(1) is
%            the coefficient of the highest order x term.
%          1 p(1) is the coefficient of the lowest order x term.
%
%OUTPUTS: y The value or values of the polynomial in p evaluated at the
%           point(s) in x. This is the same size as x, unless x is an empty
%           matrix, in which case y is 0.
%
%The function is evaluated using Horner's rule, which is described in [1].
%
%REFERENCES:
%[1] Weisstein, Eric W. "Horner's Rule." From MathWorld--A Wolfram Web
%    Resource. http://mathworld.wolfram.com/HornersRule.html
%
%July 2017 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

if(nargin<3||isempty(direction))
   direction=0;
end

numP=length(p);

y=zeros(size(x));
if(direction==0)
    if(numP>0)
        y(:)=p(1);
    end

    for k=2:numP
        y=x.*y+p(k);
    end
else
    if(numP>0)
        y(:)=p(numP);
    end

    for k=(numP-1):-1:1
        y=x.*y+p(k);
    end
end
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 [ p ] = ml_explained_variance( L, Var )
%EXPLAINED_VARIANCE Function that returns the optimal p given a desired
%   explained variance. The student should convert the Eigenvalue matrix
%   to a vector and visualize the values as a 2D plot.
%   input -----------------------------------------------------------------
%
%       o L      : (N x N), Diagonal Matrix composed of lambda_i
%
%   output ----------------------------------------------------------------
%
%       o p      : optimal principal components wrt. explained variance

% ====================== Implement Eq. 8 Here ======================
eigs = diag(L);
expl_var = eigs./sum(eigs);

% ====================== Implement Eq. 9 Here ======================
cum_expl_var = cumsum(expl_var);

% ====================== Implement Eq. 10 Here ======================
p = sum(cum_expl_var <= Var) + 1;

% Visualize Explained Variance from Eigenvalues
figure;
plot(cum_expl_var, '--r', 'LineWidth', 2) ; hold on;
plot(p,cum_expl_var(p),'or')
title('Explained Variance from EigenValues')
set(gca,'XTick',[1:1:length(eigs)])
ylabel('% Cumulative Variance Explained')
xlabel('Eigenvector index')
grid on

end


function [Zpca, U, mu, eigVecs] = PCA(Z,r)
%
% Syntax:       Zpca = PCA(Z,r);
%               [Zpca, U, mu] = PCA(Z,r);
%               [Zpca, U, mu, eigVecs] = PCA(Z,r);
%
% Inputs:       Z is an d x n matrix containing n samples of d-dimensional
%               data
%
%               r is the number of principal components to compute
%
% Outputs:      Zpca is an r x n matrix containing the r principal
%               components - scaled to variance 1 - of the input samples
%
%               U is a d x r matrix of coefficients such that
%               Zr = U * Zpca + repmat(mu,1,n);
%               is the r-dimensional PCA approximation of Z
%
%               mu is the d x 1 sample mean of Z
%
%               eigVecs is a d x r matrix containing the scaled
%               eigenvectors of the sample covariance of Z
%
% Description:  Performs principal component analysis (PCA) on the input
%               data
%
% Author:       Brian Moore
%               brimoor@umich.edu
%
% Date:         April 26, 2015
%               November 7, 2016
%

% Center data
[Zc, mu] = centerRows(Z);

% Compute truncated SVD
%[U, S, V] = svds(Zc,r); % Equivalent, but usually slower than svd()
[U, S, V] = svd(Zc,'econ');
U = U(:,1:r);
S = S(1:r,1:r);
V = V(:,1:r);

% Compute principal components
Zpca = S * V';
%Zpca = U' * Zc; % Equivalent but slower

if nargout >= 4
    % Scaled eigenvectors
    eigVecs = bsxfun(@times,U,diag(S)' / sqrt(size(Z,2)));
end


%% Systems of linear equations
% At its heart, the subject of linear algebra is concerned with how to
% solve the seemingly simple equation:
%
% $${\bf{A}}x=b$,
% where $${\bf{A}}$ is a matrix and $$x$ and $$b$ are vectors.
%%
%
% This might seem surprising, but this problem is right at the heart of
% almost all problems in scientific computing, from differential equations
% to eigenvalue problems to interpolation and curve fitting.

%%
% Of course, for a single scalar variable, x, we know what that means:
% $$ a\times x = y$
% from which we can deduce that
% $$ x = y/a$, for non-zero $$a$.
%%
% The question is how do we solve such a problem when we have more than one
% unknown variable, or, equivalently, when x is a vector? To investigate this
% question, let's consider the following electrical circuit:
%
[c,m]=imread('circuit2.gif','gif');

figure('color',[1 1 1]),
image(c), colormap(m), axis equal, axis off

%%
% We want to calculate the currents $$I_1,I_2,I_3$
%%
% Using Kirchoff's voltage laws we get the following three equations for
% the three unknown currents:
%%
% <latex>
% $\left\{\begin{array}{ccc}
% I_1 + 25(I_1-I_2)+50(I_1-I_3) & = & 10 \\
% 25(I_2-I_1) + 30I_2 + I_2 -I_3 & = & 0 \\
% 50(I_3-I_1)+I_3-I_2+55I_3 & = & 0 \end{array}\right . $
% </latex>
%%
% which, with a little re-arranging becomes:
%%
% <latex>
% $\left\{\begin{array}{ccc}
% 76I_1 - 25I_2-50I_3 & = & 10 \\
% -25I_1 +56I_2 -I_3 & = & 0 \\
% -50I_1-I_2+106I_3 & = & 0 \end{array}\right .$
% </latex>
%%
% Finally, we can gather all the coefficients into a matrix, and the
% unknowns into a vector, to write the single matrix linear equation:
%%
% <latex>
% $\left( {\begin{array}{ccc}
% 76 & -25 & -50 \\
% -25 & 56 & -1  \\
% -50& -1 & 106 \end{array}} \right)
% \times \left(\begin{array}{c}
% I_1\\
% I_2\\
% I_3 \end{array}\right) = \left( \begin{array}{c}
% 10 \\
% 0\\
% 0 \end{array}\right)$
% </latex>
%%
% In this way we have got the system of equations into the form that we
% described above, namely:
% $${\bf{A}}x=b$
%%
% Of course, for a small system (3 by 3 in this case) we can solve this by
% hand. For a larger system, however, we need a computer. The basic
% approach to solving such a system is an extension of that used by hand,
% namely we add and subtract multiples of one row to one another until we
% finally end up with an upper triangular matrix. This action
% of adding and subtrating multiples of one row to another is known as a
% basic row operation. Let us illustrate the process with MATLAB. Before we
% begin, we augment the right hand side vector to be an extra column in our
% matrix $$\bf A$, so it is now three rows by four columns.
A=[76 -25 -50 10;-25 56 -1 0; -50 -1 106 0]
rrefexample(A)
%%
% What is the advantage of reducing $${\bf A}$ to be upper triangular?
% Starting from the last row, we see that we now have an equation that
% depends only on $$I_3$, that is $$I_3 = 0.117$. The row above depends on
% $$I_3$ and $$I_2$ only, and we now know what $$I_3$ is! In this way, we
% work our way up through the rows substituting as we go, and in each row
% there is only a single unknown variable. This process is called _back
% substitution_. This entire process - that of reducing the matrix to a
% triangular form and solving via back substitution - is the way most
% computer packages solve these linear systems. In MATLAB, the shorthand
% way of solving such systems is with the backslash character ``\''
A=[76 -25 -50;-25 56 -1; -50 -1 106]
b =[10;0;0]
I= A\b
%%
% In the example above, we have performed a special case of what is a more
% general idea - that of transforming a matrix into a special form, so that
% the equations can be solved more easily. In general, the idea of
% transforming a matrix through a series of elementary row operations is a
% powerful one. May special types of _matrix factorisations_ exist, and two
% of the most important examples are:
%%
% *QR decomposition *
% In this case, a general matrix is written as the product of two matrices,
% one orthogonal and one upper triangular:
% $${\bf A = QR}$
% As the inverse of an orthogonal matrix is equal to its transpose, we find
% the solution to the general system $${\bf A}x=b$ can be calculated as:
%%
% <latex>
% $\begin{array}{l}
% {\bf A}x = b \\
% {\bf QR}x = b \\
% {\bf Q}({\bf R}x)=b \\
% {\bf R}x = {\bf Q^T} \times b \\
% x = {\bf R}\setminus{\bf Q^T} \times b \end{array}$
% </latex>
%%
% *LU Decomposition*
% In this case the matrix is decomposed into two, a lower and an upper
% triangular matrix. As both the matrices are triangular, the back (and
% forward) substitution process is very quick:
%%
% <latex>
% $\begin{array}{l}
% {\bf A}x = b \\
% {\bf LU}x = b \\
% {\bf U}({\bf L}x)=b \\
% {\bf U}x = {\bf L}\setminus b \\
% x = {\bf U}\setminus({\bf L}\setminus b) \end{array}$
% </latex>

%   Copyright 2008-2009 The MathWorks, Inc.
%   $Revision: 35 $  $Date: 2009-05-29 15:27:34 +0100 (Fri, 29 May 2009) $