%% Histogram Comparison
%
% In this demo, we show how to:
%
% * Use the function |cv.compareHist| to get a numerical parameter that
%   express how well two histograms match with each other
% * Use different metrics to compare histograms
%
% Sources:
%
% * <https://docs.opencv.org/3.2.0/d8/dc8/tutorial_histogram_comparison.html>
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp>
%

%% Theory
%
% To compare two histograms ($H_{1}$ and $H_{2}$), first we have to choose a
% _metric_ ($d(H_{1}, H_{2})$) to express how well both histograms match.
%
% OpenCV implements the function |cv.compareHist| to perform a comparison. It
% also offers 4 different metrics to compute the matching:
%
% * *Correlation*:
%
% $$d(H_1,H_2) =  \frac{\sum_I (H_1(I) - \bar{H_1}) (H_2(I) - \bar{H_2})}
%                      {\sqrt{\sum_I(H_1(I) - \bar{H_1})^2
%                             \sum_I(H_2(I) - \bar{H_2})^2}}$$
%
% where
%
% $$\bar{H_k} =  \frac{1}{N} \sum _J H_k(J)$$
%
% and $N$ is the total number of histogram bins.
%
% * *Chi-Square*:
%
% $$d(H_1,H_2) =  \sum _I  \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)}$$
%
% * *Intersection*:
%
% $$d(H_1,H_2) =  \sum _I  \min (H_1(I), H_2(I))$$
%
% * *Bhattacharyya*:
%
% $$d(H_1,H_2) =  \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}}
%                           \sum_I \sqrt{H_1(I) \cdot H_2(I)}}$$
%

%% Code
%
% This program:
%
% * Loads a _base image_ and 2 _test images_ to be compared with it.
% * Generate 1 image that is the lower half of the _base image_
% * Convert the images to HSV format
% * Calculate the H-S histogram for all the images and normalize them in order
%   to compare them.
% * Compare the histogram of the _base image_ with respect to the 2 test
%   histograms, the histogram of the lower half base image and with the same
%   base image histogram.
% * Display the numerical matching parameters obtained.
%

%%
% Load source images (base image and the two other images to compare)
im = {
    'https://docs.opencv.org/3.3.1/Histogram_Comparison_Source_0.jpg'
    'https://docs.opencv.org/3.3.1/Histogram_Comparison_Source_1.jpg'
    'https://docs.opencv.org/3.3.1/Histogram_Comparison_Source_2.jpg'
};
src = cell(3,1);
for i=1:3
    [~,name,ext] = fileparts(im{i});
    fname = fullfile(mexopencv.root(), 'test', [name ext]);
    if exist(fname, 'file') ~= 2
        disp('Downloading image...')
        urlwrite(im{i}, fname);
    end
    src{i} = cv.imread(fname, 'Color',true);
end

%%
% also create an image of half the base image
src{4} = src{1}(end/2:end,:,:);
src = src([1 4 2 3]);

%%
% show images
names = {'Base', 'Half', 'Test1', 'Test2'};
for i=1:numel(src)
    subplot(2,2,i), imshow(src{i}), title(names{i})
end

%%
% convert images to HSV color space
hsv = cell(size(src));
for i=1:numel(src)
    hsv{i} = cv.cvtColor(src{i}, 'RGB2HSV');
end

%%
% calculate H-S 2D histograms
%ranges = {linspace(0,180,50+1), linspace(0,256,60+1)};
ranges = {[0 180], [0 256]};
hsizes = [50, 60];
histo = cell(size(hsv));
for i=1:numel(hsv)
    histo{i} = cv.calcHist(hsv{i}(:,:,1:2), ranges, 'HistSize',hsizes, 'Uniform',true);
    histo{i} = cv.normalize(histo{i}, 'NormType','MinMax', 'Alpha',0, 'Beta',1);
end

%%
% compare histogram of the base image against the other histograms
% using four different metrics
algs = {'Correlation', 'ChiSquare', 'Intersection', 'Bhattacharyya'};
D = zeros(numel(algs),numel(histo));
for j=1:numel(histo)
    for i=1:numel(algs)
        D(i,j) = cv.compareHist(histo{1}, histo{j}, 'Method',algs{i});
    end
end

%%
% The first image is the base (to be compared to the others), the other 2 are
% the test images. We also compare the first image with respect to itself and
% with respect of half the base image.
%
% We should expect a perfect match when we compare the base image histogram
% with itself. Also, compared with the histogram of half the base image, it
% should present a high match since both are from the same source. For the
% other two test images, we can observe that they have very different lighting
% conditions, so the matching should not be very good.
%

%%
% Here are the numeric results
if ~mexopencv.isOctave()
    t = array2table(D, 'VariableNames',names, 'RowNames',algs);
    disp(t);
else
    %HACK: use cell array instead of table
    t = [{''}, names; algs(:), arrayfun(@num2str,D,'UniformOutput',false)];
    t = t';
    fprintf('%13s %9s %9s %9s %9s\n',t{:});
end

%%
% For the _Correlation_ and _Intersection_ methods, the higher the metric, the
% more accurate the match. As we can see, the match _base-base_ is the highest
% of all as expected. Also we can observe that the match _base-half_ is the
% second best match (as we predicted). For the other two metrics, the less the
% result, the better the match. We can observe that the matches between the
% test 1 and test 2 with respect to the base are worse, which again, was
% expected.
%


function value = legendre_determinant ( n )

%*****************************************************************************80
%
%% LEGENDRE_DETERMINANT returns the determinant of the LEGENDRE matrix.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 February 2015
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of A.
%
%    Output, real VALUE, the determinant.
%
  value = 1.0;
  t = 1.0;

  for i = 3 : n
    t = t * ( 2 * i - 3 ) / (  i - 1 );
    value = value * t;
  end

  return
end


%% Basic Data Structure representing a Mesh
%
%% Data structure: node and elem
%
% Two matrices |node(1:N,1:d)| and |elem(1:NT,1:d+1)| are used to represent
% a d-dimensional triangulation embedded in $\mathbf R^d$, where |N| is the number
% of vertices and |NT| is the number of elements.
%
% |node(k,1)| and |node(k,2)| are the x- and y-coordinates of the k-th node
% for points in 2-D. In 3-D, |node(k,3)| gives the additional z-coordinates
% of the k-th node.
%
% |elem(t,1:3)| are indices of 3 vertices of triangle t. |elem(t,1:4)| are
% indices of 4 vertices of tetrahedron t. By convention, the vertices are
% ordered such that the signed area/volume is positive. Therefore in 2-D,
% three vertices of a triangle is ordered counterclockwise and in 3-D, the
% four vertices of a tetrahedron follows the right-hand rule.

clear all; close all;
%% Example: L-shape domain in 2-D
node = [1,0; 1,1; 0,1; -1,1; -1,0; -1,-1; 0,-1; 0,0];  % coordinates
elem = [1,2,8; 3,8,2; 8,3,5; 4,5,3; 7,8,6; 5,6,8];     % connectivity
showmesh(node,elem)
axis on
findnode(node)       % plot indices of all vertices
findelem(node,elem)  % plot indices of all triangles
%%
% Apply uniform refinement three times to obtain a fine mesh.
for i = 1:3
    [node,elem] = uniformrefine(node,elem);
end
showmesh(node,elem)

%% Example: Cube in 3-D
node = [-1,-1,-1; 1,-1,-1; 1,1,-1; -1,1,-1; -1,-1,1; 1,-1,1; 1,1,1; -1,1,1];
elem = [1,2,3,7; 1,6,2,7; 1,5,6,7; 1,8,5,7; 1,4,8,7; 1,3,4,7];
clf; showmesh3(node,elem,[],'FaceAlpha',0.25);
view([-53,8]);
axis on
findnode3(node)
findelem3(node,elem)
%%
% Apply uniform refinement twice to obtain a fine mesh.
for i = 1:2
    [node,elem] = uniformrefine3(node,elem);
end
showmesh3(node,elem,[],'FaceAlpha',0.25); view([-24 10]);

%% Example: Sphere in 3-D
% a simple triangular mesh in the space
node = [1,0,0; 0,1,0; -1,0,0; 0,-1,0; 0,0,1; 0,0,-1];
elem = [6,1,2; 6,2,3; 6,3,4; 6,4,1; 5,1,4; 5,3,4; 5,3,2; 5,2,1];
showmesh(node,elem,'FaceAlpha',0.5);
axis on;
findnode3(node);
%%
% uniformly refined mesh
for i = 1:3
    [node,elem] = uniformrefine(node,elem);
end
showmesh(node,elem)
%%
% project vertices onto the unit sphere
r = sqrt(node(:,1).^2 + node(:,2).^2 + node(:,3).^2);
node = node./[r r r];
showmesh(node,elem)

%% Order of vertices: orientation
% Any permutation of vertices of an element will represent the same
% abstract simplex. By convention, the vertices of a simplex is ordered
% such that the signed volume is positive. Therefore in 2-D, three vertices
% of a triangle is ordered counterclockwise and in 3-D, the ordering of
% vertices follows the right-hand rule. The function |fixorientation| will
% compute the signed area or volume and permute vertices if necessary.

node = [1,0; 1,1; 0,1];
elem = [1 3 2];
figure(4);
subplot(1,2,1)
showmesh(node,elem)
findnode(node,elem)
display('Clockwise'); display(elem)
elem = fixorientation(node,elem);
display('Counter-Clockwise'); display(elem)

%% Order of vertices: longest edge
% An even permutation of vertices is still allowed to represent the same
% simplex with the same orientation.
%
% * The function |label| will permute the vertices such that |elem(t,2:3)|
% is the longest edge of |t|.
% * The function |label3| will permute the vertices such that |elem(t,1:2)|
% is the longest edge of |t|.
%
% These functions are important for bisection methods of triangulations.

node = [1,0; 1,1; 0,1];
elem = [1 2 3];
subplot(1,2,1)
showmesh(node,elem)
findnode(node,elem)
display('Before labeling'); display(elem)
elem = label(node,elem);
display('After labeling'); display(elem)
display('elem(t,2:3) is the longest edge')

%%
node = [-1,-1,-1; 1,-1,-1; 1,1,-1; -1,1,-1; -1,-1,1; 1,-1,1; 1,1,1; -1,1,1];
elem = [1,2,3,7; 1,6,2,7; 1,5,6,7];
figure(2)
showmesh3(node,elem,[],'FaceAlpha',0.25); view([-53,8]);
findnode3(node,[1 2 3 5 6 7]);
findelem3(node,elem);
display('Before labeling'); display(elem)
elem = label3(node,elem);
display('After labeling'); display(elem)
display('elem(t,1:2)=[1 7] is the longest edge')


function [cov_ewma,corr_ewma,vola_ewma] = ewma_covariance(data,lambda)

% calculates the RiskMetrics "Technical Document" (1996) exponentially
% weighted covariance matrix (p.179), correlation and volatilities.
%
% Input:
% data - needs to be in format T x k with T = # observations, k = # assets
% lambda = decay factor

[r,c]         = size(data);
data_mwb      = data-repmat(mean(data,1),r,1);
lambdavec     = lambda.^(0:1:r-1)';
data_tilde    = repmat(sqrt(lambdavec),1,c).*data_mwb;

cov_ewma      = 1/sum(lambdavec)*(data_tilde'*data_tilde);
corr_ewma     = zeros(c);
vola_ewma     = zeros(c,1);

for i = 1:c
    for j = 1:c
        corr_ewma(i,j) = cov_ewma(i,j)/sqrt(cov_ewma(i,i)*cov_ewma(j,j));
    end
    vola_ewma(i) = sqrt(cov_ewma(i,i));
end


function dist = line_par_point_dist_3d ( f, g, h, x0, y0, z0, p )

%*****************************************************************************80
%
%% LINE_PAR_POINT_DIST_3D: distance ( parametric line, point ) in 3D.
%
%  Discussion:
%
%    The parametric form of a line in 3D is:
%
%      X = X0 + F * T
%      Y = Y0 + G * T
%      Z = Z0 + H * T
%
%    We normalize by choosing F*F+G*G+H*H=1 and 0 <= F.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    20 February 2005
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Adrian Bowyer and John Woodwark,
%    A Programmer's Geometry,
%    Butterworths, 1983.
%
%  Parameters:
%
%    Input, real F, G, H, X0, Y0, Z0, the parametric line
%    parameters.
%
%    Input, real P(3,1), the point whose distance from the line is
%    to be measured.
%
%    Output, real DIST, the distance from the point to the line.
%
  dx =   g * ( f * ( p(2,1) - y0 ) - g * ( p(1,1) - x0 ) ) ...
       + h * ( f * ( p(3,1) - z0 ) - h * ( p(1,1) - x0 ) );

  dy =   h * ( g * ( p(3,1) - z0 ) - h * ( p(2,1) - y0 ) ) ...
       - f * ( f * ( p(2,1) - y0 ) - g * ( p(1,1) - x0 ) );

  dz = - f * ( f * ( p(3,1) - z0 ) - h * ( p(1,1) - x0 ) ) ...
       - g * ( g * ( p(3,1) - z0 ) - h * ( p(2,1) - y0 ) );

  dist = sqrt ( dx * dx + dy * dy + dz * dz ) ...
    / ( f * f + g * g + h * h );

  return
end


function [Y] = LaplacianScore(X, W)
%	Usage:
%	[Y] = LaplacianScore(X, W)
%
%	X: Rows of vectors of data points
%	W: The affinity matrix.
%	Y: Vector of (1-LaplacianScore) for each feature.
%      The features with larger y are more important.
%
%    Examples:
%
%       fea = rand(50,70);
%       options = [];
%       options.Metric = 'Cosine';
%       options.NeighborMode = 'KNN';
%       options.k = 5;
%       options.WeightMode = 'Cosine';
%       W = constructW(fea,options);
%
%       LaplacianScore = LaplacianScore(fea,W);
%       [junk, index] = sort(-LaplacianScore);
%
%       newfea = fea(:,index);
%       %the features in newfea will be sorted based on their importance.
%
%	Type "LaplacianScore" for a self-demo.
%
% See also constructW
%
%Reference:
%
%   Xiaofei He, Deng Cai and Partha Niyogi, "Laplacian Score for Feature Selection".
%   Advances in Neural Information Processing Systems 18 (NIPS 2005),
%   Vancouver, Canada, 2005.
%
%   Deng Cai, 2004/08

if nargin == 0, selfdemo; return; end

[nSmp,nFea] = size(X);

if size(W,1) ~= nSmp
    error('W is error');
end

D = full(sum(W,2));
L = W;

allone = ones(nSmp,1);

tmp1 = D'*X;

D = sparse(1:nSmp,1:nSmp,D,nSmp,nSmp);

DPrime = sum((X'*D)'.*X)-tmp1.*tmp1/sum(diag(D));
LPrime = sum((X'*L)'.*X)-tmp1.*tmp1/sum(diag(D));

DPrime(find(DPrime < 1e-12)) = 10000;

Y = LPrime./DPrime;
Y = Y';
Y = full(Y);

%---------------------------------------------------
function selfdemo
% ====== Self demo using IRIS dataset
% ====== 1. Plot IRIS data after LDA for dimension reduction to 2D
load iris.dat

feaNorm = mynorm(iris(:,1:4),2);
fea = iris(:,1:4) ./ repmat(max(1e-10,feaNorm),1,4);

options = [];
options.Metric = 'Cosine';
options.NeighborMode = 'KNN';
options.WeightMode = 'Cosine';
options.k = 3;

W = constructW(fea,options);

[LaplacianScore] = feval(mfilename,iris(:,1:4),W);
[junk, index] = sort(-LaplacianScore);

index1 = find(iris(:,5)==1);
index2 = find(iris(:,5)==2);
index3 = find(iris(:,5)==3);
figure;
plot(iris(index1, index(1)), iris(index1, index(2)), '*', ...
     iris(index2, index(1)), iris(index2, index(2)), 'o', ...
     iris(index3, index(1)), iris(index3, index(2)), 'x');
legend('Class 1', 'Class 2', 'Class 3');
title('IRIS data onto the first and second feature (Laplacian Score)');
axis equal; axis tight;

figure;
plot(iris(index1, index(3)), iris(index1, index(4)), '*', ...
     iris(index2, index(3)), iris(index2, index(4)), 'o', ...
     iris(index3, index(3)), iris(index3, index(4)), 'x');
legend('Class 1', 'Class 2', 'Class 3');
title('IRIS data onto the third and fourth feature (Laplacian Score)');
axis equal; axis tight;

disp('Laplacian Score:');
for i = 1:length(LaplacianScore)
    disp(num2str(LaplacianScore(i)));
end


function Y = spherharm(theta,phi,l,m);
% function Y = spherharm(theta,phi,l,m);

mp = abs(m);			% positive m

Y = sqrt((2*l + 1)/(4*pi) * (prod(1:(l-mp))/prod(1:(l+mp)))) * ...
    legendrex(cos(theta),mp,l) .* exp(sqrt(-1)*mp*phi);

if(m < 0),
  Y = (-1)^mp * conj(Y);
end
return


function [V,F,Q] = torus(n,m,r,varargin)
  % TORUS Construct a triangle mesh of a unit torus.
  %
  % [V,F] = torus(n,m,r)
  % [V,F] = torus(n,m,r,'ParameterName',ParameterValue, ...)
  %
  % Inputs:
  %   n  number of vertices around inner ring
  %   m  number of vertices around outer ring
  %   r  radius of the inner ring
  %   Optional:
  %     'R'  followed by outer ring radius {1}
  % Outputs:
  %   V  #V by 3 list of mesh vertex positions
  %   F  #F by 3 list of triangle mesh indices
  %
  % Example:
  %   % Roughly even shaped triangles
  %   n = 40;
  %   r = 0.4;
  %   [V,F] = torus(n,round(r*n),r);
  R = 1;
  params_to_variables = containers.Map( ...
    {'R'},{'R'});
  v = 1;
  while v <= numel(varargin)
    param_name = varargin{v};
    if isKey(params_to_variables,param_name)
      assert(v+1<=numel(varargin));
      v = v+1;
      % Trick: use feval on anonymous function to use assignin to this workspace
      feval(@()assignin('caller',params_to_variables(param_name),varargin{v}));
    else
      error('Unsupported parameter: %s',varargin{v});
    end
    v=v+1;
  end

  [V,F] = create_regular_grid(n,m,true,true);

  V = V*2*pi;
  th = V(:,2);
  phi = V(:,1);
  V = [cos(phi).*(R+r*cos(th)) sin(phi).*(R+r*cos(th)) r*sin(th)];
  Q = [F(1:2:end-1,[1 2]) F(2:2:end,[2 3])];

end


% Isoparametric Formulation Implementation
% clear memory
clear all
close all
clc
% E: modulus of elasticity
% A: area of cross section
% L: length of bar
E=8; L=4;
u_exact=@(x) (56-8*(x-2)-24*heaviside(x-5))/2/x;
hold on;
ezplot(u_exact,[2 6])
title('Exact solution v.s. FEM','interpreter','latex');
xlabel('x','interpreter','latex');
ylabel('Axial stress, $\it{\sigma}_{x}$','interpreter','latex');
for i=1:4  %For NEL = 1, 2, 4, 8
fprintf( '\nNumber of elements:%d\n\n',2^(i-1) );
% numberElements: number of elements
numberElements=2^(i-1);
% numberNodes: number of nodes
NNOD = 2;
numberNodes=numberElements+1;
% generation of coordinates and connectivities
elementNodes=[1:numberNodes-1;2:numberNodes]';
nodeCoordinates=linspace(2,L+2,numberNodes);
%Generate element length vector
Le=ones(1,numberElements)*L/numberElements;
A=(nodeCoordinates(1:end-1)+Le./2)*2;
%Evaluate area for each cross-section at the center of each element by A=2x;
% for structure:
   % displacements: displacement vector
   % force : force vector
   % stiffness: stiffness matrix
force=zeros(numberNodes,1);
stiffness=zeros(numberNodes,numberNodes);
% computation of the system stiffness matrix and force vector
for e=1:numberElements;
  % elementDof: element degrees of freedom (Dof)
  elementDof=elementNodes(e,:);
  detJacobian=Le(e)/2;
  invJacobian=1/detJacobian;
  ngp = 2;
  xc=0.5*(nodeCoordinates(elementDof(1))+nodeCoordinates(elementDof(end)));
  [w,xi]=gauss1d(ngp);
  if(nodeCoordinates(elementDof(1))==5)
     x=(5-xc)/detJacobian;
     [s,n]=shapeFunctionL2(x);
     force(elementDof)= force(elementDof)+...
         24*s';
  elseif(nodeCoordinates(elementDof(1))<5&&...
          nodeCoordinates(elementDof(end))>5)
     x=(5-xc)/detJacobian;
     [s,n]=shapeFunctionL2(x);
     force(elementDof)= force(elementDof)+...
         24*s';
  end
  for ip=1:ngp;
      [shape,naturalDerivatives]=shapeFunctionL2(xi(ip));
      B=naturalDerivatives*invJacobian;
      stiffness(elementDof,elementDof)=...
      stiffness(elementDof,elementDof)+ B'*B*w(ip)*detJacobian*E*A(e);
      force(elementDof)=force(elementDof)+...
          8*shape'*detJacobian*w(ip);
  end
end

% boundary conditions and solution
% prescribed dofs
prescribedDof=[1];
% solution
GDof=numberNodes;
displacements=solution(GDof,prescribedDof,stiffness,force);
% output displacements/reactions
outputDisplacementsReactionsPretty(displacements,stiffness, ...
    numberNodes,prescribedDof,force)
%stress/strain recover
fprintf('Axial stress\n')
fprintf('element\tgauss point\taxial stress\n')
ngp = 2;
elementNodeCoor=zeros(numberElements*NNOD,1);
elementNodeStr=zeros(numberElements*NNOD,1);
for e=1:numberElements;
  % elementDof: element degrees of freedom (Dof)
  elementDof=elementNodes(e,:) ;
  detJacobian=Le(e)/2;
  invJacobian=1/detJacobian;
  % Nodal coordiantes in natural coordinate
  xi=[-1 1];
  for ip=1:NNOD
      [shape,naturalDerivatives]=shapeFunctionL2(xi(ip));
      B=naturalDerivatives*invJacobian;
      elementNodeStr(ip+(e-1)*NNOD,1)=E*B*displacements(elementDof,1);
      fprintf('%2.0f\t%2.0fth ip\t%10.4e\n', e, ip,...
          elementNodeStr(ip+(e-1)*NNOD,1))
  end
  elementNodeCoor(1+(e-1)*ngp:2+(e-1)*ngp)=[nodeCoordinates(elementDof(1))...
      nodeCoordinates(elementDof(2))];
end

%post process
switch numberElements
    case 1
        str='r*--';
    case 2
        str='g*--';
    case 4
        str='k*--';
    case 8
        str='m*--';
end

plot(elementNodeCoor,elementNodeStr,str)
hold on;
end
legend('Exact solution','NEL=1','NEL=2','NEL=4','NEL=8','interpreter','latex');


function [ grid_level, grid_order, grid_point ] = cc_levels_minmax ( ...
  dim_num, level_min, level_max, grid_num, point_num )

%*****************************************************************************80
%
%% CC_LEVELS_MINMAX computes CC grids with LEVEL_MIN <= LEVEL <= LEVEL_MAX.
%
%  Discussion:
%
%    The CC grids are required to have an order that is 2**LEVEL + 1.
%
%    The necessary dimensions of GRID_LEVEL, GRID_ORDER and GRID_POINT can be
%    determined by calling CC_LEVELS_MINMAX first.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    03 July 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the spatial dimension.
%
%    Input, integer LEVEL_MIN, LEVEL_MAX, the minimum and maximum values of
%    LEVEL.
%
%    Input, integer GRID_NUM, the number of Clenshaw Curtis
%    grids whose LEVEL value is between LEVEL_MIN and LEVEL_MAX.
%
%    Input, integer POINT_NUM, the total number of points in the grids.
%
%    Output, integer GRID_LEVEL(DIM_NUM,GRID_NUM), contains, for each
%    grid, the level of the Clenshaw-Curtis rule in each dimension.
%
%    Output, integer GRID_ORDER(DIM_NUM,GRID_NUM), contains, for each
%    grid, the order of the Clenshaw-Curtis rule in each dimension.
%
%    Output, real GRID_POINT(DIM_NUM,POINT_NUM), contains
%    a list of all the abscissas of all the rules, listed one grid at
%    a time.  If a point occurs in several grids, it will be listed
%    several times.
%

%
%  Outer loop generates LEVEL's from LEVEL_MIN to LEVEL_MAX.
%
  point_num = 0;
  grid_num = 0;

  for level = level_min : level_max
%
%  Middle loop generates next partition that adds up to LEVEL.
%
    level_1d = [];
    more = 0;
    h = 0;
    t = 0;

    while ( 1 )

      [ level_1d, more, h, t ] = comp_next ( level, dim_num, level_1d, more, h, t );
%
%  Inner (hidden) loop generates all CC points corresponding to given grid.
%
      order_1d = cc_level_to_order ( dim_num, level_1d );

      order_nd = prod ( order_1d(1:dim_num) );

      grid_point(1:dim_num,point_num+1:point_num+order_nd) = cc_grid ( ...
        dim_num, order_1d, order_nd );

      point_num = point_num + order_nd;

      grid_num = grid_num + 1;
      grid_level(1:dim_num,grid_num) = level_1d(1:dim_num);
      grid_order(1:dim_num,grid_num) = order_1d(1:dim_num);

      if ( ~more )
        break
      end

    end

  end

  return
end


function vObjRef=relVecAdd(vObsFrame,vObjInFrame)
%%RELVECADD  Special relativistic addition of velocity vectors. In the
%            inertial reference coordinate system, an observer moves with
%            constant velocity vObsFrame. In the coordinate system of the
%            observer, an object moves with constant velocity vObjInFrame.
%            This computes the velocity of the observed object in the
%            inertial reference frame. Under special relativity, it is not
%            just vObsFrame+vObjInFrame as it is in Newtonian mechanics.
%
%INPUTS:  vObsFrame The 3XN set of N velocity vectors in meters per second
%                   of the observer with respect to the inertial reference
%                   coordinate system. The magnitude of the velocity must
%                   be less than the speed of light.
%       vObjInFrame The 3XN set of N velocity vectors in meters per second
%                   of the object with respect to the observer's coordinate
%                   system. The magnitude of the velocity must be less than
%                   or equal to the speed of light.
%
%OUTPUTS: vObjRef  The 3XN set of velocity vectors in vObjInFrame
%                  transformed into the inertial reference coordinate
%                  system.
%
%The formulae for special relativistic velocity addition is derived in
%Chapter 1.4 of [1]. The magnitudes of vObsFrame and vObjInFrame must both
%be less than the speed of light (Constants.speedOfLight).
%
%REFERENCES:
%[1] G. Ludyk, Einstein in Matrix Form: Exact Derivation of the Theory of
%    Special and General Relativity without Tensors. Heidelberg: Springer,
%    2013.
%
%March 2014 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

c=Constants.speedOfLight;

v=vObsFrame;
u=vObjInFrame;

%The magnitudes of all of the v vectors.
vMag=sqrt(sum(v.*v,1));

gamma=1./sqrt(1-vMag.^2/c^2);

%v^T*u for each of the velocity vectors.
uv=sum(v.*u,1);

Num=v+u+bsxfun(@times,(1./gamma-1),(u-bsxfun(@times,(uv./vMag.^2),v)));
Denom=1+uv/c^2;

vObjRef=bsxfun(@rdivide,Num,Denom);

%If vMag=0 for any of the vectors, then NaNs will appear. In such an
%instance, the correct solution is vObjInFrame, because the frame is not
%moving.
colSel=any(~isfinite(vObjRef),1);
vObjRef(:,colSel)=u(:,colSel);
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 [a,d]=dualdiag(w,b)
%DUALDIAG Simultaneous diagonalisation of two hermitian matrices [A,D]=(W,B)
% Given two hermitian matrices W and B with W positive definite, this routine
% calculates A such that A'*W*A=I and A'*B*A=diag(D). The D will be in descending order.
%
% Suppose we have several N-dimensional data row-vectors arising from each of C different classes of data.
% for each class, c, we can form the mean data vector m(c) and the within-class covariance matrix W(c)
% We can then form the between class covariance matrix B by taking the covariance of the mean vectors m(1), m(2), ...
% and also the averaged within-class covariance matrix W by averaging W(1), W(2), ...
% If we then take A=dualdiag(W,B) and postmultiply all our original data vectors by A, we obtain new
% data vectors for which the average within-class covariance matrix is the identity and for which
% the first few components contain most of the information that is useful in discriminating between classes.

% An alternative algorithm that is 20% faster but slightly less accurate is:
% n=size(w,1);
% [v,l]=eig(w\b);
% [s,i]=sort(-diag(l));
% s=-s;
% d=l(i*(n+1)-n);
% q=sqrt(diag(v'*w*v))'.^(-1);
% a=v(:,i).*q(ones(n,1),i);

%      Copyright (C) Mike Brookes 1997
%      Version: $Id: dualdiag.m,v 1.4 2007/05/04 07:01:38 dmb Exp $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

[y,l]=eig(w+w');
z=y*diag(sqrt(diag(l*0.5)).^(-1));
[u,s,v]=svd(z'*(b+b')*z);
d=diag(s)*0.5;
a=z*u;


% Isoparametric Formulation Implementation
% clear memory
clear all; %close all; clc;

%% Physical parameters
% E: modulus of elasticity
% A: area of cross section
% L: length of bar
E=2e11; A=12.5e-4; L=[0.75,0.75];

%% Build Elements
% numberElements: number of elements
numberElements=2;
% numberNodes: number of nodes
numberNodes=3;
% generation of coordinates and connectivities
elementNodes=[1 2;2 3];
nodeCoordinates=[0 0.75 1.5];
% for structure:
   % displacements: displacement vector
   % force : force vector
   % stiffness: stiffness matrix
force=zeros(numberNodes,1);
stiffness=zeros(numberNodes,numberNodes);
% computation of the system stiffness matrix and force vector
for e=1:numberElements;
  % elementDof: element degrees of freedom (Dof)
  elementDof=elementNodes(e,:) ;
  detJacobian=L(e)/2;
  invJacobian=1/detJacobian;
  ngp = 2;
  [w,xi]=gauss1d(ngp);
  xc=0.5*(nodeCoordinates(elementDof(1))+nodeCoordinates(elementDof(2)));
  for ip=1:ngp;
      [shape,naturalDerivatives]=shapeFunctionL2(xi(ip));
      B=naturalDerivatives*invJacobian;
      stiffness(elementDof,elementDof)=...
      stiffness(elementDof,elementDof)+ B'*B*w(ip)*detJacobian*E*A;
      force(elementDof) = force(elementDof)+...
          60000*shape'*detJacobian*w(ip);
  end
end

%% BCs and solution
% prescribed dofs
prescribedDof = [1];
% solution
GDof=numberNodes;
displacements=solution(GDof,prescribedDof,stiffness,force);
% output displacements/reactions
outputDisplacementsReactions(displacements,stiffness, ...
    numberNodes,prescribedDof,force)

%% Stress
stress = zeros(numberElements,1);
for e=1:numberElements;
    stress(elementNodes(e,:)) = E*B*displacements(elementNodes(e,:));
end

%% Exact solutions
x = 0:0.1:1.5;
displacements_exact=(90000*x-30000*x.^2)/(E*A);
stress_exact=-((60000*x)-90000)/A;

%% plot figures
figure(1)

% Displacements
subplot(1,2,1); hold on;
plot(nodeCoordinates,displacements,'-.sb')
plot(x,displacements_exact,'-r'); hold off;
xlabel('x'); ylabel('displacement, u');
legend('FEM','Exact Solution',2);

% Stress
subplot(1,2,2); hold on;
stairs(nodeCoordinates,stress,'-.sb')
plot(x,stress_exact,'-r'); hold off;
xlabel('x'); ylabel('stress, \sigma');
legend('FEM','Exact Solution',1);


function sphere = makeSphere(Nx, Ny, Nz, radius, plot_sphere, binary)
%MAKESPHERE     Create a binary map of a sphere within a 3D grid.
%
% DESCRIPTION:
%       makeSphere creates a binary map of a spherical shell (using an
%       extension of the midpoint circle algorithm) within a
%       three-dimensional grid. The sphere position is denoted by 1's in
%       the matrix with 0's elsewhere. If the Boolean input parameter
%       "binary" is set to false (the default), the sphere map is returned
%       as a double precision matrix. If it is set to true, the map is
%       returned as a logical matrix.
%
% USAGE:
%       sphere = makeSphere(Nx, Ny, Nz, radius)
%       sphere = makeSphere(Nx, Ny, Nz, radius, plot_sphere)
%       sphere = makeSphere(Nx, Ny, Nz, radius, plot_sphere, binary)
%       sphere = makeSphere(Nx, Ny, Nz, radius, [], binary)
%
% INPUTS:
%       Nx, Ny, Nz      - size of the 3D grid [grid points]
%       radius          - sphere radius [grid points]
%
% OPTIONAL INPUTS:
%       plot_sphere     - Boolean controlling whether the sphere is
%                         plotted using voxelPlot (default = false)
%       binary          - Boolean controlling whether the sphere map is
%                         returned as a double precision matrix (false) or
%                         a logical matrix (true) (default = false)
%
% OUTPUTS:
%       sphere          - 3D binary map of a sphere
%
% ABOUT:
%       author          - Bradley Treeby
%       date            - 16th June 2009
%       last update     - 20th August 2014
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox
%
% See also makeBall, makeCartSphere, makeCircle, makeSphericalSection

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

% check for plot_sphere input
if nargin < 5 || isempty(plot_sphere)
    plot_sphere = false;
end

% check for binary input
if nargin < 6 || isempty(binary)
    binary = false;
end

% enforce a centered sphere
cx = floor(Nx/2)+1;
cy = floor(Ny/2)+1;
cz = floor(Nz/2)+1;

% preallocate the storage variable
if binary
    sphere = false(Nx, Ny, Nz);
else
    sphere = zeros(Nx, Ny, Nz);
end

% create a guide circle from which the individal radii can be extracted
guide_circle = makeCircle(Ny, Nx, cy, cx, radius);

% step through the guide circle points and create partially filled discs
centerpoints = (cx - radius):cx;
reflection_offset = length(centerpoints):-1:2;
for centerpoint_index = 1:length(centerpoints)

    % extract the current row from the guide circle
    row_data = guide_circle(:, centerpoints(centerpoint_index));

    % add an index to the grid points in the current row
    row_index = row_data.*(1:length(row_data)).';

    % calculate the radius
    swept_radius = (max(row_index) - min(row_index(row_index ~= 0)))/2;

    % create a circle to add to the sphere
    circle = makeCircle(Ny, Nz, cy, cz, swept_radius);

    % make an empty fill matrix
    if binary
        circle_fill = false(Ny, Nz);
    else
        circle_fill = zeros(Ny, Nz);
    end

    % fill in the circle line by line
    fill_centerpoints = (cz - swept_radius):(cz + swept_radius);
    for fill_centerpoint_index = 1:length(fill_centerpoints)

        % extract the first row
        row_data = circle(:, fill_centerpoints(fill_centerpoint_index));

        % add an index to the grid points in the current row
        row_index = row_data.*(1:length(row_data)).';

        % calculate the diameter
        start_index = min(row_index(row_index ~= 0));
        stop_index = max(row_index);

        % count how many points on the line
        num_points = sum(row_data);

        % fill in the line
        if start_index ~= stop_index && (stop_index - start_index) >= num_points
            circle_fill(start_index + num_points/2:stop_index - num_points /2, fill_centerpoints(fill_centerpoint_index)) = 1;
        end
    end

    % remove points from the filled circle that existed in the previous
    % layer
    if centerpoint_index == 1
        sphere(centerpoints(centerpoint_index), :, :) = circle + circle_fill;
        prev_circle = circle + circle_fill;
    else
        prev_circle_alt = circle + circle_fill;
        circle_fill = circle_fill - prev_circle;
        circle_fill(circle_fill < 0) = 0;
        sphere(centerpoints(centerpoint_index), :, :) = circle + circle_fill;
        prev_circle = prev_circle_alt;
    end

    % create the other half of the sphere at the same time
    if centerpoint_index ~= length(centerpoints)
        sphere(cx + reflection_offset(centerpoint_index) - 1, :, :) = sphere(centerpoints(centerpoint_index), :, :);
    end
end

% plot results
if plot_sphere
    voxelPlot(double(sphere));
end


%% CUBEMAXWELLSADDLE solves Maxwell type equations in a cube using linear order element.
% This is a special case of div u = g being nozero.
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

clear; close all;

%% Defacult setting
[node,elem] = cubemesh([-1,1,-1,1,-1,1],1);
%%
pde.J = @(p) [sin(p(:,1)).*cos(p(:,2)).*sin(p(:,3)), ...
              cos(p(:,1)).*sin(p(:,2)).*sin(p(:,3)), ...
              2*cos(p(:,1)).*cos(p(:,2)).*cos(p(:,3))];
pde.exactu = @(p)[0*p(:,1), 0*p(:,2), ...
    cos(p(:,1)).*cos(p(:,2)).*cos(p(:,3))];
pde.g_D = pde.exactu;
pde.curlu = @(p) [-cos(p(:,1)).*sin(p(:,2)).*cos(p(:,3)), ...
              sin(p(:,1)).*cos(p(:,2)).*cos(p(:,3)), 0*p(:,3)];
pde.g = @(p) -cos(p(:,1)).*cos(p(:,2)).*sin(p(:,3));
pde.mu = 1;

%%
bdFlag = setboundary3(node,elem,'Dirichlet');
option.printlevel = 0;
% option.solver = 'direct';
option.solver = 'mg';
option.solver = 'diag';

%% Parameters
maxIt = 3;
N = zeros(maxIt,1);
h = zeros(maxIt,1);
energyErr = zeros(maxIt,1);
L2Err = zeros(maxIt,1);
uIuhErr = zeros(maxIt,1);

%% Finite Element Method
for k = 1:maxIt
    [node,elem,bdFlag] = uniformrefine3(node,elem,bdFlag);
    [soln,eqn,info] = Maxwell1saddle(node,elem,bdFlag,pde,option);
    u = soln.u;
    fprintf('\n\n # of DoFs = %d \n',length(u));
    % compute error
    uI = edgeinterpolate1(pde.exactu,node,eqn.edge);
    energyErr(k) = getHcurlerror3ND1(node,elem,pde.curlu,u);
    L2Err(k) = getL2error3ND1(node,elem,pde.exactu,u);
    uIuhErr(k) = sqrt((u-uI)'*(eqn.A)*(u-uI));
%     L2Err(k) = sqrt((u-uI)'*(eqn.M)*(u-uI));
    fprintf('\n ||curl(u-u_h)|| is %g \n',energyErr(k))
    N(k) = length(u);
    h(k) = 1./(size(node,1)^(1/3)-1);
end

%% Plot convergence rates
figure(1);
showrateh3(h,energyErr,1,'k-+','|| curl (u-u_h) ||',...
           h,uIuhErr,1,'r-+','|| curl (u_I-u_h) ||',...
           h,L2Err,1,'b-+','|| u-u_h||');


function [ n_data, a, x, fx ] = chi_square_cdf_values ( n_data )

%*****************************************************************************80
%
%% CHI_SQUARE_CDF_VALUES returns some values of the Chi-Square CDF.
%
%  Discussion:
%
%    In Mathematica, the function can be evaluated by:
%
%      Needs["Statistics`ContinuousDistributions`"]
%      dist = ChiSquareDistribution [ df ]
%      CDF [ dist, x ]
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  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 A, the parameter of the function.
%
%    Output, real X, the argument of the function.
%
%    Output, real FX, the value of the function.
%
  n_max = 21;

  a_vec = [ ...
     1,  2,  1,  2, ...
     1,  2,  3,  4, ...
     1,  2,  3,  4, ...
     5,  3,  3,  3, ...
     3,  3, 10, 10, ...
    10 ];

  fx_vec = [ ...
     0.7965567455405796E-01, ...
     0.4987520807317687E-02, ...
     0.1124629160182849E+00, ...
     0.9950166250831946E-02, ...
     0.4729107431344619E+00, ...
     0.1812692469220181E+00, ...
     0.5975750516063926E-01, ...
     0.1752309630642177E-01, ...
     0.6826894921370859E+00, ...
     0.3934693402873666E+00, ...
     0.1987480430987992E+00, ...
     0.9020401043104986E-01, ...
     0.3743422675270363E-01, ...
     0.4275932955291202E+00, ...
     0.6083748237289110E+00, ...
     0.7385358700508894E+00, ...
     0.8282028557032669E+00, ...
     0.8883897749052874E+00, ...
     0.1721156299558408E-03, ...
     0.3659846827343712E-02, ...
     0.1857593622214067E-01 ];

  x_vec = [ ...
     0.01E+00, ...
     0.01E+00, ...
     0.02E+00, ...
     0.02E+00, ...
     0.40E+00, ...
     0.40E+00, ...
     0.40E+00, ...
     0.40E+00, ...
     1.00E+00, ...
     1.00E+00, ...
     1.00E+00, ...
     1.00E+00, ...
     1.00E+00, ...
     2.00E+00, ...
     3.00E+00, ...
     4.00E+00, ...
     5.00E+00, ...
     6.00E+00, ...
     1.00E+00, ...
     2.00E+00, ...
     3.00E+00 ];

  if ( n_data < 0 )
    n_data = 0;
  end

  n_data = n_data + 1;

  if ( n_max < n_data )
    n_data = 0;
    a = 0;
    x = 0.0;
    fx = 0.0;
  else
    a = a_vec(n_data);
    x = x_vec(n_data);
    fx = fx_vec(n_data);
  end

  return
end


function idx = findClosestCentroids(X, centroids)
%FINDCLOSESTCENTROIDS computes the centroid memberships for every example
%   idx = FINDCLOSESTCENTROIDS (X, centroids) returns the closest centroids
%   in idx for a dataset X where each row is a single example. idx = m x 1
%   vector of centroid assignments (i.e. each entry in range [1..K])
%

% Set K
K = size(centroids, 1);

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

% ====================== YOUR CODE HERE ======================
% Instructions: Go over every example, find its closest centroid, and store
%               the index inside idx at the appropriate location.
%               Concretely, idx(i) should contain the index of the centroid
%               closest to example i. Hence, it should be a value in the
%               range 1..K
%
% Note: You can use a for-loop over the examples to compute this.
%

t = zeros(1, K);
for i = 1:length(idx)
    for j = 1:K
        temp = centroids(j, :) - X(i, :);
        t(j) = temp * temp';
    end
    [~, index] = min(t);
    idx(i) = index;
end

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

end


% DEMO  --  Chebyshev Polynomial Interpolation Order vs Accuracy
% UPDATED  --  October 28, 2013
% Written by Matthew Kelly, Cornell University
%
%
% This script demonstrates how the accuracy of a chebyshev approximation is
% dependant on the order of the underlying polynomial.
%
% RESULTS:
%   The accuracy is very bad if the order is too small, but then rapidly
%   improves until it reaches machine precision. The accuracy of the
%   derivative will get slowly worse for very large order apprimations due
%   to the compounding of rounding errors in the matrix multiplication.
%

%% General Settings
clear; clc;

%What order should the approximation be?
orderRange = [2,1000];
orderNum = 20;
orderList = unique(round(logspace(...
    log10(orderRange(1)),...
    log10(orderRange(2)),...
    orderNum)));

%How many points should be used for error calculations and plotting?
nTime = 1000;

%What domain should we be looking at?
d = [-2,1];

%Time for use in plots
time = linspace(d(1),d(2),nTime);

%Set up the input/output struct:
IO.domain = d;
IO.userFunc = @testFunction;

%Set up the data logging:
N = length(orderList);
cpuTime = zeros(N,1);
maxError = zeros(N,2);
meanError = zeros(N,2);

%Run the calculations:
for i=1:N
    disp(['Order: ' num2str(orderList(i))])
    tic;
    f = chebyshevFit(IO, orderList(i));
    [y, Dy] = chebyshevInterpolate(f,time,d);
    cpuTime(i) = toc;
    [g,Dg] = testFunction(time);
    e = abs(g-y);
    De = abs(Dg-Dy);
    maxError(i,:) = [max(e),max(De)];
    meanError(i,:) = [mean(e),mean(De)];
end

%Make nice plots:
    figure(403); clf;
    subplot(3,2,1)
        loglog(orderList,cpuTime)
        title('CPU Time')
        xlabel('Order of Chebyshev Polynomial')
        ylabel('Time (s)')
    subplot(3,2,2)
        plot(time,testFunction(time))
        title('Function')
        xlabel('Input')
        ylabel('Output')
    subplot(3,2,3)
        loglog(orderList,maxError(:,1))
        title('Max Error in Function')
        xlabel('Order of Chebyshev Polynomial')
    subplot(3,2,5)
        loglog(orderList,meanError(:,1))
        title('Mean Error in Function')
        xlabel('Order of Chebyshev Polynomial')
    subplot(3,2,4)
        loglog(orderList,maxError(:,2))
        title('Max Error in Derivative')
        xlabel('Order of Chebyshev Polynomial')
    subplot(3,2,6)
        loglog(orderList,meanError(:,2))
        title('Mean Error in Derivative')
        xlabel('Order of Chebyshev Polynomial')


function [tfr,t,f] = tfrpmh(x,t,N,h,trace);
%TFRPMH  Pseudo Margenau-Hill time-frequency distribution.
%       [TFR,T,F]=TFRPMH(X,T,N,H,TRACE) computes the Pseudo Margenau-Hill
%       distribution of a discrete-time signal X, or the
%       cross Pseudo Margenau-Hill representation between two signals.
%
%       X     : signal if auto-PMH, or [X1,X2] if cross-PMH.
%       T     : time instant(s)          (default : 1:length(X)).
%       N     : number of frequency bins (default : length(X)).
%       H     : frequency smoothing window, H(0) being forced to 1
%                                        (default : Hamming(N/4)).
%       TRACE : if nonzero, the progression of the algorithm is shown
%                                        (default : 0).
%       TFR   : time-frequency representation. When called without
%               output arguments, TFRPMH runs TFRQVIEW.
%       F     : vector of normalized frequencies.
%
%       Example :
%        sig=fmlin(128,0.1,0.4); t=1:128;
%        h=tftb_window(63,'Kaiser'); tfrpmh(sig,t,128,h,1);
%
%       See also all the time-frequency representations listed in
%        the file CONTENTS (TFR*)

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

[xrow,xcol] = size(x);
if (nargin < 1),
 error('At least 1 parameter is required');
elseif nargin<=2,
 N=xrow;
end;

hlength=floor(N/4);
hlength=hlength+1-rem(hlength,2);

if (nargin == 1),
 t=1:xrow; h = tftb_window(hlength); trace=0;
elseif (nargin == 2 | nargin == 3),
 h = tftb_window(hlength); trace = 0;
elseif (nargin == 4),
 trace = 0;
end;

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

[hrow,hcol]=size(h); Lh=(hrow-1)/2; h=h/h(Lh+1);
if (hcol~=1)|(rem(hrow,2)==0),
 error('H must be a smoothing window with odd length');
end;

tfr= zeros (N,tcol) ;
if trace, disp('Pseudo Margenau-Hill distribution'); end;
for icol=1:tcol,
 ti= t(icol); tau=-min([round(N/2)-1,Lh,xrow-ti]):min([round(N/2)-1,Lh,ti-1]);
 indices= rem(N+tau,N)+1;
 if trace, disprog(icol,tcol,10); end;
 tfr(indices,icol)=h(Lh+1+tau).*x(ti,1).*conj(x(ti-tau,xcol));
end;
if trace, fprintf('\n'); end;
tfr= real(fft(tfr));

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


function mappedX = diffusion_maps(X, no_dims, t, sigma)
%DIFFUSION_MAPS Runs the diffusion map algorithm
%
%   mappedX = diffusion_maps(X, no_dims, t, sigma)
%
% The functions runs the diffusion map algorithm on dataset X to reduce it
% to dimensionality no_dims. The variable sigma is the variance of the Gaussian
% used in the affinity computation (default = 1). The variable alpha
% determines the operator that is applied on the graph (default = 1).
%
%

% This file is part of the Matlab Toolbox for Dimensionality Reduction.
% The toolbox can be obtained from http://homepage.tudelft.nl/19j49
% You are free to use, change, or redistribute this code in any way you
% want for non-commercial purposes. However, it is appreciated if you
% maintain the name of the original author.
%
% (C) Laurens van der Maaten, Delft University of Technology

    % Give memory warning
    if size(X, 1) > 3000
        warning(['Due to the large number of instances (' num2str(size(X, 1)) '), diffusion maps may run out of memory.']);
    end

    % Normalize data
    X = double(X);
    X = X - min(X(:));
    X = X / max(X(:));

    % Compute Gaussian kernel matrix
    disp(['Compute Markov forward transition probability matrix with ' num2str(t) ' timesteps...']);
    sumX = sum(X .^ 2, 2);
    K = exp(-bsxfun(@plus, sumX, bsxfun(@plus, sumX', -2 * (X * X'))) ./ (2 .* sigma ^ 2));

    % Compute Markov probability matrix with t timesteps
    p = sum(K, 1)';
    K = K ./ ((p * p') .^ t);
    p = sqrt(sum(K, 1))';
    K = K ./ (p * p');

    % Perform economy-size SVD
    disp('Perform eigendecomposition...');
    [U, S, V] = svd(K, 0);
    U = bsxfun(@rdivide, U, U(:,1));
    mappedX = U(:,2:no_dims + 1);


function tq = gettrimeshquan( p, t)
% tq.ds  - edge length connecting node
%           2-3, 3-1, and 1-2 respectively
% tq.J   - 0.5*element area
% tq.vang - angle assocaited with node 1, 2, 3 respectively
%

edge = [2  3  1
        3  1  2] ;

ne = size( t, 1) ;

p1 = p(t(:, edge(1,:))',:)  ;
p2 = p(t(:, edge(2,:))',:)  ;

%
ds = reshape(sqrt(sum((p1 - p2).^2,2)), 3, ne )' ;

idxcm = [ 1 2 3
          2 3 1
          3 1 2 ] ;

% Internal angle
tq.vang = zeros(ne,3) ;
for i = 1: 3
   tq.vang(:,i) = acos((-ds(:,idxcm(i,1)).^2 +  ds(:,idxcm(i,2)).^2 + ...
           ds(:,idxcm(i,3)).^2)./(2*ds(:,idxcm(i,2)).*ds(:,idxcm(i,3)))) ;
end
%

% Length
tq.ds = ds ;

% Jacobian
xr = 0.5*(p(t(:,2),:) - p(t(:,1),:)) ;
xs = 0.5*(p(t(:,3),:) - p(t(:,1),:)) ;

tq.J = (xr(:,1).*xs(:,2) - xs(:,1).*xr(:,2)) ;

% idxtb = find( vang' < 25*pi/180 ) ;
% ietb = unique(ceil(idxtb/3)) ;

%
%  Bank, Randolph E.,
%      PLTMG: A Software Package for Solving Elliptic Partial Differential Equations,
%      User's Guide 6.0, Society for Industrial and Applied Mathematics, Philadelphia, PA, 1990.
tq.qm = 4*sqrt(3)*(2*tq.J)./(sum(tq.ds.^2,2)) ;


function call_price=american_call_perpetual(S, K, r, q, sigma)

%--------------------------------------------------------------------------
%
% DESCRIPTION:
%
% Price for an american perpetual call option
%
%
% Reference:
%
% John Hull, "Options, Futures and other Derivative Securities",
% Prentice-Hall, second edition, 1993.
%
%--------------------------------------------------------------------------
%
% INPUTS:
%
%  S:       spot price
%  K:       exercice price
%  r:       interest rate
%  q:       dividend yield
%  sigma:   volatility
%
%--------------------------------------------------------------------------
%
% OUTPUT:
%
% call_price: price of a call option
%
%--------------------------------------------------------------------------
%
% Author:  Paolo Z., February 2012
%
%--------------------------------------------------------------------------

sigma_sqr=(sigma^2);
h1 = 0.5 - ((r-q)/sigma_sqr);
h1 = h1 + sqrt( (((r-q)/sigma_sqr-0.5)^2)+2.0*r/sigma_sqr );

call_price=(K/(h1-1.0))*( (((h1-1.0)/h1)*(S/K))^h1 );


function Y=runMLP(X,Wx,Wy)
% The matrix implementation of the two-layer Multilayer Perceptron (MLP) neural networks.
%
% Author: Marcelo Augusto Costa Fernandes
% DCA - CT - UFRN
% mfernandes@dca.ufrn.br
%
% Input parameters:
%   X: Input neural network.  X is a (p x K) dimensional matrix, where p is a number of the inputs and K >= 1.
%   Wx: Hidden layer weight matrix. Wx is a (H x p+1) dimensional matrix.
%   Wy: Output layer weight matrix. Wy is a (m x H+1) dimensional matrix.
%
% Output parameters:
%  Y: Outpuy neural network.  Y is a (m x K) dimensional matrix, where m is a number of the output neurons and K >= 1.

[p1 N] = size (X);

bias = -1;

X = [bias*ones(1,N) ; X];

V = Wx*X;
Z = 1./(1+exp(-V));

S = [bias*ones(1,N);Z];
G = Wy*S;

Y = 1./(1+exp(-G));


function [ x, w ] = hermite_ek_compute ( n )

%*****************************************************************************80
%
%% HERMITE_EK_COMPUTE computes a Gauss-Hermite quadrature rule.
%
%  Discussion:
%
%    The code uses an algorithm by Elhay and Kautsky.
%
%    The abscissas are the zeros of the N-th order Hermite polynomial.
%
%    The integral:
%
%      integral ( -oo < x < +oo ) exp ( - x * x ) * f(x) dx
%
%    The quadrature rule:
%
%      sum ( 1 <= i <= n ) w(i) * f ( x(i) )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 April 2011
%
%  Author:
%
%    Original FORTRAN77 version by Sylvan Elhay, Jaroslav Kautsky.
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Sylvan Elhay, Jaroslav Kautsky,
%    Algorithm 655: IQPACK, FORTRAN Subroutines for the Weights of
%    Interpolatory Quadrature,
%    ACM Transactions on Mathematical Software,
%    Volume 13, Number 4, December 1987, pages 399-415.
%
%  Parameters:
%
%    Input, integer N, the number of abscissas.
%
%    Output, real X(N), the abscissas.
%
%    Output, real W(N), the weights.
%

%
%  Define the zero-th moment.
%
  zemu = gamma ( 0.5 );
%
%  Define the Jacobi matrix.
%
  bj = zeros ( n, 1 );
  for i = 1 : n
    bj(i) = i / 2.0;
  end
  bj(1:n) = sqrt ( bj(1:n) );

  x = zeros ( n, 1 );

  w = zeros ( n, 1 );
  w(1) = sqrt ( zemu );
%
%  Diagonalize the Jacobi matrix.
%
  [ x, w ] = imtqlx ( n, x, bj, w );

  w(1:n) = w(1:n).^2;

  return
end


function [ x, seed ] = normal_truncated_ab_sample ( mu, s, a, b, seed )

%*****************************************************************************80
%
%% NORMAL_TRUNCATED_AB_SAMPLE samples the truncated Normal PDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 August 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real MU, S, the mean and standard deviation of the
%    parent Normal distribution.
%
%    Input, real A, B, the lower and upper truncation limits.
%
%    Input/output, integer SEED, a seed for the random number
%    generator.
%
%    Output, real X, a sample of the PDF.
%
  alpha = ( a - mu ) / s;
  beta = ( b - mu ) / s;

  alpha_cdf = normal_01_cdf ( alpha );
  beta_cdf = normal_01_cdf ( beta );

  [ u, seed ] = r8_uniform_01 ( seed );
  xi_cdf = alpha_cdf + u * ( beta_cdf - alpha_cdf );
  xi = normal_01_cdf_inv ( xi_cdf );

  x = mu + s * xi;

  return
end


function r=ksrmv(x,y,hx,z)
% KSRMV   Multivariate kernel smoothing regression
%
% r=ksrmv(x,y) returns the Gaussian kernel regression in structure r such that
%   r.f(r.x) = y(x) + e
% The bandwidth and number of samples are also stored in r.h and r.n
% respectively.
%
% r=ksrmv(x,y,h) performs the regression using the specified bandwidth, h.
%
% r=ksrmv(x,y,h,z) calculates the regression at location z (default z=x).
%
% Algorithm
% The kernel regression is a non-parametric approach to estimate the
% conditional expectation of a random variable:
%
% E(Y|X) = f(X)
%
% where f is a non-parametric function. Based on the kernel density
% estimation, this code implements the Nadaraya-Watson kernel regression
% using the Gaussian kernel as follows:
%
% f(x) = sum(kerf((x-X)/h).*Y)/sum(kerf((x-X)/h))
%
% See also gkde, ksdensity, ksr

% Example 1: smoothing a noised logo
%{
L = 40*membrane(1,25)+randn(51);
[x,y]=meshgrid(0:50);
r=ksrmv([x(:) y(:)],L(:));
Lr=L;
Lr(:)=r.f;
subplot(121), surf(x,y,L)
subplot(122), surf(x,y,Lr)
%}
% Example 2: smoothing noised peaks with 20% missing data
%{
L = 10*peaks(50)+randn(50);
I = ceil(rand(500,1)*2500);
L(I) = NaN;
[x,y]=meshgrid(1:50);
r=ksrmv([x(:) y(:)],L(:));
Lr=L;
Lr(:)=r.f;
subplot(121), surf(x,y,L)
subplot(122), surf(x,y,Lr)
%}

% By Yi Cao at Cranfield University on 20 March 2008.
%

% Check input and output
error(nargchk(2,4,nargin));
error(nargoutchk(0,1,nargout));
y=y(:);
if size(x,1)~=size(y,1)
    error('x and y have different rows.');
end
d=size(x,2);

% Default parameters
if nargin<4
    z=x;
elseif size(z,2)~=d
    error('z must have the same number of columns as x.')
end
r.x=z;
N=size(z,1);

% clean missing or invalid data points
inv=(y~=y);
x(inv,:)=[];
y(inv)=[];
r.n=numel(y);

if nargin<3
    % optimal bandwidth suggested by Bowman and Azzalini (1997) p.31
    hy=median(abs(y-median(y)))/0.6745*(4/(d+2)/r.n)^(1/(d+4));
    hx=median(abs(x-repmat(median(x),r.n,1)))/0.6745*(4/(d+2)/r.n)^(1/(d+4));
    hx=sqrt(hy*hx);
elseif size(hx,2)~=d
    error('h must be a scalar.')
end
r.h=hx;
%
% % Vectorization, Not suitable for large data set
% % Firstly, diagnal matrix for bandwidth
% H=diag(1./hx);
%
% % Then scale X by the bendwidth
% X=r.x*H;
%
% % Square of X
% X2=sum(X.*X,2)/2;
%
% % Scale Xi
% C=H*x';
%
% % Square of Xi
% C2=sum(C.*C)/2;
%
% % D = ((X - Xi) / H)^T ((X - Xi) / H)
% D=C2(ones(N,1),:)+X2(:,ones(1,r.n))-X*C;
%
% % only elements whos values < 12 need to evaluated since exp(-12) = 6.1e-6
% idx=D<12;
%
% % prepare local variable
% Z=zeros(N,r.n);
%
% % Z = exp(-D)
% Z(idx)=exp(-D(idx));
%
% % f(x) = sum Z*Yi / sum Z
% r.f=sum(Z.*y(:,ones(1,N))',2)./sum(Z,2);

% Improved efficient code

% Scaling first
H=diag(1./hx);
x=x*H;
x1=r.x*H;

% Gaussian kernel function
kerf=@(z)exp(-sum(z.*z,2)/2);

% allocate memory
r.f=zeros(N,1);

% Loop through each regression point
for k=1:N
    % scaled deference from regression point
    xx=abs(x-x1(k+zeros(r.n,1),:));
    % select neighbours using exp(-5^2/2)<5e-6
    idx=all(xx<5,2);
    % kernel function
    z=kerf(xx(idx,:));
    % regression
    r.f(k)=sum(z.*y(idx))/sum(z);
end


function [PBarVals,dPBarValsdTheta,d2PBarValsdTheta2]=LegendreCos(theta,M,scalFactor)
%%LEGENDRECOS Evaluate the fully associated Legendre functions of
%           cos(theta) of degree n and order m for all n from 0 to M and
%           for each n, m goes from 0 to n. Such a function is typically
%           written as \bar{P}_{nm}(cos(theta)). Also evaluate
%           D{\bar{P}_{nm}(cos(theta))} and D2{\bar{P}_{nm}(cos(theta))},
%           where D{} is the first derivative with respect to theta and
%           D2{} is the second derivative with respect to theta. All of the
%           values can be scaled by a factor of scalFac, if desired, to
%           help prevent overflows with high degrees and orders.
%
%INPUTS: theta An angle in radians.
%       maxDeg The maximum degree and order of the output. This must be
%              >=0.
%   scalFactor A scale factor to help prevent overflow of the results. If
%              this parameter is omitted or an empty matrix is passed, the
%              default of 1 is used.
%
%OUTPUTS: PBarUVals An instance of the CountingClusterSet class such that
%                   PBarVals(n+1,m+1)=scalFac*\bar{P}_{nm}(cos(theta)).
%                   To extract all coefficients as a vector just call
%                   PBarUVals(:).
%   dPBarValsdTheta An instance of the CountingClusterSet class such that
%                   dPBarValsdTheta(n+1,m+1)=scalFac*D{\bar{P}_{nm}(cos(theta))}
% d2PBarValsdTheta2 An instance of the CountingClusterSet class such that
%                   d2PBarValsdTheta2(n+1,m+1)=scalFac*D2{\bar{P}_{nm}(cos(theta))}
%
%The definition of associated Legendre polynomial underlying this function
%is
% P_(nm)(x)=(1-x^2)^(m/2)*Dm{P(n,x)}
%where Dm{} represents the mth-order derivative and P(n,x) is the Legendre
%polynomial having the form
%P(n,x)=(1/2^n)*sum_{k=0}^n binomial(n,n)*(x-1)^(n-k)*(x+k)^k
%This definition lacks the Condon-Shortley phase. Adding the phase is the
%same as multiplying P_(nm)(x) by (-1)^m. The polynomials are fully
%normalized, meaning that each one is multiplied by
%N(n,m)=sqrt((2*n+1)*(2-KDelta(m))*factorial(n-m)/factorial(n+m))
%This is normalization 0 in the changeSpherHarmonicNorm function.
%
%Fully normalized associated Legendre polynomials often arise when
%computing spherical harmonic expansions. When simply evaluating an
%expansion, one will typically use fully normalized Legendre functions that
%have been divided by abs(sin(theta))^m as in [1]. However, when fitting
%coefficients for such an expansion, one will typically need the function
%values directly, which is what this function provides.
%
%This function just calls the function NALegendreCosRat and then multiplies
%out the denominators.
%
%EXAMPLE:
%One can see that this function returns the same values as the legendre
%function of cos(theta) when the proper normalization is selected. However,
%this function returns more values than legendre, as Matlab's legendre
%function just returns a vector for a single value of n.
% M=3;
% theta=-0.5;
% PBarVecMatLab=legendre(M,cos(theta));
% PBarVals=LegendreCos(theta,M);
% arePolyVals=true;
% origNormType=0;
% normType=8;
% PBarVals=changeSpherHarmonicNorm(PBarVals,origNormType,normType,arePolyVals);
% PBarVec=PBarVals(M+1,:);
% ratioCompare=PBarVecMatLab./PBarVec
%One will see that the ratio is essentially all ones.
%
%REFERENCES:
%[1] S. A. Holmes and W. E. Featherstone, "A unified approach to the
%    Clenshaw summation and the recursive computation of very high degree
%    and order normalised associated Legendre functions," Journal of
%    Geodesy, vol. 76, no. 5, pp. 279-299, May 2002.
%
%June 2017 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

if(nargin<3||isempty(scalFactor))
    scalFactor=1;
end

u=abs(sin(theta));

if(nargin<2)
    PBarVals=NALegendreCosRat(theta,M,scalFactor);
    for n=1:M
        um=u;
        for m=1:n
            PBarVals(n+1,m+1)=PBarVals(n+1,m+1)*um;
            um=um*u;
        end
    end
elseif(nargout==2)
    [PBarVals,dPBarValsdTheta]=NALegendreCosRat(theta,M,scalFactor);
    for n=1:M
        um=u;
        for m=1:n
            PBarVals(n+1,m+1)=PBarVals(n+1,m+1)*um;
            dPBarValsdTheta(n+1,m+1)=dPBarValsdTheta(n+1,m+1)*um;
            um=um*u;
        end
    end
else%nargout==3
    [PBarVals,dPBarValsdTheta,d2PBarValsdTheta2]=NALegendreCosRat(theta,M,scalFactor);
    for n=1:M
        um=u;
        for m=1:n
            PBarVals(n+1,m+1)=PBarVals(n+1,m+1)*um;
            dPBarValsdTheta(n+1,m+1)=dPBarValsdTheta(n+1,m+1)*um;
            d2PBarValsdTheta2(n+1,m+1)=d2PBarValsdTheta2(n+1,m+1)*um;
            um=um*u;
        end
    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 Chi2 = chistart (D,L,a,ncands,factor)
%CHISTART: Computes the initial size of the search ellipsoid
%
% This routine computes or approximates the initial size of the search
% ellipsoid. If the requested number of candidates is not more than the
% dimension + 1, this is done by computing the squared distances of partially
% conditionally rounded float vectors to the float vector in the metric of the
% covariance matrix. Otherwise an approximation is used.
%
% Input arguments
%    L,D   : LtDL-decomposition of the variance-covariance matrix of
%            the float ambiguities (preferably decorrelated)
%    a     : float ambiguites (preferably decorrelated)
%    ncands: Requested number of candidates (default = 2)
%    factor: Multiplication factor for the volume of the resulting
%            search ellipsoid (default = 1.5)
%
% Output arguments:
%    Chi2  : Size of the search ellipsoid

% ----------------------------------------------------------------------
% File.....: chistart.m
% Date.....: 19-MAY-1999
% Modified.: 05-MAR-2001, by P. Joosten
% Author...: Peter Joosten
%            Mathematical Geodesy and Positioning
%            Delft University of Technology
% ----------------------------------------------------------------------

% ------------------
% --- Initialize ---
% ------------------

if nargin < 4; ncands = 2  ; end;
if nargin < 5; factor = 1.5; end;

n = max(size(a));

% ----------------------------------------------------------------------
% --- Computation depends on the number of candidates to be computed ---
% ----------------------------------------------------------------------

if ncands <= n+1;

    % --------------------------------------------------------
    % --- Computation based on the bootstrapping estimator ---
    % --------------------------------------------------------

    Chi = [];

    for k = n:-1:0;

        afloat = a;
        afixed = a;

        for i = n:-1:1;

            dw = 0;
            for j = n:-1:i;
                dw = dw + L(j,i) * (afloat(j) - afixed(j));
            end;

            afloat(i) = afloat(i) - dw;
            if (i ~= k);
                afixed(i) = round (afloat(i));
            else
                if isequal (afloat(i),afixed(i));
                    afixed(i) = round(afixed(i) + 1);
                else
                    afixed(i) = round (afloat(i) + sign (afloat(i) - afixed(i)));
                end;
            end;

        end;

        Chi = [Chi (a-afixed)' * (L'*diag(D)*L)^(-1) * (a-afixed)];

    end;

    % ---------------------------------------------------------------
    % --- Sort the results, and return the appropriate number     ---
    % --- Add an "eps", to make sure there is no boundary problem ---
    % ---------------------------------------------------------------

    Chi  = sort(Chi);
    Chi2 = Chi(ncands) + 1d-6;

else

    % -----------------------------------------------------
    % An approximation for the squared norm is computed ---
    % -----------------------------------------------------

    Linv = (L)^(-1);
    Dinv = 1./D;

    Vn   = (2/n) * (pi ^ (n/2) / gamma(n/2));
    Chi2 = factor * (ncands / sqrt((prod(1 ./ Dinv)) * Vn)) ^ (2/n);

end;

% ----------------------------------------------------------------------
% End of routine: chistart
% ----------------------------------------------------------------------


function varargout = sph2cart2d(theta, phi, rho)
%SPH2CART2D Convert spherical coordinates to cartesian coordinates in degrees
%
%   C = SPH2CART2(THETA, PHI, RHO)
%   C = SPH2CART2(THETA, PHI)       (assume rho = 1)
%   C = SPH2CART2(S)
%   [X, Y, Z] = SPH2CART2(THETA, PHI, RHO);
%
%   S = [phi theta rho] (spherical coordinate).
%   C = [X Y Z]  (cartesian coordinate)
%
%   The following convention is used:
%   THETA is the colatitude, in degrees, 0 for north pole, +180 degrees for
%   south pole, +90 degrees for points with z=0.
%   PHI is the azimuth, in degrees, defined as matlab cart2sph: angle from
%   Ox axis, counted counter-clockwise.
%   RHO is the distance of the point to the origin.
%   Discussion on choice for convention can be found at:
%   http://www.physics.oregonstate.edu/bridge/papers/spherical.pdf
%
%   See also:
%   angles3d, cart2sph2d, sph2cart2
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2011-06-29,    using Matlab 7.9.0.529 (R2009b)
% Copyright 2011 INRA - Cepia Software Platform.

% Process input arguments
if nargin == 1
    phi     = theta(:, 2);
    if size(theta, 2) > 2
        rho = theta(:, 3);
    else
        rho = ones(size(phi));
    end
    theta   = theta(:, 1);

elseif nargin == 2
    rho     = ones(size(theta));

end

% conversion
rz = rho .* sind(theta);
x  = rz  .* cosd(phi);
y  = rz  .* sind(phi);
z  = rho .* cosd(theta);

% Process output arguments
if nargout == 1 || nargout == 0
    varargout{1} = [x, y, z];

else
    varargout{1} = x;
    varargout{2} = y;
    varargout{3} = z;
end


function p = bspeval(d,c,k,u)
%
% Function Name:
%
%   bspeval - Evaluate a univariate B-Spline.
%
% Calling Sequence:
%
%   p = bspeval(d,c,k,u)
%
% Parameters:
%
%   d	: Degree of the B-Spline.
%
%   c	: Control Points, matrix of size (dim,nc).
%
%   k	: Knot sequence, row vector of size nk.
%
%   u	: Parametric evaluation points, row vector of size nu.
%
%   p	: Evaluated points, matrix of size (dim,nu)
%
% Description:
%
%   Evaluate a univariate B-Spline. This function provides an interface to
%   a toolbox 'C' routine.
nu = numel(u);
[mc,nc] = size(c);
                                                %   int bspeval(int d, double *c, int mc, int nc, double *k, int nk, double *u,int nu, double *p){
                                                %   int ierr = 0;
                                                %   int i, s, tmp1, row, col;
                                                %   double tmp2;
                                                %
                                                %   // Construct the control points
                                                %   double **ctrl = vec2mat(c,mc,nc);
                                                %
                                                %   // Contruct the evaluated points
p = zeros(mc,nu);                               %   double **pnt = vec2mat(p,mc,nu);
                                                %
                                                %   // space for the basis functions
N = zeros(d+1,1);                               %   double *N = (double*) mxMalloc((d+1)*sizeof(double));
                                                %
                                                %   // for each parametric point i
for col=1:nu                                    %   for (col = 0; col < nu; col++) {
                                                %     // find the span of u[col]
    s = findspan(nc-1, d, u(col), k);           %     s = findspan(nc-1, d, u[col], k);
    N = basisfun(s,u(col),d,k);                 %     basisfun(s, u[col], d, k, N);
                                                %
    tmp1 = s - d + 1;                           %     tmp1 = s - d;
    for row=1:mc                                %     for (row = 0; row < mc; row++)  {
        tmp2 = 0;                               %       tmp2 = 0.0;
        for i=0:d                               %       for (i = 0; i <= d; i++)
           tmp2 = tmp2 + N(i+1)*c(row,tmp1+i);  % 	tmp2 += N[i] * ctrl[tmp1+i][row];
        end                                     %
        p(row,col) = tmp2;                      %       pnt[col][row] = tmp2;
    end                                         %     }
end                                             %   }
                                                %
                                                %   mxFree(N);
                                                %   freevec2mat(pnt);
                                                %   freevec2mat(ctrl);
                                                %
                                                %   return ierr;
                                                %   }


% StackExchange Mathematics Q3892375
% https://math.stackexchange.com/questions/3892375
% Solve Linear Least Squares with L1 Norm Regularization with Linear
% Equality and Non Negativity Constraints.
% References:
%   1.
% Remarks:
%   1.  sa
% TODO:
% 	1.  ds
% Release Notes
% - 1.0.000     27/12/2020
%   *   First release.

%% General Parameters

subStreamNumberDefault = 0;2165;42; %<! Set to 0 for Random

run('InitScript.m');

figureIdx           = 0;
figureCounterSpec   = '%04d';

generateFigures = ON;

%% Parameters

numRows         = 100;
numCols         = 20;
numRowsC        = 80;
numRowsD        = 20;
paramLambda     = 0;

% Solvers parameters
numIterations       = 5000;
stepSizeGd          = 5e-5;
stepSizeMomentum    = 0.8;
stepSizeAccel       = 0.4;

%% Load / Generate Data

mA = randn(numRows, numCols);
mC = randn(numRows, numCols);
mD = randn(numRows, numCols);
vB = randn(numRows, 1);

hObjFun = @(vX) 0.5 * sum((mA * vX - vB) .^ 2) + (paramLambda * sum(abs(mC * vX)));

mAA = mA.' * mA;
vAb = mA.' * vB;
mDD = mD * mD.';
mInvDD = pinv(mDD);

hG = @(vX) (mAA * vX) - vAb + (paramLambda * mD.' * sign(mD * vX)); %<! Gradient of the Objection Function

hP1 = @(vX) vX - (mD.' * mInvDD * (mD * vX)); %<! Projection onto the constraint set
hP2 = @(vX) max(vX, 0); %<! Projection onto the constraint set

hP = @(vX) OrthogonalProjectionOntoConvexSets({hP1; hP2}, vX, 100, 1e-6);

solverIdx       = 0;
cMethodString   = {};

mObjFunValMse   = zeros([numIterations, 1]);
mSolMse         = zeros([numIterations, 1]);

%% Solution by CVX

solverString = 'CVX';

% cvx_solver('SDPT3'); %<! Default, Keep numRows low
% cvx_solver('SeDuMi');
% cvx_solver('Mosek'); %<! Can handle numRows > 500, Very Good!
% cvx_solver('Gurobi');

hRunTime = tic();

cvx_begin('quiet')
% cvx_begin()
    % cvx_precision('best');
    variable vX(numCols, 1);
    minimize( 0.5 * sum_square(mA * vX - vB) + (paramLambda * norm(mC * vX, 1)) );
    subject to
        mD * vX == 0;
        vX >= 0;
cvx_end

runTime = toc(hRunTime);

% vX = mX(:);

disp([' ']);
disp([solverString, ' Solution Summary']);
disp(['The ', solverString, ' Solver Status - ', cvx_status]);
disp(['The Optimal Value Is Given By - ', num2str(hObjFun(vX))]);
disp(['The Optimal Argument Is Given By - [ ', num2str(vX(:).'), ' ]']);
disp(['The Run Time Is Given By - ', num2str(runTime), ' [Sec]']);
disp([' ']);

sCvxSol.vXCvx     = vX;
sCvxSol.cvxOptVal = hObjFun(vX);

%% Solution by Projected Gradient Descent

solverIdx                   = solverIdx + 1;
cLegendString{solverIdx}    = ['Projected Gradient Method'];

hRunTime = tic();

[vX, mX] = ProjectedGd(zeros(numCols, 1), hG, hP, numIterations, stepSizeGd);

runTime = toc(hRunTime);

disp([' ']);
disp([cLegendString{solverIdx}, ' Solution Summary']);
disp(['The Optimal Value Is Given By - ', num2str(hObjFun(vX))]);
disp(['The Optimal Argument Is Given By - [ ', num2str(vX(:).'), ' ]']);
disp(['The Run Time Is Given By - ', num2str(runTime), ' [Sec]']);
disp([' ']);

[mObjFunValMse, mSolMse] = UpdateAnalysisData(mObjFunValMse, mSolMse, mX, hObjFun, sCvxSol, solverIdx);

%% Solution by Projected Gradient Descent with Momentum

solverIdx                   = solverIdx + 1;
cLegendString{solverIdx}    = ['Projected Gradient Descent with Momentum'];

hRunTime = tic();

[vX, ~, mX] = ProjectedGdMomentum(zeros(numCols, 1), zeros(numCols, 1), hG, hP, numIterations, stepSizeGd, stepSizeMomentum);

runTime = toc(hRunTime);

disp([' ']);
disp([cLegendString{solverIdx}, ' Solution Summary']);
disp(['The Optimal Value Is Given By - ', num2str(hObjFun(vX))]);
disp(['The Optimal Argument Is Given By - [ ', num2str(vX(:).'), ' ]']);
disp(['The Run Time Is Given By - ', num2str(runTime), ' [Sec]']);
disp([' ']);

[mObjFunValMse, mSolMse] = UpdateAnalysisData(mObjFunValMse, mSolMse, mX, hObjFun, sCvxSol, solverIdx);

%% Solution by Projected Gradient Descent with Nesterov Acceleration

solverIdx                   = solverIdx + 1;
cLegendString{solverIdx}    = ['Projected Gradient Descent with Nesterov Acceleration'];

hRunTime = tic();

[vX, ~, mX] = ProjectedGdAccel(zeros(numCols, 1), zeros(numCols, 1), hG, hP, numIterations, stepSizeGd, stepSizeAccel);

runTime = toc(hRunTime);

disp([' ']);
disp([cLegendString{solverIdx}, ' Solution Summary']);
disp(['The Optimal Value Is Given By - ', num2str(hObjFun(vX))]);
disp(['The Optimal Argument Is Given By - [ ', num2str(vX(:).'), ' ]']);
disp(['The Run Time Is Given By - ', num2str(runTime), ' [Sec]']);
disp([' ']);

[mObjFunValMse, mSolMse] = UpdateAnalysisData(mObjFunValMse, mSolMse, mX, hObjFun, sCvxSol, solverIdx);

%% Solution by Projected Gradient Descent with FISTA

solverIdx                   = solverIdx + 1;
cLegendString{solverIdx}    = ['Projected Gradient Descent with FISTA Acceleration'];

hRunTime = tic();

[vX, ~, mX] = ProjectedGdFista(zeros(numCols, 1), zeros(numCols, 1), hG, hP, numIterations, stepSizeGd);
% [vX, mX] = SolveLsFista(zeros(numCols, 1), mA, vB, paramLambda, numIterations, stepSizeGd);

runTime = toc(hRunTime);

disp([' ']);
disp([cLegendString{solverIdx}, ' Solution Summary']);
disp(['The Optimal Value Is Given By - ', num2str(hObjFun(vX))]);
disp(['The Optimal Argument Is Given By - [ ', num2str(vX(:).'), ' ]']);
disp(['The Run Time Is Given By - ', num2str(runTime), ' [Sec]']);
disp([' ']);

[mObjFunValMse, mSolMse] = UpdateAnalysisData(mObjFunValMse, mSolMse, mX, hObjFun, sCvxSol, solverIdx);

%% Display Results

figureIdx = figureIdx + 1;

hFigure     = figure('Position', figPosLarge);

hAxes       = subplot(2, 1, 1);
hLineSeries = plot(1:numIterations, 10 * log10(mObjFunValMse));
set(hLineSeries, 'LineWidth', lineWidthNormal);
set(get(hAxes, 'Title'), 'String', ['Objective Function Value vs. Optimal Value (CVX)'], ...
    'FontSize', fontSizeTitle);
set(get(hAxes, 'XLabel'), 'String', 'Iteration Number', ...
    'FontSize', fontSizeAxis);
set(get(hAxes, 'YLabel'), 'String', '$ 10 \log_{10} {\left( \left| f \left( x \right) - f \left( {x}_{CVX} \right) \right| \right)}^{2} $', ...
    'FontSize', fontSizeAxis, 'Interpreter', 'latex');
set(hAxes, 'XLim', [1, numIterations]);
hLegend = ClickableLegend(cLegendString);

hAxes       = subplot(2, 1, 2);
hLineSeries = plot(1:numIterations, 10 * log10(mSolMse));
set(hLineSeries, 'LineWidth', lineWidthNormal);
set(get(hAxes, 'Title'), 'String', ['Solution Error Norm'], ...
    'FontSize', fontSizeTitle);
set(get(hAxes, 'XLabel'), 'String', 'Iteration Number', ...
    'FontSize', fontSizeAxis);
set(get(hAxes, 'YLabel'), 'String', '$ 10 \log_{10} \left( {\left\| x - {x}_{CVX} \right\|}_{2}^{2} \right) $', ...
    'FontSize', fontSizeAxis, 'Interpreter', 'latex');
set(hAxes, 'XLim', [1, numIterations]);
hLegend = ClickableLegend(cLegendString);

if(generateFigures == ON)
    % saveas(hFigure,['Figure', num2str(figureIdx, figureCounterSpec), '.png']);
    print(hFigure, ['Figure', num2str(figureIdx, figureCounterSpec), '.png'], '-dpng', '-r0'); %<! Saves as Screen Resolution
end

%% Restore Defaults

% set(0, 'DefaultFigureWindowStyle', 'normal');
% set(0, 'DefaultAxesLooseInset', defaultLoosInset);


function w = WeightTransform_Morgan(W,N,D,Ms)

% WeightTransform_Morgan    Mapping of Subband Adaptive Filters Coefficients to
%                           Full-band Filter
%
% Weight transformation by Morgan and Thi (See Section 4.4.3.1)
%
% Arguments:
% W            Tap-weights for subbands i = 0,1,...,(N/2) in each column
% N            Number of subbands
% Ms           Length of adaptive subfilters
%
% by Lee, Gan, and Kuo, 2008
% Subband Adaptive Filtering: Theory and Implementation
% Publisher: John Wiley and Sons, Ltd

w = zeros(Ms*D,1);                    % Setup fullband weight vector

Ms = Ms*2;                            % Zero padding
G = fft(W,Ms);                        % Ms-point FFT on (N/2)+1 adaptive subfilters

% Weight trasformation for 2x-oversampling

if D == N/2                           % For 2x-oversampling

% or subband from i = 1,2,...,(N/2)-1, where i is the subband index

    X = zeros(Ms/2,N/2-1);
	for i = 1:2:(N/2-1)           % For i is an odd number
        x = reshape(G(:,i+1),Ms/4,4);
        x = [x(:,2); x(:,3)];
        X(:,i) = x;
	end
	for i = 2:2:(N/2-1)           % For i is an even number
        x = reshape(G(:,i+1),Ms/4,4);
        x = [x(:,4); x(:,1)];
        X(:,i) = x;
	end
    X = X(:);

    i = 0;   x = reshape(G(:,i+1),Ms/4,4); X = [x(:,1); X];

    i = N/2;
    if mod(i,2)==0                    % For N/2 is even, eg. N = 8, 16 subbanbs
        x = reshape(G(:,i+1),Ms/4,4); X = [X; x(:,4)];
    else                              % For N/2 is odd, eg. N = 10 subbands
        x = reshape(G(:,i+1),Ms/4,4); X = [X; x(:,2)];
    end

    X = [X; 0; conj(flipud(X(2:end)))];
    x = real(ifft(X));                % Ms*D-point ifft
    w = x(1:(Ms/2)*D);

end

% Weight trasformation for critical subsampling

if D == N                             % if critical subsampling

% For subbands from i = 1,2,...,(N/2)-1, where i is the subband index

    X = zeros(Ms,N/2-1);
	for i = 1:(N/2-1)
        x = reshape(G(:,i+1),Ms/2,2);
        x = [x(:,2); x(:,1)];
        X(:,i) = x;
	end
    X = X(:);

    i = 0;   x = reshape(G(:,i+1),Ms/2,2); X = [x(:,1); X];
    i = N/2; x = reshape(G(:,i+1),Ms/2,2); X = [X; x(:,2)];

    X = [X; 0; conj(flipud(X(2:end)))];
    x = real(ifft(X));                % Ms*D-point ifft
    w = x(1:(Ms/2)*D);

end


function mu = imCSMoment(img, p, q, varargin)
% Compute centered and scaled moments of an image.
%
%   MU = imCSMoment(IMG, P, Q)
%   compute (p+q)-th centered moment of image IMG.
%
%   MU = imCSMoment(IMG, P, Q, CENTER, MASS)
%   where CENTER = [CX CY], provides pre-computed center of mass.
%
%   Example
%   imCMoment
%
%   See also
%     imMoment, imCMoment, imEquivalentEllipse

% ------
% Author: David Legland
% e-mail: david.legland@inrae.fr
% Created: 2008-10-08,    using Matlab 7.4.0.287 (R2007a)
% Copyright 2008 INRA - BIA PV Nantes - MIAJ Jouy-en-Josas.

% get the centroid, either by argument, or by computation
if ~isempty(varargin)
    var = varargin{1};
    if length(var)>1
        cx = var(1);
        cy = var(2);
        varargin(1) = [];
    else
        cx = var;
        cy = varargin{2};
        varargin(1:2) = [];
    end
else
    s = sum(img(:));
    cx = imMoment(img, 1, 0)/s;
    cy = imMoment(img, 0, 1)/s;
end

if ~isempty(varargin)
    m00 = varargin{1};
else
    m00 = sum(img(:));
end

% image dimension
dim = size(img);
Dy = dim(1);
Dx = dim(2);

% compute x and y for each pixel
Ix = repmat((1:Dx), [Dy 1])-cx;
Iy = repmat((1:Dy)', [1 Dx])-cy;

% compute moment
mu = zeros(size(p));
for i = 1:length(p(:))
    d = (p(i)+q(i)) / 2 + 1;
    mu(i) = sum(Ix(:).^p(i) .* Iy(:).^q(i) .* img(:)) / m00^d;
end


function variance = chi_square_variance ( a )

%*****************************************************************************80
%
%% CHI_SQUARE_VARIANCE returns the variance of the central Chi squared PDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 September 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real A, the parameter of the distribution.
%    1 <= A.
%
%    Output, real VARIANCE, the variance of the PDF.
%
  variance = 2.0 * a;

  return
end


function [P, lam] = pswf(N, c, dom, output_type)
%PSWF   Prolate spheroidal wave functions.
% P = PSWF(N, C) returns a CHEBFUN P representing the Nth prolate spheroidal
% wave function with bandwidth C on the interval [-1,1], i.e., the Nth
% eigenfunction of the differential eigenvalue problem
%
%    [(1-x^2)*P(x)')' + (LAM - C^2*x^2)*P(x) = 0,
%
% with N = 0,1,2,....  C must be a positive scalar but N may be a vector of
% non-negative integers, in which case the output is an array-valued CHEBFUN
% with LENGTH(N) columns. P is scaled so that P'*P = 2/(2N+1), with the sign
% such that sign(P(0)) = (-1)^(N/2) if N is even and sign(P'(0)) =
% (-1)^((N-1)/2) if N is odd (see [3], eq. (30.4.1)).
%
% [P, LAM] = PSWF(N, C) also returns the eigenvalue(s).
%
% Examples:
%    f = pswf(2,pi); f(0.3)
%    plot(pswf(0:2:6, 100))
%
% [1] H. Xiao, V. Rokhlin and N. Yarvin, Prolate spheroidal wavefunctions,
% quadrature and interpolation, Inverse Problems, 17 (2001), 805-838.
%
% [2] https://reference.wolfram.com/language/ref/SpheroidalPS.html
%
% [3] https://dlmf.nist.gov/30.4
%
% See also PSWFPTS, LEGPOLY.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Developer note: The approach is to compute the (approximate) normalised
% Legendre coefficients of the PSWFs by solving an eigenvalue problem [1].
% The Legendre coefficients are then converted to Chebyshev via LEG2CHEB,
% and a Chebfun constructed.
%
% There is functionality for scaling the domain, but this is currently
% undocumented, since we are not sure at present whether this choice
% is the right one.
%
% Copyright 2020 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Defaults:
if ( nargin < 3 )
    dom = [-1 1];
    output_type = 'chebfun';
end
if ( nargin == 3 )
    if ( isnumeric(dom) )
        output_type = 'chebfun';
    else
        output_type = dom;
        dom = [-1 1];
    end
end

% Parse inputs:
assert( nargin >= 2, 'PSWF requires at least two input arguments.')
assert( all(round(N)==N) && all(N>=0) && isvector(N), ...
    'Input N must be vector of non-negative integers.');
assert( (numel(c)==1) && (c>0) , ...
    'Input C must be a positive scalar.');
assert( numel(dom)==2 && all(isfinite(dom)) , ...
    'Domain must be a finite two-vector.');

% Set discretisation size. Heuristic estimates for initialisation.
M = max(ceil([2*sqrt(c)*N, 2*c, 20]));

% Increase discretisation size until the trailing Legendre coefficients are
% sufficiently small:
ishappy = 0;
tol = eps;
count = 0;

while ( ~ishappy )

    % Construct the matrix (see Xiao et al):
    j = (0:M).';
    Asub = c^2*j.*(j-1)./((2*j-1).*sqrt((2*j-3).*(2*j+1)));
    Adia = j.*(j+1) + c^2*(2*j.*(j+1)-1)./((2*j+3).*(2*j-1));
    Asup = c^2*(j+2).*(j+1)./((2*j+3).*sqrt((2*j+5).*(2*j+1)));
    A = diag(Asub(3:end), -2) + diag(Adia, 0) + diag(Asup(1:end-2), 2);

    % Split in to even and odd parts for efficiency/accuracy.
    Ae = A(1:2:end,1:2:end);
    Ao = A(2:2:end,2:2:end);

    % Compute (sorted) eigenvectors:
    [Ve, De] = eig(Ae);
    [lame, idx] = sort(diag(De), 'ascend');
    Ve = Ve(:,idx);
    [Vo, Do] = eig(Ao);
    [lamo, idx] = sort(diag(Do), 'ascend');
    Vo = Vo(:,idx);

    % Reassemble full V and eigenvalues:
    V = zeros(M+1,M+1);
    V(1:2:end,1:2:end) = Ve;
    V(2:2:end,2:2:end) = Vo;
    lam = zeros(M+1,1);
    lam(1:2:end) = lame;
    lam(2:2:end) = lamo;

    % Check discretisation size was large enough;
    ishappy = sum(abs(V(end-3:end,N+1)))/(2*length(N)) < tol;
    if ( ~ishappy )
        M = 2*M;
    end

    % Failsafe:
    count = count + 1;
    if ( count > 10 )
        break
    end

end

% Extract required columns and unnormalise the Legendre coeffients:
V = bsxfun(@times, V(:,N+1), sqrt((0:M)'+1/2) );
lam = lam(N+1);

% Trim trailing coefficients that are below machine precision:
M = max(abs(V), [], 2);
idx = find(M > eps, 1, 'last');
V = V(1:idx,:);

% Scale as per Wolfram Alpha definition [1]:
V = (1./sqrt(N+0.5)).*V;

%%

% Enforce P_N(0) > 0 for N even and P'_N(0) > 0 for N odd.
m = 0:(idx-1)/2; idx = ~mod(N,2);
if ( any(idx) )
    L0 = (-1).^m./(beta(m,.5).*m); L0(1) = 1;
    V0 = L0*V(1:2:end,idx);
    currentSign = sign(V0);
    desiredSign = 1 - mod(N(idx),4);
    scl = currentSign.*desiredSign;
    V(:,idx) = scl.*V(:,idx);
end
if ( ~all(idx) )
    Lp0 = 2*(-1).^m./beta(m+1,.5); Lp0 = Lp0(1:length(V(2:2:end,1)));
    Vp0 = Lp0*V(2:2:end,~idx);
    currentSign = sign(Vp0);
    desiredSign = 1 - mod(N(~idx)-1,4);
    scl = currentSign.*desiredSign;
    V(:,~idx) = scl.*V(:,~idx);
end

% Quit now if only coefficients are required:
if ( strcmpi(output_type, 'coeffs') )
    P = V;
    return
end

% Convert Legendre coeffs to Chebyshev coeffs:
W = leg2cheb(V);

% Enforce even/oddness (which is lost in leg2cheb):
idx = logical(mod(N,2));
W(1:2:end,idx) = 0;
W(2:2:end,~idx) = 0;

% Create a Chebfun from the Chebyshev  coefficients:
P = chebfun(W, dom, 'coeffs');

% The coefficients are trimmed in V, so simplifying should not be necessary.
% P = simplify(P);

end


function [x, y, z] = torus (a, n, r, kpi)
% TORUS Generate a torus.
% torus (r, n, a, kpi) generates a plot of a
% torus with central radius a and
% lateral radius r.
% n controls the number of facets
% on the surface.
% kpi makes it possible to draw a whole torus,
% or e.g. half of it.
%
% This script is a modification of a
% program from:

% MATLAB Primer, 6th Edition
% Kermit Sigmon and Timothy A. Davis
% Section 11.5, page 65.

theta = -pi * (0:2:kpi*n)/n ;
phi = 2*pi* (0:2:n)'/n ;
x = (a + r*cos(phi)) * cos(theta) ;
y = (a + r*cos(phi)) * sin(theta) ;
z = r * sin(phi) * ones(size(theta)) ;


function corr_coef = RegreesionLIVE(objectiveValues,mos)
%this script is used to calculate the pearson linear correlation
%coefficient and root mean sqaured error after regression

%get the objective scores computed by the IQA metric and the subjective
%scores provided by the dataset
% matData = load('VSIOnLIVE.mat');
% VSIOnLIVE = matData.VSIOnLIVE;
% objectiveValues = VSIOnLIVE(:,1);
% mos = VSIOnLIVE(:,2);

%plot objective-subjective score pairs
% p = plot(objectiveValues,mos,'+');
% set(p,'Color','blue','LineWidth',1);

%initialize the parameters used by the nonlinear fitting function
beta(1) = max(mos);
beta(2) = min(mos);
beta(3) = mean(objectiveValues);
beta(4) = 0.1;
beta(5) = 40;

%fitting a curve using the data
[bayta ehat,J] = nlinfit(objectiveValues,mos,@logistic,beta);
%given a ssim value, predict the correspoing mos (ypre) using the fitted curve
[ypre junk] = nlpredci(@logistic,objectiveValues,bayta,ehat,J);

RMSE = sqrt(sum((ypre - mos).^2) / length(mos));%root meas squared error
corr_coef = corr(mos, ypre, 'type','Pearson'); %pearson linear coefficient

%draw the fitted curve
% t = min(objectiveValues):0.01:max(objectiveValues);
% [ypre junk] = nlpredci(@logistic,t,bayta,ehat,J);
% hold on;
% p = plot(t,ypre);
% set(p,'Color','black','LineWidth',2);
% legend('Images in LIVE','Curve fitted with logistic function', 'Location','NorthEast');
% xlabel('Objective score by VSI');
% ylabel('MOS');


function [ result, seed ] = sphere01_quad_mc ( f, h, seed, n )

%*****************************************************************************80
%
%% SPHERE01_QUAD_MC uses the Monte Carlo rule for sphere quadrature.
%
%  Discussion:
%
%    A number of points N are chosen at random on the sphere, with N
%    being determined so that, if the points were laid out on a regular
%    grid, the average spacing would be no more than H.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 September 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, function v = F ( n, x ), evaluates the integrand.
%
%    Input, real H, the maximum length of a side of the spherical
%    quadrilaterals.
%
%    Input/output, integer SEED, a seed for the random
%    number generator.
%
%    Input, integer N, the number of points to use.
%
%    Output, real RESULT, the approximate integral.
%
  sphere_area = 4.0 * pi;

  [ x, seed ] = sphere01_sample_3d ( n, seed );

  v = f ( n, x )

  result = sphere_area * sum ( v(1:n) ) / n;

  return
end


function [ T, W ] = rd_lin_spline ( w0, t_array, n, c_array )

%*****************************************************************************80
%
%% RD_LIN_SPLINE discretizes and solves a 1D reaction diffusion problem.
%
%  Discussion:
%
%    The problem includes homogeneous Neumann boundary conditions at both ends.
%
%    The dynamics are given by the following reaction/diffusion equation
%    for the function W(T,X):
%
%      W_t = W_xx + NL(W,c),
%
%    where NL(W,c) is a polynomial in W:
%
%       NL(W,c) = c(1) + c(2) * W + c(3) * W^2 + c(4) * W^3
%
%    with Neumann boundary conditions at X = 0.0 and X = 1.0:
%
%      W_x(T,0.0) = 0.0
%      W_x(T,1.0) = 0.0
%
%    and initial condition at T = 0.0:
%
%      W(0,X) = sin ( pi * X ).
%
%    The problem is to be solved for 0.0 <= T <= 4.0, 0.0 <= X <= 1.0.
%
%    We use a finite element approximation with piecewise linear "hat"
%    functions. The resulting ODE model is:
%
%      M * w-dot(t) = - K * w(t) + NL(w, c)
%
%    where M is the mass matrix, K the stiffness matrix, and NL the nonlinear
%    term.
%
%      NL(w, c_array)=c_array(1)+ c_array(2)*w + c_array(3)*w^2 + c_array(4)*w^3
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    05 April 2011
%
%  Author:
%
%   Eugene Cliff
%
%  Reference:
%
%    Jeffrey Borggaard, John Burkardt, John Burns, Eugene Cliff,
%    Working Notes on a Reaction Diffusion Model: a Finite Element Formulation.
%
%  Parameters:
%
%    w0     - handle to initial function (on [0, 1])
%
%    t_array- array of times for output
%
%    n      - grid  parameter ( > 2)
%
%    c_array- coefficients in nonlinear term
%

%
%  Assemble the mass matrix.
%
    M = spdiags([ones(n+1,1) [2;4*ones(n-1,1);2] ones(n+1,1)], ...
                                                 [-1 0 1], n+1, n+1)/(6*n);
%
%  Assemble the stiff matrix.
%
    K = n*spdiags([-ones(n+1,1) [1;2*ones(n-1,1);1] -ones(n+1,1)], ...
                                                 [-1 0 1], n+1, n+1);
%
%  Set the initial condition.
%
   wr  = zeros(n+1,1);
   h_wr = @(x) w0(x).*basic_hat(n*x );
   wr(1) = quad(h_wr, 0, 1/n);                    % < w_0, \phi_1 >
   h_wr = @(x) w0(x).*basic_hat(n*x - n);
   wr(n+1) = quad(h_wr, (n-1)/n, 1);              % < w_0, \phi_n+1 >
   for jj=2:n
      h_wr = @(x) w0(x).*basic_hat(n*x + 1 - jj);
      wr(jj) = quad(h_wr, (jj-2)/n, jj/n);        % < w_0, \phi_i >
   end

   w_0 = M \ wr;

   ODE_opt = odeset('Mass', M);                  % constant mass matrix
   h_rhs = @(t, w) -K*w  + NL(w, c_array, n, M); % handle for rhs function

   [T, W] = ode15s(h_rhs, t_array, w_0, ODE_opt);% invoke ODE solver

  return
end
function val = NL (w, c, n, M )

%*****************************************************************************80
%
%% NL evaluates the nonlinear term in the reaction-diffusion equation.
%
      val = (c(1)/n)* [1; 2*ones(n-1,1); 1] ... % constant
          +  c(2) * M * w     ...               % linear
          +  c(3) * Nq(w, n)  ...               % quadratic
          +  c(4) * Nc(w, n) ;                  % cubic

  return
end
function val = Nq(w, n)

%*****************************************************************************80
%
%% NQ evaluates a quadratic nonlinear finite element function.
%
     w2 = w(:).^2; wx = (w(1:end-1,1)+ w(2:end,1)).^2;

     val = [2*w2(1)+wx(1); wx(1:end-1)+4*w2(2:end-1)+wx(2:end) ; ...
                                                 wx(end)+2*w2(end)]/(12*n);

  return
end
function val = Nc(w, n)

%*****************************************************************************80
%
%% NC evaluates a cubiic nonlinear finite element function.
%
     w2 = w(:).*w(:); w3 = w(:).*w2(:); wx = (w(1:end-1,1)+w(2:end,1)).^3;

     val = [3*w3(1)+wx(1)-w(1)*w(2)^2;
   wx(1:end-1)+6*w3(2:end-1)+wx(2:end)-w(2:end-1).*(w2(1:end-2)+w2(3:end));
                               wx(end)+3*w3(end)-w(end)*w(end-1)^2]/(20*n);

  return
end


function trans = createTranslation(varargin)
%CREATETRANSLATION Create the 3*3 matrix of a translation.
%
%   TRANS = createTranslation(DX, DY);
%   Returns the translation corresponding to DX and DY.
%   The returned matrix has the form :
%   [1 0 TX]
%   [0 1 TY]
%   [0 0  1]
%
%   TRANS = createTranslation(VECTOR);
%   Returns the matrix corresponding to a translation by the vector [x y].
%
%
%   See also
%   transforms2d, transformPoint, createRotation, createScaling

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

% process input arguments
if isempty(varargin)
    tx = 0;
    ty = 0;
elseif length(varargin)==1
    var = varargin{1};
    tx = var(1);
    ty = var(2);
else
    tx = varargin{1};
    ty = varargin{2};
end

% create the matrix representing the translation
trans = [1 0 tx ; 0 1 ty ; 0 0 1];


function [] = draw_crystal_lattice
% File:      draw_crystal_lattice.m
% Author:    Ioannis Filippidis, jfilippidis@gmail.com
% Date:      2011.01.30 -
% Language:  MATLAB R2012a
% Purpose:   draw crystal lattices
% Copyright: Ioannis Filippidis, 2011-

selection = 'diamond'; % 'diamond', 'copper'

a = 1;
c = a /4;

r_diamond_cubic = c *[0, 0, 0;
        2, 0, 0;
        0, 2, 0;
        2, 2, 0;
        1, 1, 0; %
        1, 0, 1;
        0, 1, 1;
        1, 2, 1;
        2, 1, 1; %
        0, 0, 2;
        2, 0, 2;
        0, 2, 2;
        2, 2, 2;
        1, 1, 2; %
        0.5, 0.5, 0.5;
        1.5, 1.5, 0.5;
        0.5, 1.5, 1.5;
        1.5, 0.5, 1.5]';

r_fcc = c *[0, 0, 0;
        2, 0, 0;
        0, 2, 0;
        2, 2, 0;
        1, 1, 0; %
        1, 0, 1;
        0, 1, 1;
        1, 2, 1;
        2, 1, 1; %
        0, 0, 2;
        2, 0, 2;
        0, 2, 2;
        2, 2, 2;
        1, 1, 2]'; %

i_diamond_cubic =[15, 1;
     15, 5;
     15, 6;
     15, 7; %
     16, 5;
     16, 4;
     16, 8;
     16, 9; %
     17, 7;
     17, 12;
     17, 14;
     17, 8; %
     18, 6;
     18, 9;
     18, 14;
     18, 11];
%

i_fcc = [1, 2;
    2, 4;
    2, 3;
    1, 3;
    1, 4;
    3, 4; %
    1, 10;
    2, 10;
    2, 11;
    1, 11;
    10, 11; %
    3, 12;
    4, 13;
    12, 13;
    4, 12;
    3, 13; %
    10, 12;
    10, 13;
    13, 11;
    12, 11;
    1, 12;
    3, 10; %
    2, 13;
    4, 11];

switch selection
    case 'diamond'
        r = r_diamond_cubic;
        i1 = i_diamond_cubic;
    case 'copper'
        r = r_fcc;
        i1 = i_fcc;
    otherwise
        disp('Unknown material selection.')
end

ax = newax;
hold(ax, 'on')
for i=1:size(r, 2)
    h = drawSphere(r(:, i), 0.05);
    set(h, 'FaceColor', 'r')
end
grid(ax, 'on')
box(ax, 'on')
axis(ax, 'equal')
axis(ax, 'tight')
view(ax, 3)
%maximize(get(ax, 'Parent') )

for i=1:size(i1, 1)
    a = i1(i, 1);
    b = i1(i, 2);
    drawCylinder([r(:, a)', r(:, b)', 0.01] )
end

fname = selection;
fig2u3d(gca, fname, '-pdf');


function a_cum = r8vec_cum0 ( n, a )

%*****************************************************************************80
%
%% R8VEC_CUM0 computes the cumulutive sums of an R8VEC.
%
%  Example:
%
%    Input:
%
%      A = (/ 1.0, 2.0, 3.0, 4.0 /)
%
%    Output:
%
%      A_CUM = (/ 0.0, 1.0, 3.0, 6.0, 10.0 /)
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    07 May 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of entries in the vector.
%
%    Input, real A(N), the vector to be summed.
%
%    Output, real A_CUM(1:N+1), the cumulative sums.
%
  a_cum(1) = 0.0;

  for i = 1 : n
    a_cum(i+1) = a_cum(i) + a(i);
  end

  return
end