%% Examples of Numerical Solutions of PDEs
% We shall use a sequence of examples to introduce basic components of
% numerical solutions of PDEs.

%% Smooth solutions on regular domains
% We solve the Poisson equation $-\Delta u =1$ in the unit square $\Omega =
% (0,1)\times (0,1)$ with homogenous Dirichlet boundary condition
% $u|_{\partial \Omega}=0$ using linear finite element discrization on a
% sequence of uniform and structured grids.

close all; clear all
figure(1); set(gcf,'Units','normal'); set(gcf,'Position',[0,0,0.45,0.3]);
node = [0,0; 1,0; 1,1; 0,1];    % nodes
elem = [2,3,1; 4,1,3];          % elements
subplot(1,3,1); showmesh(node,elem)
[node,elem] = uniformrefine(node,elem);
subplot(1,3,2); showmesh(node,elem)
[node,elem] = uniformrefine(node,elem);
subplot(1,3,3); showmesh(node,elem)

%%
squarePoisson
% See squarePoisson for details of computation.

%% Smooth solutions on irregular domains
% We solve the Poisson equation in a Lake-type domain. This example shows
% the flexibility of FEM to complex domains.

load lakemesh
f = inline('ones(size(x,1),1)');    % right hand side
g_D = inline('zeros(size(x,1),1)'); % Dirichlet boundary condition
u = Poisson(node,elem,[],f,g_D,[]); % Poisson equation
% graphic
figure(1); set(gcf,'Units','normal'); set(gcf,'Position',[0,0,0.45,0.3]);
subplot(1,2,1); showmesh(node,elem); pause(0.05)
subplot(1,2,2); showsolution(node,elem,u,[0,90]);axis equal; colorbar;

%% Tutorial of iFEM

%% Features of iFEM
%
% * Simple data structures
% * Mesh adaptation in two- and three-dimensions
% * Fast solvers of algebraic equations
% * Easy to use, Easy to code, Easy to debug
% * Efficient programming

%% Basic Data Stucture
%
% *Mesh: 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 $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:d+1)| are the global indices of |d+1| vertices which form the
% abstract $d$-simplex |t|. 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.
%
% Related functions: <matlab:doc('fixorientation') fixorientation>,
% <matlab:doc('label') label>, <matlab:doc('label3') label3>
%
% Documentation: <matlab:ifemdoc('meshdoc') meshdoc>

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];
elem = [1,2,8; 3,8,2; 8,3,5; 4,5,3; 7,8,6; 5,6,8];
figure(1)
showmesh(node,elem)
axis on
findnode(node)
findelem(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];
figure(2)
showmesh3(node,elem,[],'FaceAlpha',0.25);
view([-53,8]);
axis on
findnode3(node)
findelem3(node,elem)

%%
% *Boundary: bdEdge or bdFace.*
%
% For 2-D triangulations, we use |bdEdge(1:NT,1:3)| to record the type of
% three edges of each element. Similarly in 3-D, we use |bdFace(1:NT,1:4)|
% to record the type of four faces of each element.
% The value is the type of boundary condition listed as follows.
%
% * 0: non-boundary, i.e., an interior edge or face.
% * 1: first type, i.e., a Dirichlet boundary edge or face.
% * 2: second type, i.e., a Neumann boundary edge or face.
% * 3: third type, i.e., a Robin boundary edge or face.
%
% We label three edges of a triangle such that |bdEdge(t,i)| is the edge
% opposite to the i-th vertex. Similarly |bdFace(t,i)| is the face opposite
% to the i-th vertex.
%
% Related functions: <matlab:doc('findboundary') findboundary>,
% <matlab:doc('setboundary') setboundary>, <matlab:doc('findboundary3') findboundary3>
% <matlab:doc('setboundary3') setboundary3>.
%
% Documentation: <matlab:ifemdoc('bddoc') bddoc>

node = [1,0; 1,1; 0,0];
elem = [1 2 3];
edge = [2 3; 1 3; 1 2];
subplot(1,2,1);
showmesh(node,elem);
findedge(node,edge);
findnode(node);
node = [1,1,1; 0,0,0; 1,1,0; 1,0,0];
elem = [1,2,3,4];
subplot(1,2,2);
showmesh3(node,elem,[],'FaceAlpha',0.35); view([-10,18]);
findnode3(node);
findelem3(node,[2,3,4; 1,3,4; 1,2,4; 1,2,3])

%% Finite Element Method
%
%
%%
% * Example 1: The Poisson equation in 2-D
% * Example 2: The Poisson equation: complex domains
% * Example 2: The Poisson equation in 3-D with multigrid solvers

%% Adaptive Finite Element Method
%
%
%%
% * Example 1: The Poisson equation on a 2-D L-shaped domain
% * Example 2: The Poisson equation in 3-D with jump diffusion coefficients

%% Time-dependent Problems
%%
% * Example 1: Heat equation
% * Example 2: Moving interface


function [node,elem] = cubehexmesh(cube,h)
%% CUBEHEXMESH uniform mesh of cube
%
% [node,elem] = cubehexmesh([x0,x1,y0,y1,z0,z1],h) generates a uniform
% cubic mesh of the cube [x0,x1]*[y0,y1]*[z0,z1] with mesh size h.
%
% Example
%  [node,elem] = cubehexmesh([0 1 0 2 0 3],0.5);
%
% See also: squarequadmesh, cubehexgradmesh
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

x0 = cube(1); x1 = cube(2);
y0 = cube(3); y1 = cube(4);
z0 = cube(5); z1 = cube(6);
[z,x,y] = ndgrid(z0:h:z1,x0:h:x1,y0:h:y1);
node = [x(:),y(:),z(:)];
% findnode3(node); view([83 10]);

%% Generate elements
ni = size(x,1); % number of rows
nj = size(x,2); % number of columns
nk = size(x,3); % number of pages
nij = ni*nj;    % number of elements in one page
N = size(node,1);
nodeidx = reshape(1:N,ni,nj,nk);
t2nidxMap = nodeidx(1:ni-1,1:nj-1,1:nk-1);
s = t2nidxMap(:);
elem = [s s+ni s+ni+nij s+nij s+1 s+ni+1 s+ni+nij+1 s+nij+1];
% s+1 s+ni*nj
%  | /
%  s - s + ni


function K = curvature_2D(X,Y,degree)
% CURVATURE_2D estimate curvature of a curve defined by points
%
%   K = CURVATURE_2D(X, Y, DEGREE)
%
%   DEGREE is the degree of the polynom used for the interpolation
%

%
%   Created by Alexandre Gramfort on 2008-12-15.
%   Copyright (c) 2007 Alexandre Gramfort. All rights reserved.
%

% $Id: curvature_2D.m 2 2009-06-16 19:24:10Z gramfort $
% $LastChangedBy: gramfort $
% $LastChangedDate: 2009-06-16 15:24:10 -0400 (Mar, 16 jui 2009) $
% $Revision: 2 $

if nargin<3
    % default values
    degree = 5; % degree of polynum used for interpolation
end

% Find a parametrization of the curve
t = cumsum(sqrt(diff(X).^2 + diff(Y).^2));
t = [0,t];
t = t / t(end); % normalize between 0 and 1

% compute coefficients of interpolation functions
x0 = polyfit(t, X, degree);
y0 = polyfit(t, Y, degree);

% compute coefficients of first and second derivatives. In the case of a
% polynom, it is possible to compute coefficient of derivative by
% multiplying with a matrix.
derive = diag(degree:-1:0);
xp = circshift(x0*derive, [0 1]);
yp = circshift(y0*derive, [0 1]);
xs = circshift(xp*derive, [0 1]);
ys = circshift(yp*derive, [0 1]);

% compute values of first and second derivatives for needed points
xprime = polyval(xp, t);
yprime = polyval(yp, t);
xsec = polyval(xs, t);
ysec = polyval(ys, t);

% compute value of curvature
K = (xprime.*ysec - xsec.*yprime)./ ...
    power(xprime.*xprime + yprime.*yprime, 3/2);


% Return the total number of edges given the adjacency matrix
% INPUTs: adjacency matrix, nxn
% OUTPUTs: m - total number of edges/links
%
% Note: Valid for both directed and undirected, simple or general graph
% Other routines used: selfLoops.m, isSymmetric.m
% GB, last updated Sep 19, 2012

function m = numEdges(adj)

sl=selfLoops(adj); % counting the number of self-loops

if isSymmetric(adj) && sl==0    % undirected simple graph
    m=sum(sum(adj))/2;

elseif isSymmetric(adj) && sl>0
    m=(sum(sum(adj))-sl)/2+sl; % counting the self-loops only once

elseif not(isSymmetric(adj))   % directed graph (not necessarily simple)
    m=sum(sum(adj));

end


%% Example A.1: Linear Advection in a Periodic Domain
%
% The linear advection problem with periodic boundary conditions
%
% $$u_t + u_x = 0, \qquad u(x,0)=u_0(x), \qquad u(0,t)=u(1,t)$$
%
% is well suited for studying error mechanisms in numerical schemes for
% hyperbolic conservation laws. In particular, to study dissipative and
% oscillatory errors, we will use initial data consisting of a combination
% of a smooth, squared cosine wave and double step function.

%%
% We consider two first-order methods (Lax-Friedrichs and the upwind
% method) and two second-order methods (Lax-Wendroff and MacCormack)
T  = 10;
N  = 100; h=1/N; x=h*(1:N);
u0 = (abs(x-.25)<=0.15).*(cos(pi*(10/3)*(x-0.25))).^2 + ...
   1.0*(abs(x-0.75)<0.15);
xx  = linspace(0,1,1001);
uf  = (abs(xx-.25)<=0.15).*(cos(pi*(10/3)*(xx-0.25))).^2 + ...
   1.0*(abs(xx-0.75)<0.15);

method = {'LxF', 'upwind', 'LxW', 'McC'};
name   = {'Lax-Friedrichs', 'Upwind', 'Lax-Wendroff', 'MacCormack'};
for i=1:4
   u=finvol('linearfunc',u0,T,h,1,'periodic',method{i},.9);
   subplot(2,2,i);
   plot(xx,uf,'-',x,u,'o','MarkerSize',2); axis([0 1 -0.2 1.3]);
   title(name{i});
end
%%
% We see that the two first-order schemes smear both the smooth part and
% the discontinuous path of the advected profile and that the
% Lax-Friedrichs method is more diffusive than the upwind method. The
% second-order schemes, on the other hand, preserve the smooth profile
% quite accurately, but introduce spurious oscillations around the two
% discontinuities.


function v = r8vec_house_column ( n, a, k )

%*****************************************************************************80
%
%% R8VEC_HOUSE_COLUMN defines a Householder premultiplier that "packs" a column.
%
%  Discussion:
%
%    The routine returns a vector V that defines a Householder
%    premultiplier matrix H(V) that zeros out the subdiagonal entries of
%    column K of the matrix A.
%
%       H(V) = I - 2 * v * v'
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 April 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of the matrix A.
%
%    Input, real A(N), column K of the matrix A.
%
%    Input, integer K, the column of the matrix to be modified.
%
%    Output, real V(N), a vector of unit L2 norm which defines an
%    orthogonal Householder premultiplier matrix H with the property
%    that the K-th column of H*A is zero below the diagonal.
%
  v(1:n) = 0.0;

  if ( k < 1 | n <= k )
    return
  end

  s = sqrt ( sum ( a(k:n).^2 ) );

  if ( s == 0.0 )
    return
  end

  v(k) = a(k) + abs ( s ) * r8_sign ( a(k) );
  v(k+1:n) = a(k+1:n);

  v(k:n) = v(k:n) / sqrt ( v(k:n).^2 );

  return
end


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

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

for iter = 1:num_iters

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

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

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

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

end

end


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

% Fourier Series properties

%time shifting

t0=0;
T=10;
w=2*pi/T;
syms t
x=t*exp(-5*t)
k=-5:5;
a=(1/T)*int(x*exp(-j*k*w*t),t,t0,t0+T);
a1=eval(a);
subplot(211);
stem(k,abs(a1));
title(' Coefficients of x(t)=te^-^5^t');
legend('Magnitude');
subplot(212);
stem(k,angle(a1));
legend('Angle');

figure
t1=3;
right= exp(-j*k*w*t1).*a;
right =eval(right);
subplot(211);
stem(k,abs(right));
legend('Magnitude');
title('Right part');
subplot(212);
stem(k,angle(right));
legend('Angle');

figure
x=(t-t1).*exp(-5*(t-t1));
a=(1/T)*int(x*exp(-j*k*w*t),t,t0+t1,t0+T+t1);
coe=eval(a);
subplot(211);
stem(k,abs(coe));
legend('Magnitude');
title(' Coefficient of (t-3)exp(-5(t-3)) ');
subplot(212);
stem(k,angle(coe));
legend('Angle');


function allCombos=genAllCapacitatedCombos(numPerBin,numBins,totalItems)
%%GENALLCAPACITATEDCOMBOS Given totalItems items, generate all combinations
%               combinations of placing the items into numBins unlabeled
%               bins where each bin can hold numPerBin items. If
%               numPerBin=1, then this is just generating standard
%               combinations of numBins items taken from a total of
%               totalItems. The capacitated combinations are equivalent to
%               putting totalItems labeled balls into numBins unlabeled
%               bins such that each bin holds numPerBin items and the
%               ordering of the items in the bins does not matter.
%
%INPUTS: numPerBin The scalar integer capacity of the bins; numPerBin>=1.
%          numBins The scalar integer number of bins; numBins>=1.
%       totalItems The scalar integer total number of items to place in the
%                  bins; totalitems>=numBins*numPerBin. If omitted or an
%                  empty matrix is passed, then the default of
%                  totalItems=numBins*numPerBin is used.
%
%OUTPUTS: allCombos The numPerBinXnumBinsXnumCapCombos set of capacitated
%                   combinations. allCombos(:,:,i) is the ith capacitated
%                   combination. The rows are the items in each bin and the
%                   columns are the bins. Items are numbered from 1 to
%                   totalItems.
%
%If we assume that totalItems=n=numPerBin*numBins, then we can generate the
%combinations by fixing the first element of each bin to the smallest index
%unassigned to any previous bin in the current combination being
%constructed. Thus, the first bin will always contain item 1. The second
%bin will always contain the smallest unassigned item that is not in the
%first bin and so on. Thus, we have to go through standard
%(n-(k-1)*numPerBin-1) choose (numPerBin-1) combinations of the remaining
%indices for the kth bin conditioned on the previous bins. This function
%implements a non-recursive algorithm for generating such combinations.
%
%In the general case, if totalItems>n, then we have to additionally go
%through all possible combinations of n items chosen from totalItems. This
%means generating all combinations as if totalItems=n and then remapping
%the indices for each subset of n items from totalItems.
%
%A total of numCapacitatedCombos(numPerBin,numBins,totalItems) capacitated
%combinations will be produced. Note that the number of capacitated
%combinations can grow rapidly and one might prefer visiting them
%sequentially using getNextCapacitatedCombo rather than generating all of
%them at once.
%
%EXAMPLE:
%Here we put six items into two bins of capacity 3:
% allCombos=genAllCapacitatedCombos(3,2,6)
%One wil get 10 combinations:
% allCombos(:,:,1)=[1, 4;
%                   2, 5;
%                   3, 6];
% allCombos(:,:,2)=[1, 3;
%                   2, 5;
%                   4, 6];
% allCombos(:,:,3)=[1, 3;
%                   2, 4;
%                   5, 6];
% allCombos(:,:,4)=[1, 3;
%                   2, 4;
%                   6, 5];
% allCombos(:,:,5)=[1, 2;
%                   3, 5;
%                   4, 6];
% allCombos(:,:,6)=[1, 2;
%                   3, 4;
%                   5, 6];
% allCombos(:,:,7)=[1, 2;
%                   3, 4;
%                   6, 5];
% allCombos(:,:,8)=[1, 2;
%                   4, 3;
%                   5, 6];
% allCombos(:,:,9)=[1, 2;
%                   4, 3;
%                   6, 5];
% allCombos(:,:,10)=[1, 2;
%                    5, 3;
%                    6, 4];
%
%July 2019 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

%The total number of items to assign in combinations across the bins.
n=numBins*numPerBin;

if(nargin<3||isempty(totalItems))
    totalItems=n;
end

if(n>totalItems)
    error('totalItems cannot be less than numBins*numPerBin')
end

%Special case for standard combinations.
if(numPerBin==1)
    allCombos=genAllCombinations(totalItems,numBins,1,1);
    numCopies=size(allCombos,2);
    allCombos=reshape(allCombos,[numPerBin,numBins,numCopies]);
    return
end

%The total number of items to assign in combinations.
n=numBins*numPerBin;

%The total number of capacitated combinations if n=totalItems.
numCombosNoExtra=numCapacitatedCombos(numPerBin,numBins);

%If n~=totalItems, then this is the number of variants of each capacitated
%combination that will have to be generated.
numCopies=binomial(totalItems,n);

%To store the results.
allCombos=zeros(numPerBin,numBins,numCopies,numCombosNoExtra);

numPerBinM1=numPerBin-1;

curIdxCombos=zeros(numPerBin,numBins);
curCombos=zeros(numPerBin-1,numBins);

%This holds the indices that can be assigned in each bin and in subsequent
%bins.
idxLists=zeros(n,numBins);
idxLists(:,1)=1:n;

curSet=1;
curBin=1;
backtracking=false;
while(curBin>0)
    %This is the number of elements that can be assigned in the current
    %bin including making a hard assignment on the first index.
    numInIdx=n-(curBin-1)*numPerBin;

    if(backtracking==false)
        %We are just entering this bin.
        %The first element in each bin is fixed to the first index in the
        %idxList.
        curIdxCombos(1,curBin)=idxLists(1,curBin);

        %In this level, we have to go through all combinations of the
        %remaining n-curBin*(numPerBin-1); unassigned elements of
        %idxLists(:,curBin) in this bin. Each time an assignment is made in
        %this bin, those elements are removed from idxLists going into the
        %next higher level so that we never get repeats.
        curIdxCombos(2:numPerBin,curBin)=idxLists(2:numPerBin,curBin);
        %Current combination of the indices in idxLists in this bin.
        curCombos(:,curBin)=1:numPerBinM1;

        if(curBin==numBins)
            %If we are in the final bin, then save the combo with all
            %variants of indices and move to the previous bin.

            I=1:n;
            for curCopy=1:numCopies
                allCombos(:,:,curCopy,curSet)=I(curIdxCombos);

                I=getNextCombo(I,totalItems,1);
            end

            curSet=curSet+1;

            backtracking=true;
            curBin=curBin-1;
            continue;
        else
            %Otherwise, set idxLists for the next level and move to the
            %next bin.numInIdxNext
            numInIdxNext=numInIdx-numPerBin;
            idxLists(1:numInIdxNext,curBin+1)=idxLists((numPerBin+1):numInIdx,curBin);

            curBin=curBin+1;
        end
    else
        %If here, we are backtracking.

        %We subtract 1 because we have made a hard assignment on the first
        %index.
        nextCombo=getNextCombo(curCombos(:,curBin),numInIdx-1,1);
        if(isempty(nextCombo))
            %Continue backtracking.
            curBin=curBin-1;
            continue;
        end
        %Otherwise, record the current combination.
        curCombos(:,curBin)=nextCombo;

        %Record the indices for the current combination.
        nextCombo=nextCombo+1;
        curIdxCombos(2:numPerBin,curBin)=idxLists(nextCombo,curBin);

        %Now, set the values in idxLists at the next bin level to those
        %that are in idxLists but not in nextCombo. We note that the
        %indices are given in increasing order and that the first index is
        %skipped because we know it is assigned.
        curAssignedIdx=2;
        curNextIdx=1;
        for curListIdx=2:numInIdx
            if(idxLists(curListIdx,curBin)==curIdxCombos(curAssignedIdx,curBin))
                curAssignedIdx=curAssignedIdx+1;
                if(curAssignedIdx>numPerBin)
                    %Then all of the rest of the indices are assigned.
                    numInIdxNext=numInIdx-numPerBin;
                    idxLists(curNextIdx:numInIdxNext,curBin+1)=idxLists((curListIdx+1):numInIdx,curBin);
                    break;
                end
            else
                idxLists(curNextIdx,curBin+1)=idxLists(curListIdx,curBin);
                curNextIdx=curNextIdx+1;
            end
        end

        %Go to the next bin.
        curBin=curBin+1;
        backtracking=false;
    end
end

allCombos=allCombos(:,:,:);

end

%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


function y=PSNR(noisyImage,restoredImage)

% Compute the PSNR of two gray scale image
% Traditional progarmming using loops
% Class input : [0,1]
% july, 25 , 2012
% KHMOU Youssef

N=size(noisyImage);
if length(N)> 2
    error('Input must be grayscale image');
end
if size(noisyImage)~=size(restoredImage)
    error('The images must have the same size');
end

%if ~isa(noisyImage,'double')
%   noisyImage=double(noisyImage)./255.00;
%end
%if  ~isa(restoredImage,'double')
%    restoredImage=double(restoredImage)./255.00;
%end

% begin

d1=max(noisyImage(:));
d2=max(restoredImage(:));
d=max(d1,d2);

MSE=0;
for i=1:N(1)
    for j=1:N(2)
        if isnan(noisyImage(i,j)) || isinf(restoredImage(i,j))...
                || isnan(restoredImage(i,j)) || isinf(noisyImage(i,j))
            continue;
        end
        MSE=MSE+((abs(noisyImage(i,j)-restoredImage(i,j))).^2);
    end
end

MSE=MSE./(N(1)*N(2));

y=10*log10((d.^2) /MSE)


function [x,y] = EquiNodes2D(N);

% function [x,y] = EquiNodes2D(N);
% Purpose  : Compute (x,y) nodes in equilateral triangle for polynomial of order N

% total number of nodes
Np = (N+1)*(N+2)/2;

% Create equidistributed nodes on equilateral triangle
L1 = zeros(Np,1); L2 = zeros(Np,1); L3 = zeros(Np,1);
sk = 1;
for n=1:N+1
  for m=1:N+2-n
    L1(sk) = (n-1)/N; L3(sk) = (m-1)/N;
    sk = sk+1;
  end
end
L2 = 1.0-L1-L3;

x = -L2+L3; y = (-L2-L3+2*L1)/sqrt(3.0);
return


function [mu sigma2] = estimateGaussian(X)
%ESTIMATEGAUSSIAN This function estimates the parameters of a
%Gaussian distribution using the data in X
%   [mu sigma2] = estimateGaussian(X),
%   The input X is the dataset with each n-dimensional data point in one row
%   The output is an n-dimensional vector mu, the mean of the data set
%   and the variances sigma^2, an n x 1 vector
%

% Useful variables
[m, n] = size(X);

% You should return these values correctly
mu = zeros(n, 1);
sigma2 = zeros(n, 1);

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the mean of the data and the variances
%               In particular, mu(i) should contain the mean of
%               the data for the i-th feature and sigma2(i)
%               should contain variance of the i-th feature.
%

mu = mean(X);
sigma2 = var(X,opt=1);

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

end


function value = r4_atanh ( x )

%*****************************************************************************80
%
%% R4_ATANH evaluates the arc-hyperbolic tangent of an R4 argument.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 September 2011
%
%  Author:
%
%    Original FORTRAN77 version by Wayne Fullerton.
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Wayne Fullerton,
%    Portable Special Function Routines,
%    in Portability of Numerical Software,
%    edited by Wayne Cowell,
%    Lecture Notes in Computer Science, Volume 57,
%    Springer 1977,
%    ISBN: 978-3-540-08446-4,
%    LC: QA297.W65.
%
%  Parameters:
%
%    Input, real X, the argument.
%
%    Output, real VALUE, the arc-hyperbolic tangent of X.
%
  persistent atnhcs;
  persistent dxrel;
  persistent nterms;
  persistent sqeps;

  if ( isempty ( nterms ) )
    atnhcs = [ ...
    0.094395102393195492E+00;
    0.049198437055786159E+00;
    0.002102593522455432E+00;
    0.000107355444977611E+00;
    0.000005978267249293E+00;
    0.000000350506203088E+00;
    0.000000021263743437E+00;
    0.000000001321694535E+00;
    0.000000000083658755E+00;
    0.000000000005370503E+00;
    0.000000000000348665E+00;
    0.000000000000022845E+00;
    0.000000000000001508E+00;
    0.000000000000000100E+00;
    0.000000000000000006E+00 ];
    nterms = r4_inits ( atnhcs, 15, 0.1 * r4_mach ( 3 ) );
    dxrel = sqrt ( r4_mach ( 4 ) );
    sqeps = sqrt ( 3.0 * r4_mach ( 3 ) );
  end

  y = abs ( x );

  if ( y <= sqeps )
    value = x;
  elseif ( y <= 0.5 )
    value = x * ( 1.0 ...
      + r4_csevl ( 8.0 * x * x - 1.0, atnhcs, nterms ) );
  elseif ( y < 1.0 )
    value = 0.5 * log ( ( 1.0 + x ) / ( 1.0 - x ) );
  else
    fprintf ( 1, '\n' );
    fprintf ( 1, 'R4_ATANH - Fatal error!\n' );
    fprintf ( 1, '  1 <= |X|.\n' );
    error ( 'R4_ATANH - Fatal error!' )
  end

  return
end


function halton_dataset ( )

%*****************************************************************************80
%
%% HALTON_DATASET generates a Halton dataset and writes it to a file.
%
%  Discussion:
%
%    This program is meant to be used interactively.  It's also
%    possible to prepare a simple input file beforehand and use it
%    in batch mode.
%
%    The program requests input values from the user:
%
%    * NDIM, the spatial dimension,
%    * N, the number of points to generate,
%    * STEP, the index of the first subsequence element to be computed.
%    * SEED(1:NDIM), the Halton sequence index corresponding
%      to STEP = 0.
%    * LEAP(1:NDIM), the successive jumps in the Halton sequence.
%    * BASE(1:NDIM), the Halton bases (usually distinct primes).
%
%    The program generates the data, writes it to the file
%
%      halton_NDIM_N.txt
%
%    where "NDIM" and "N" are the numeric values specified by the user,
%    and then asks the user for more input.   To indicate that no further
%    computations are desired, it is enough to input a nonsensical
%    value, such as -1.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 October 2008
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );

  fprintf ( 1, '\n' );
  fprintf ( 1, 'HALTON_DATASET\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Generate a Halton dataset.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  This program is meant to be used interactively.\n' );
  fprintf ( 1, '  It is also possible to prepare a simple input \n' );
  fprintf ( 1, '  file beforehand and use it in batch mode.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  The program requests input values from the user:\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  * NDIM, the spatial dimension,\n' );
  fprintf ( 1, '  * N, the number of points to generate,\n' );
  fprintf ( 1, '  * STEP, the index of the first subsequence element.\n' );
  fprintf ( 1, '  * SEED(1:NDIM), the Halton sequence element\n' );
  fprintf ( 1, '    corresponding to STEP = 0\n' );
  fprintf ( 1, '  * LEAP(1:NDIM), the successive jumps in the\n' );
  fprintf ( 1, '    Halton sequence.\n' );
  fprintf ( 1, '  * BASE(1:M), the Halton bases,\n' );
  fprintf ( 1, '    usually distinct primes.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  The program generates the data, writes it to the file\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '    halton_NDIM_N.txt\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  where "NDIM" and "N" are the numeric values specified\n' );
  fprintf ( 1, '  by the user, and then asks the user for more input.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  To indicate that no further computations are \n' );
  fprintf ( 1, '  desired, it is enough to input a nonsensical value, \n' );
  fprintf ( 1, '  such as -1.\n' );

  while ( 1 )

    fprintf ( 1, '  *\n' );
    fprintf ( 1, ' *\n' );
    fprintf ( 1, '*  Ready to generate a new dataset:\n' );
    fprintf ( 1, ' *\n' );
    fprintf ( 1, '  *\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  NDIM is the spatial dimension.\n' );
    fprintf ( 1, '  (Try ''2'' if you have no preference.)\n' );
    fprintf ( 1, '  Any value less than 1 terminates execution.\n' );
    ndim = input ( '  Enter NDIM:  ' );

    fprintf ( 1, '  User input NDIM = %d\n', ndim );

    if ( ~halham_ndim_check ( ndim ) )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'HALTON_DATASET\n' );
      fprintf ( 1, '  The input value of NDIM = %d\n', ndim );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  N is the number of points.\n' );
    fprintf ( 1, '  (Try ''25'' if you have no preference.)\n' );
    fprintf ( 1, '  Any value less than 1 terminates execution.\n' );
    n = input ( '  Enter N:  ' );

    fprintf ( 1, '  User input N = %d\n', n );

    if ( ~halham_n_check ( n ) )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'HALTON_DATASET\n' );
      fprintf ( 1, '  The input value of N = %d\n', n );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  STEP is the index of the first subsequence element.\n' );
    fprintf ( 1, '  (Try ''0'' or ''1'' if you have no preference.)\n' );
    fprintf ( 1, '  Any value less than 0 terminates execution.\n' );
    step = input ( '  Enter STEP:  ' );

    fprintf ( 1, '  User input STEP = %d\n', step );

    if ( ~halham_step_check ( step ) )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'HALTON_DATASET\n' );
      fprintf ( 1, '  The input value of STEP = %d\n', step );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  SEED(1:NDIM) is the starting element index\n' );
    fprintf ( 1, '  for each coordinate.\n' );
    fprintf ( 1, '  (Try ''[0,0,...,0]'' if you have no preference.)\n' );
    fprintf ( 1, '  (Any value less than 0 terminates execution.)\n' );
    seed = [];
    seed(1:ndim) = input ( '  Enter SEED(1:NDIM):  ' );

    fprintf ( 1, '\n' );
    i4vec_transpose_print ( ndim, seed, 'SEED:' );

    if ( ~halham_seed_check ( ndim, seed ) )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'HALTON_DATASET\n' );
      fprintf ( 1, '  The negative input value of at least one entry of\n' );
      fprintf ( 1, '  SEED is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  LEAP(1:NDIM) is the leaping multiplier\n' );
    fprintf ( 1, '  for each coordinate.\n' );
    fprintf ( 1, '  (Try ''[1,1,...,1]'' if you have no preference.)\n' );
    fprintf ( 1, '  (Another choice is a prime bigger than all the bases.)\n' );
    fprintf ( 1, '  (Any value less than 1 terminates execution.)\n' );
    leap = [];
    leap(1:ndim) = input ( '  Enter LEAP(1:NDIM):  ' );

    fprintf ( 1, '\n' );
    i4vec_transpose_print ( ndim, leap, 'LEAP:' );

    if ( ~halham_leap_check ( ndim, leap ) )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'HALTON_DATASET\n' );
      fprintf ( 1, '  The input value of at least one entry of\n' );
      fprintf ( 1, '  LEAP is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  BASE(1:NDIM) is the base for each coordinate,\n' );
    fprintf ( 1, '  usually distinct primes.\n' );
    fprintf ( 1, '  (Try ''[2,3,5,7,11,13,...]'' if you have no preference.)\n' );
    fprintf ( 1, '  (Any value less than 2 terminates execution.)\n' );
    base = [];
    base(1:ndim) = input ( '  Enter BASE:  ' );

    fprintf ( 1, '\n' );
    i4vec_transpose_print ( ndim, base, 'BASE:' );

    if ( ~halton_base_check ( ndim, base ) )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'HALTON_DATASET\n' );
      fprintf ( 1, '  The input value of at least one entry of\n' );
      fprintf ( 1, '  BASE is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
    end

    r = i4_to_halton_sequence ( ndim, n, step, seed, leap, base );

    file_out_name = ...
      strcat ( 'halton_', num2str ( ndim ), '_', num2str ( n ), '.txt' );

    halham_write ( ndim, n, step, seed, leap, base, r, file_out_name );

    fprintf ( 1, '\n' );
    fprintf ( 1, '  The data was written to the file "%s".\n', ...
      file_out_name );

  end

  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function turn = angle_turn_2d ( p1, p2, p3 )

%*****************************************************************************80
%
%% ANGLE_TURN_2D computes a turning angle in 2D.
%
%  Discussion:
%
%    This routine is most useful when considering the vertices of a
%    polygonal shape.  We wish to distinguish between angles that "turn
%    in" to the shape, (between 0 and 180 degrees) and angles that
%    "turn out" (between 180 and 360 degrees), as we traverse the boundary.
%
%    If we compute the interior angle and subtract 180 degrees, we get the
%    supplementary angle, which has the nice property that it is
%    negative for "in" angles and positive for "out" angles, and is zero if
%    the three points actually lie along a line.
%
%    Assuming P1, P2 and P3 define an angle, the TURN can be
%    defined to be either:
%
%    * the supplementary angle to the angle formed by P1=P2=P3, or
%
%    * the angle between the vector ( P3-P2) and the vector -(P1-P2),
%      where -(P1-P2) can be understood as the vector that continues
%      through P2 from the direction P1.
%
%    The turning will be zero if P1, P2 and P3 lie along a straight line.
%
%    It will be a positive angle if the turn from the previous direction
%    is counterclockwise, and negative if it is clockwise.
%
%    The turn is given in radians, and will lie between -PI and PI.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 March 2006
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real P1(2), P2(2), P3(2), the points that form
%    the angle.
%
%    Output, real TURN, the turn angle, between -PI and PI.
%
  p(1) = ( p3(1) - p2(1) ) * ( p1(1) - p2(1) ) ...
       + ( p3(2) - p2(2) ) * ( p1(2) - p2(2) );

  p(2) = ( p3(1) - p2(1) ) * ( p1(2) - p2(2) ) ...
       - ( p3(2) - p2(2) ) * ( p1(1) - p2(1) );

  if ( p(1) == 0.0 & p(2) == 0.0 )
    turn = 0.0;
  else
    turn = pi - r8_atan ( p(2), p(1) );
  end

  return
end


function area = polygon_area_3d_2 ( n, v, area )

%*****************************************************************************80
%
%% POLYGON_AREA_3D_2 computes the area of a polygon in 3D.
%
%  Discussion:
%
%    The computation is not valid unless the vertices of the polygon
%    lie in a plane, so that the polygon that is defined is "flat".
%
%    The polygon does not have to be "regular", that is, neither its
%    sides nor its angles need to be equal.
%
%    The area is computed as the sum of the areas of the triangles
%    formed by the last node with consecutive pairs of nodes (1,2),
%    (2,3), ..., and (N-2,N-1).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 October 2005
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Adrian Bowyer and John Woodwark,
%    A Programmer's Geometry,
%    Butterworths, 1983.
%
%  Parameters:
%
%    Input, integer N, the number of vertices of the polygon.
%
%    Input, real V(3,N), the coordinates of the vertices.
%
%    Output, real AREA, the area of the polygon.
%
  area_vector(1:3) = 0.0;

  for i = 1 : n - 2

    t(1:3,1:3) = [ v(1:3,i)'; v(1:3,i+1)'; v(1:3,n)' ]';

    area_vector_triangle = triangle_area_vector_3d ( t );

    area_vector(1:3) = area_vector(1:3) + area_vector_triangle(1:3);

  end

  area = 0.5 * sqrt ( sum ( area_vector(1:3).^2 ) );

  return
end


function rotated=uniform_rotation_3D(v)
% This function perform a unformly random rotation 3D.
% It is clear that in 2 dimensions that this means the
% rotation angle is uniformly distributed between (0, 2pi).
% However, it is NOT correct and does NOT carry over to
% higher dimensions.
%
% More information see Le?n, Carlos A.; Mass?, Jean-Claude;
% Rivest, Louis-Paul (February 2006), "A statistical model
% for random rotations", Journal of Multivariate Analysis 97
% (2): 412?430, doi:10.1016/j.jmva.2005.03.009, ISSN 0047-259X

% Arguments (input):
%   v - 3*1 vector needs to be rotated
%
%
% arguments (output):
%   rotated - 3*1 vector after unformly random rotation
%
%
% References: J. Arvo (1992), Fast Random Rotation Matrices
%
% Author: Yaming Wang. ETH Zurich.
% email: yaming.wang@sed.ethz.ch
% Release: 1.00
% Release data: 18.09.2012

rot_1=2*pi*rand(1);
matrix_1=[cos(rot_1),sin(rot_1),0;...
    -sin(rot_1),cos(rot_1),0;...
    0,0,1];

rot_2a=2*pi*rand(1);
rot_2b=rand(1);

Householder_v=[cos(rot_2a)*sqrt(rot_2b)
    sin(rot_2a)*sqrt(rot_2b)
    sqrt(1-rot_2b)];

% Householder matrix
matrix_2=eye(3)-2*Householder_v*Householder_v';

rotated=-matrix_2*matrix_1*v;

fprintf(1,'rotation finished.\n');

% ====================================================
%      end of function
% ====================================================


% LegendrePoly.m by David Terr, Raytheon, 5-10-04

% Given nonnegative integer n, compute the
% Legendre polynomial P_n. Return the result as a vector whose mth
% element is the coefficient of x^(n+1-m).
% polyval(LegendrePoly(n),x) evaluates P_n(x).

function pk = LegendrePoly(n)

if n==0
    pk = 1;
elseif n==1
    pk = [1 0]';
else

    pkm2 = zeros(n+1,1);
    pkm2(n+1) = 1;
    pkm1 = zeros(n+1,1);
    pkm1(n) = 1;

    for k=2:n

        pk = zeros(n+1,1);

        for e=n-k+1:2:n
            pk(e) = (2*k-1)*pkm1(e+1) + (1-k)*pkm2(e);
        end

        pk(n+1) = pk(n+1) + (1-k)*pkm2(n+1);
        pk = pk/k;

        if k<n
            pkm2 = pkm1;
            pkm1 = pk;
        end

    end

end


function f = bohach1_xy ( x, y )

%*****************************************************************************80
%
%% BOHACH1_XY evaluates the Bohachevsky function #1.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 February 2008
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Zbigniew Michalewicz,
%    Genetic Algorithms + Data Structures = Evolution Programs,
%    Third Edition,
%    Springer Verlag, 1996,
%    ISBN: 3-540-60676-9,
%    LC: QA76.618.M53.
%
%  Parameters:
%
%    Input, real X, Y, the argument of the function.
%
%    Output, real F, the value of the function at X.
%
  f =       x * x - 0.3 * cos ( 3.0 * pi * x ) ...
    + 2.0 * y * y - 0.4 * cos ( 4.0 * pi * y ) ...
    + 0.7;

  return
end


% Compute the average degree of a node in a graph, defined as
% 2 times the number of edges divided by the number of nodes
%          (every edge is counted towards the degrees twice).
%
% Inputs: adjacency matrix, nxn
% Outputs: float, the average degree, a number between 0 and max(sum(adj))
%
% Note: The average degree is related to the link density, namely:
%       link_density = ave_degree/(n-1), where n is the number of nodes
%
% Other routines used: numNodes.m, numEdges.m
% GB: last update, September 20, 2012

function k=averageDegree(adj)

k=2*numEdges(adj)/numNodes(adj);


%MAIN_doublePendulum.m
%
% This script runs a simulation of a double pendulum

% Use: EoM_Double_Pendulum to write the equations of motion

clear; clc;

%Physical parameters:
P.m1 = 4.0;  % (kg) pendulum mass, link 1
P.m2 = 1.0;  % (kg) pendulum mass, link 2
P.g = 9.81; % (m/s^2) gravity
P.l1 = 1.0; % (m) link 1 length
P.l2 = 2.0; % (m) link 2 length
P.d1 = 0.6*P.l1; % Distance from parent joint to link CoM
P.d2 = 0.4*P.l2; % Distance from parent joint to link CoM
P.I1 = P.m1*P.l1^2/12; %Link 1, moment of inertia
P.I2 = P.m2*P.l2^2/12; %Link 2, moment of inertia

tSpan = [0,10]; %Simulation time interval

z0 = zeros(4,1);
z0(1) = (pi/180)*(-90);  % Link 1, initial abs angle
z0(2) = 0;  % Link 1, initial abs angle rate
z0(3) = (pi/180)*(-90);  % Link 1, initial abs angle
z0(4) = 0;  % Link 1, initial abs angle rate

u = [0;0];

userFunc = @(t,z)doublePendulumDynamics(t,z,u,P);

options = odeset(...
    'AbsTol',1e-6,...
    'RelTol',1e-6,...
    'Vectorized','on');

% Run the simulation!
sol = ode45(userFunc,tSpan,z0,options);

% Break apart solution for plotting
nPlot = 1000;
time = linspace(tSpan(1),tSpan(2),nPlot);
z = deval(sol,time); %Evaluate solution from ode45 at points in time
th1 = z(1,:);
w1 = z(2,:);
th2 = z(3,:);
w2 = z(4,:);
[energy, kinetic, potential] = doublePendulumEnergy(z,P);

% Plotting!

figure(2222);clf;

subplot(3,1,1); hold on;
plot(time,th1,'r-','LineWidth',2);
plot(time,th2,'b-','LineWidth',2);
xlabel('time (s)')
ylabel('angle (rad)');

subplot(3,1,2); hold on;
plot(time,w1,'r-','LineWidth',2);
plot(time,w2,'b-','LineWidth',2);
xlabel('time (s)')
ylabel('angle rate (rad/s)');

subplot(3,1,3);  hold on;
datum = min(potential);
plot(time,energy - datum,'k-','LineWidth',3);
plot(time,kinetic,'LineWidth',2,'color',[0.5,0.1,0.6]);
plot(time,potential - datum,'LineWidth',2,'color',[0.3,0.5,0.2]);
xlabel('time (s)')
ylabel('energy (J)');
legend('total','kinetic','potential');

% Animation
figure(3333); clf;
doublePendulumAnimate(sol,P);


function X = matrandnorm(varargin)
%MATRANDNORM Normalizes columns of X so that each is unit 2-norm.
%
%   X = MATRANDNORM(M,N) creates a random M x N matrix with randomly using
%   normally distributed enries and then rescales the columsn so that each
%   has a unit 2-norm.
%
%   X = MATRANDNORM(X) rescales the columns of X so that each
%   column has a unit 2-norm.
%
%   Examples
%      X = MATRANDNORM(rand(5,5));
%      X = MATRANDNORM(3,2);
%      X = MATRANDNORM(ones(4));
%
%   See also MATRANDORTH, MATRANDNORM, CREATE_PROBLEM, CREATE_GUESS.
%
%MATLAB Tensor Toolbox.
%Copyright 2015, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2015) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

if nargin == 2
    X = randn(varargin{1}, varargin{2});
else
    X = varargin{1};
end

norms = sqrt(sum(X.^2,1));
X = bsxfun(@rdivide,X,norms);


function result = circle_annulus ( func, xc, yc, radius1, radius2, nr )

%*****************************************************************************80
%
%% CIRCLE_ANNULUS approximates an integral in a circular annulus.
%
%  Integration region:
%
%    Points (X,Y) such that
%
%      RADIUS1**2 <= ( X - XC )**2 + ( Y - YC )**2 <= RADIUS2**2
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 May 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    William Peirce,
%    Numerical Integration Over the Planar Annulus,
%    Journal of the Society for Industrial and Applied Mathematics,
%    Volume 5, Issue 2, June 1957, pages 66-73.
%
%  Parameters:
%
%    Input, external FUNC, the name of the user supplied function of two
%    variables which is to be integrated, of the form:
%      function value = func ( x, y )
%
%    Input, real XC, YC, the center of the circle.
%
%    Input, real RADIUS1, RADIUS2, the radii of the circles.
%
%    Input, integer NR, the order of the rule.  This quantity specifies
%    the number of distinct radii to use.  The number of angles used will
%    be 4*NR, for a total of 4*NR**2 points.
%
%    Output, real RESULT, the approximation to the integral.
%

%
%  Choose radial abscissas and weights.
%
  [ ra, rw ] = legendre_set ( nr );
  a = -1.0E+00;
  b = +1.0E+00;
  c = radius1^2;
  d = radius2^2;
  [ ra, rw ] = rule_adjust ( a, b, c, d, nr, ra, rw );
  ra(1:nr) = sqrt ( ra(1:nr) );
  rw(1:nr) = rw(1:nr) / ( radius2^2 - radius1^2 );
%
%  Set angular abscissas and weights.
%
  nt = 4 * nr;

  tw = 1.0E+00 / nt;
%
%  Approximate the integral.
%
  quad = 0.0E+00;
  for i = 1 : nt
    t = 2.0E+00 * pi * ( i - 1 ) / nt;
    for j = 1 : nr
      x = xc + ra(j) * cos ( t );
      y = yc + ra(j) * sin ( t );
      quad = quad + tw * rw(j) * feval ( func, x, y );
    end
  end

  area = circle_annulus_area_2d ( radius1, radius2 );
  result = quad * area;

  return
end


function lij = fem_basis_1d ( i, j, x )

%*****************************************************************************80
%
%% FEM_BASIS_1D evaluates an arbitrary 1D basis function.
%
%  Discussion:
%
%    Given the maximum degree D for the polynomial basis defined
%    on a reference interval, we have D + 1 monomials
%    of degree at most D.  In each barycentric coordinate, we define
%    D+1 points, so that 0 <= I, J <= D and I+J = D, with
%    (I,J) corresponding to
%    * the basis point X(I,J) = ( I/D );
%    * the basis monomial P(I,J)(X) = X^I.
%
%    For example, with D = 2, we have simply:
%
%      A---B---C
%
%    with
%
%       I J    X      P(I,J)(X)
%
%    A (0 2) ( 0.0 )  1
%    B (1 1) ( 0.5 )  x
%    C (2 0) ( 1.0 )  x^2
%
%    Now instead of the monomials P(I,J)(X), we want a set of
%    polynomials L(I,J)(X) which span the same space, but have
%    the Lagrange property, namely L(I,J) (X) is 1 if X is
%    equal to X(I,J), and 0 if X is equal to any other
%    of the basis points.
%
%    This is easily arranged.  Given an index (I,J), we compute
%    1) I factors of the form (X-0)   * (X-1/D)   * ... * (X-(I-1)/D);
%    2) J factors of the form ???
%
%    This results in the product of I+J linear factors, in other words,
%    a polynomial of degree D.  This polynomial is 0 at all basis points
%    except X(I,J).  If we divide this polynomial by its value at
%    the basis point, we arrive at the desired Lagrange polynomial
%    L(I,J)(X).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    05 October 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer I, J, the integer barycentric coordinates of the basis
%    function, 0 <= I, J.  The polynomial degree D = I + J
%
%    Input, real X, the evaluation point.
%
%    Output, real LIJ, the value of the basis function at X.
%
  d = i + j;
  lij = 1.0;
  cij = 1.0;
  for p = 0 : i - 1
    lij = lij * ( d * x - p );
    cij = cij * (     i - p );
  end
  for p = 0 : j - 1
    lij = lij * ( d * x - ( d - p ) );
    cij = cij * (     i - ( d - p ) );
  end

  lij = lij / cij;

  return
end


function plane2 = normalizePlane(plane1)
%NORMALIZEPLANE Normalize parametric representation of a plane
%
%   PLANE2 = normalizePlane(PLANE1);
%   Transforms the plane PLANE1 in the following format:
%   [X0 Y0 Z0  DX1 DY1 DZ1  DX2 DY2 DZ2], where:
%   - (X0, Y0, Z0) is a point belonging to the plane
%   - (DX1, DY1, DZ1) is a first direction vector
%   - (DX2, DY2, DZ2) is a second direction vector
%   into another plane, with the same format, but with:
%   - (x0 y0 z0) is the closest point of plane to the origin
%   - (DX1 DY1 DZ1) has norm equal to 1
%   - (DX2 DY2 DZ2) has norm equal to 1 and is orthogonal to (DX1 DY1 DZ1)
%
%   See also:
%   planes3d, createPlane
%
%   ---------
%   author: David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 21/02/2005.
%

%   HISTORY
%   21/08/2009 compute origin after computation of vectors (more precise)
%       and add support for several planes.

% compute first direction vector
d1  = normalizeVector3d(plane1(:,4:6));

% compute second direction vector
n   = normalizeVector3d(planeNormal(plane1));
d2  = -normalizeVector3d(crossProduct3d(d1, n));

% compute origin point of the plane
origins = repmat([0 0 0], [size(plane1, 1) 1]);
p0 = projPointOnPlane(origins, [plane1(:,1:3) d1 d2]);

% create the resulting plane
plane2 = [p0 d1 d2];


function [J, grad] = cofiCostFunc(params, Y, R, num_users, num_movies, ...
                                  num_features, lambda)
%COFICOSTFUNC Collaborative filtering cost function
%   [J, grad] = COFICOSTFUNC(params, Y, R, num_users, num_movies, ...
%   num_features, lambda) returns the cost and gradient for the
%   collaborative filtering problem.
%

% Unfold the U and W matrices from params
X = reshape(params(1:num_movies*num_features), num_movies, num_features);
Theta = reshape(params(num_movies*num_features+1:end), ...
                num_users, num_features);

% You need to return the following values correctly
J = 0;
X_grad = zeros(size(X));
Theta_grad = zeros(size(Theta));

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the cost function and gradient for collaborative
%               filtering. Concretely, you should first implement the cost
%               function (without regularization) and make sure it is
%               matches our costs. After that, you should implement the
%               gradient and use the checkCostFunction routine to check
%               that the gradient is correct. Finally, you should implement
%               regularization.
%
% Notes: X - num_movies  x num_features matrix of movie features
%        Theta - num_users  x num_features matrix of user features
%        Y - num_movies x num_users matrix of user ratings of movies
%        R - num_movies x num_users matrix, where R(i, j) = 1 if the
%            i-th movie was rated by the j-th user
%
% You should set the following variables correctly:
%
%        X_grad - num_movies x num_features matrix, containing the
%                 partial derivatives w.r.t. to each element of X
%        Theta_grad - num_users x num_features matrix, containing the
%                     partial derivatives w.r.t. to each element of Theta
%

temp = (X*Theta').*R;
J = sum( sum( (temp - Y.*R).^2) )/2.0 + (lambda/2) * ( sum(sum( X.^2 )) + sum(sum( Theta.^2 )) );
% J = sum( sum( (temp - Y.*R).^2) )/2.0 + (lambda/2) * ( sum(sum( X.^2 )) + sum(sum( Theta.^2 )) ) ;

X_grad = (temp - Y.*R) * Theta + lambda * X;
Theta_grad = (temp - Y.*R)' * X + lambda * Theta;

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

grad = [X_grad(:); Theta_grad(:)];

end


function geometry_test013 ( )

%*****************************************************************************80
%
%% TEST013 tests CIRCLE_LUNE_CENTROID_2D, CIRCLE_SECTOR_CENTROID_2D.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  n_test = 12;

  r = 2.0;
  center(1:2,1) = [ 5.0; 3.0 ];
  theta1 = 0.0;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST013\n' );
  fprintf ( 1, '  CIRCLE_LUNE_CENTROID_2D computes the centroid of a\n' );
  fprintf ( 1, '    circular lune, defined by joining the endpoints\n' );
  fprintf ( 1, '    of a circular arc.\n' );
  fprintf ( 1, '  CIRCLE_SECTOR_CENTROID_2D computes the centroid of a\n' );
  fprintf ( 1, '    circular sector, defined by joining the endpoints\n' );
  fprintf ( 1, '    of a circular arc to the center.\n' );

  circle_imp_print_2d ( r, center, '  The implicit circle:' );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  The first angle of our lune and sector is always 0.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '                         Lune                       Sector\n' );
  fprintf ( 1, '  THETA2           X             Y             X             Y\n' );
  fprintf ( 1, '\n' );

  for i = 0 : n_test

    theta2 = i * 2.0 * pi / n_test;

    centroid1(1:2,1) = circle_lune_centroid_2d ( r, center, theta1, theta2 );

    centroid2(1:2,1) = circle_sector_centroid_2d ( r, center, theta1, theta2 );

    fprintf ( 1, '  %12f  %12f  %12f  %12f  %12f\n', ...
      theta2, centroid1(1:2,1), centroid2(1:2,1) );

  end

  return
end


% StackExchange Mathematics Q3872982
% https://math.stackexchange.com/questions/3872982
% Solve Linear Least Squares with Squared L2 Norm Regularization (Tikhonov
% / Ridge Regression) with Non Negativity Constraint Using FISTA
% References:
%   1.
% Remarks:
%   1.  sa
% TODO:
% 	1.  ds
% Release Notes
% - 1.0.000     26/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;
paramLambda     = 0.1;

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

%% Load / Generate Data

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

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

mAA = mA.' * mA;
vAb = mA.' * vB;

hG = @(vX) (mAA * vX) - vAb + (paramLambda * vX); %<! Gradient of the Objection Function
hP = @(vX) max(vX, 0); %<! Projection onto the constraint set

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) + (0.5 * paramLambda * square_pos(norm(vX))) );
    subject to
        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 [labels, distances] = elec_distance(elec_labels,X,Y,Z,xo,yo,zo)

% elec_distance - Calculates spherical interelectrode distances (arc length).
%
% Usage: [labels, distances] = elec_distance(elec_labels,X,Y,Z,xo,yo,zo)
%
% Notes:    Arc length method assumes a centroid at (xo,yo,zo) = (0,0,0)
%           and input values are in rectangular Cartesian coordinates.
%
%           Sphere radius is estimated by the average radius from
%           (xo,yo,zo) to any 2 pairs of electrodes.  It will vary
%           from one pair to another, but this method works well for
%           small theta (eg, nearest neighbours).
%
%           Returns 2 matrices, one for paired electrode labels and
%           another for spherical arc length estimates.
%

% $Revision: 1.1 $ $Date: 2009-04-28 22:13:54 $

% Author:   Darren.Weber_at_radiology.ucsf.edu
% Created:  18/05/00 - linear distance
% Modified: 24/06/01 - spherical arc length (should be OK for small theta
%                      but for large theta, elliptical arc length may be
%                      preferable).
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    % initialise centroid, unless input parameters defined
    if ~exist('xo','var')  xo = 0;   end
    if ~exist('yo','var')  yo = 0;   end
    if ~exist('zo','var')  zo = 0;   end

    fprintf('%s\n', 'Calculating inter-electrode spherical arc length.');

    labels = cell(1);
    distances = [];

    % convert numerical electrode labels to cell strings
    if isnumeric(elec_labels) > 0
        if size(elec_labels,1) > size(elec_labels,2)
            elec_labels = cellstr(strcat(num2str(elec_labels)));
        else
            elec_labels = cellstr(strcat(num2str(elec_labels')));
        end
    end

    A = [ (X-xo) (Y-yo) (Z-zo) ];  B = A;              % define electrode vectors A,B, given centroid (xo,yo,zo)
    rows = 50;                                         % progress indicator
    for a =   1:length(X)
        fprintf('.'); if( a == rows ) fprintf('\n'); rows = rows + 50; end  % progress indicator

        Aa = A(a,:);
        A_len = sqrt( sum( Aa.^2 ) );                        % length of electrode vector A

        for b = 1:length(X)

            Bb = B(b,:);
            B_len = sqrt ( sum(Bb.^2) );                     % length of electrode vector B

            if( Aa == Bb )
                arc_len = 0;                                    % no distance from electrode to itself
            else
                r = (A_len + B_len)/2;                          % estimate sphere radius from A_len and B_len
                theta = acos( dot(Aa,Bb) / (A_len * B_len) );   % Angle between A & B, in radians
                arc_len = r * theta;                            % arc length = radius * theta
            end

            distances(a, b) = arc_len;
            labels(a, b) = strcat(elec_labels(a), ', ', elec_labels(b));
        end
    end
    fprintf('\n');


function breadth = polyhedronMeanBreadth(vertices, edges, faces)
%POLYHEDRONMEANBREADTH Mean breadth of a convex polyhedron
%
%   BREADTH = polyhedronMeanBreadth(V, E, F)
%   Return the mean breadth (average of polyhedron caliper diameter over
%   all direction) of a convex polyhedron.
%
%   The mean breadth is computed using the sum, over the edges of the
%   polyhedron, of the edge dihedral angles multiplied by the edge length,
%   the final sum being divided by (4*PI).
%
%   Note: the function assumes that the faces are correctly oriented. The
%   face vertices should be indexed counter-clockwise when considering the
%   supporting plane of the plane, with the outer normal oriented outwards
%   of the polyhedron.
%
%   Typical values for classical polyhedra are:
%     cube side a               breadth = (3/2)*a
%     cuboid sides a, b, c      breadth = (a+b+c)/2
%     tetrahedron side a        breadth = 0.9123*a
%     octaedron side a          beradth = 1.175*a
%     dodecahedron, side a      breadth = 15*arctan(2)*a/(2*pi)
%     icosaehdron, side a       breadth = 15*arcsin(2/3)*a/(2*pi)
%
%   Example
%   [v e f] = createCube;
%   polyhedronMeanBreadth(v, e, f)
%   ans =
%       1.5
%
%   See also
%   meshes3d, meshEdgeFaces, meshDihedralAngles, checkMeshAdjacentFaces
%   trimeshMeanBreadth
%
%   References
%   Stoyan D., Kendall W.S., Mecke J. (1995) "Stochastic Geometry and its
%       Applications", John Wiley and Sons, p. 26
%   Ohser, J., Muescklich, F. (2000) "Statistical Analysis of
%       Microstructures in Materials Sciences", John Wiley and Sons, p.352

% ------
% Author: David Legland
% e-mail: david.legland@inra.fr
% Created: 2010-10-04,    using Matlab 7.9.0.529 (R2009b)
% Copyright 2010 INRA - Cepia Software Platform.

% compute dihedral angle of each edge
alpha = meshDihedralAngles(vertices, edges, faces);

% compute length of each edge
lengths = meshEdgeLength(vertices, edges);

% compute product of length by angles
breadth = sum(alpha.*lengths)/(4*pi);


function w = map ( code, element_order )

%*****************************************************************************80
%
%% MAP returns the interpolation matrix for any available element.
%
%  Formula:
%
%    For an element of order ELEMENT_ORDER, we suppose we are given
%    ELEMENT_ORDER items of data Q associated with the nodes.
%
%   Let PHI(J)(R,S) be the Lagrange basis polynomial associated with
%   node J.  PHI(J)(R,S) is 1 at node J, and 0 at each of the other nodes.
%
%   Let P(R,S) be the polynomial of ELEMENT_ORDER terms which interpolates the
%   data Q, that is,
%
%      P(R(J),S(J)) = Q(J)
%
%   where the coordinates of node J are (R(J),S(J)).  Then we know
%   that we can write
%
%     P(R,S) = sum ( 1 <= J <= ELEMENT_ORDER ) Q(J) * PHI(J)(R,S)
%
%   But P(R,S) also has a standard representation as
%
%     P(R,S) = sum ( 1 <= I <= ELEMENT_ORDER ) A(I) * R**REXP(I) * S**SEXP(I)
%
%   where REXP(I) and SEXP(I) are the exponents of R and S and
%   the A(I) are the appropriate coefficients.
%
%   The interpolation matrix W allows us to immediately compute
%   the standard basis coefficients A from the data Q to be interpolated
%   using the formula:
%
%      A(I) = sum ( 1 <= J <= ELEMENT_ORDER ) W(I,J) * Q(J)
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, character CODE(*), identifies the element.
%    Legal values include 'Q4', 'Q8', 'Q9', 'Q12', 'Q16', 'QL',
%    'T3', 'T6' and 'T10'.
%
%    Input, integer ELEMENT_ORDER, the order associated with the code.
%
%    Output, real W(ELEMENT_ORDER,ELEMENT_ORDER), the interpolation matrix.
%

%
%  Get the (R,S) location of the nodes.
%
  [ r, s, area ] = node_reference ( code );
%
%  Get the associated monomials.
%
  [ rexp, sexp ] = poly ( code );
%
%  Set up the Vandermonde matrix.
%  Factors of the form 0**0 are to be understood as 1.
%
  for i = 1 : element_order
    for j = 1 : element_order

      if ( rexp(j) == 0 )
        rfact = 1.0;
      else
        rfact = r(i)^rexp(j);
      end

      if ( sexp(j) == 0 )
        sfact = 1.0;
      else
        sfact = s(i)^sexp(j);
      end

      w(i,j) = rfact * sfact;

    end
  end
%
%  Factor the Vandermonde matrix.
%
  [ w_lu, pivot, info ] = r8ge_fa ( element_order, w );

  if ( info ~= 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'MAP - Fatal error!\n' );
    fprintf ( 1, '  The Vandermonde matrix is singular.\n' );
    error ( 'MAP - Fatal error!' );
  end
%
%  Invert the Vandermonde matrix.
%
  w = r8ge_inverse ( element_order, w_lu, pivot );

  return
end


%% Optimise parameters of GMM through stochastic gradient descent
clear all;
%% Create ground truth GMM

Priors = ones(1,3)./3;
Mu     = [-8 2;0 0; 3 -3]';
Sigma(:,:,1) = [2 0.5; 0.5 1];
Sigma(:,:,2) = [1 0;0  5];
Sigma(:,:,3) = [4 0;0 1];

X = gmm_sample(500,Priors,Mu,Sigma);

%% Plot groud truth GMM & Data

close all;box on; grid on;
plot_gmm_contour(gca,Priors,Mu,Sigma,[0 0 1],1);
plot(X(1,:),X(2,:),'r+');

%% Initial parameters of GMM to train & Data

Priors_I = ones(1,3)./3;
Mu_I     = [ [-8;-2],[8;0],[0;8] ];
for i=1:3
    Sigma_I(:,:,i) = eye(2,2);
end

%% Plot Initial parameters & Data

close all;
figure; hold on;grid on; box on;
plot_gmm_contour(gca,Priors_I,Mu_I,Sigma_I,[0 0 1],1);
plot(X(1,:),X(2,:),'r+');
axis equal;

%% Gradient descent on Likelihood

W           = log_gmm_div_w(X,Priors_I,Mu_I,Sigma_I);
[dMu,dMu_n] = log_gmm_div_mu(X,W,Mu_I,Sigma_I);
dPriors     = log_gmm_div_prior(W,Priors);
dSigma      = log_gmm_div_sigma(X,W,Mu_I + dMu,Sigma_I);

dTSigma = dSigma;

%% Plot gradient direction of Mu

colors = [1 0 0;
          0 1 0;
          0 0 1];
close all;
figure; hold on;grid on; box on;
plot_gmm_contour(gca,Priors_I,Mu_I,Sigma_I,colors,3);

plot_gmm_contour(gca,Priors_I,Mu_I,dTSigma,[0 0 0],3);

%      (3 x 3)
color = (colors * W')';
scatter(X(1,:),X(2,:),10,color,'filled');

for k=1:3
    %(D x N)
    x = repmat(Mu_I(:,k),1,size(dMu_n,2));
    quiver(x(1,:),x(2,:),dMu_n(1,:,k),dMu_n(2,:,k));
    quiver(x(1,1),x(2,1),dMu(1,k),dMu(2,k),'r');

end

axis equal;

%% Optimise over mean

Priors_I = ones(1,3)./3;
Mu_I     = [ [-8;-2],[8;0],[0;8] ];
for i=1:3
    Sigma_I(:,:,i) = eye(2,2);
end

Priors_k = Priors_I;
Mu_k     = Mu_I;
Sigma_k  = Sigma_I;

W        = log_gmm_div_w(X,Priors_I,Mu_I,Sigma_I);
color = (colors * W')';
scatter(X(1,:),X(2,:),10,color,'filled');

K       = 1;
logliks = [];
bVision = true;

if bVision
    close all;
    hf = figure; hold on;grid on; box on;
    ghandle = plot_gmm_contour(gca,Priors_k,Mu_k,Sigma_k,colors,3);
    hs      = scatter(X(1,:),X(2,:),10,color,'filled');
    axis equal;
    axis([get(gca,'XLim'),get(gca,'YLim')]);
end

%% Optimisation

K = 1000;

for k=1:K

    % compute log likelihood
    logliks(k) =  LogLikelihood_gmm(X,Priors_k,Mu_k,Sigma_k);

    %(D x N x K)
    W       = log_gmm_div_w(X,Priors_k,Mu_k,Sigma_k);
    dPriors = log_gmm_div_prior(W,Priors);
    dMu     = log_gmm_div_mu(X,W,Mu_k,Sigma_k);
%    dSigma  = log_gmm_div_sigma(X,W, Mu_k + dMu,Sigma_k);

    Priors_k = Priors_k + dPriors;
    Priors_k = Priors_k./sum(Priors_k);
    Mu_k     = Mu_k + dMu;
%    Sigma_k  = Sigma_k + 0.001 .* dSigma;

    disp(['it(' num2str(k) ') loglik: ' num2str(logliks(k))]);

    if bVision
        plot_gmm_contour(gca,Priors_k,Mu_k,Sigma_k,[0 0 1],1,ghandle);
        color = (colors * W')';
        set(hs,'CData',color);
        pause(0.01);
    end

    if k > 1
       if abs(logliks(k) - logliks(k-1)) < 1e-8
            k = K +1;
            disp(['Optimisation finished diff: ' num2str(abs(logliks(k) - logliks(k-1)))]);
       end
    end

end

%% Plot Likelihood

figure; hold on;
plot(-logliks);
title('Log lik vs epoch');
xlabel('epoch');

%% Plot result Priors_k, Mu_k, Sigma_k for k=END

close all;
figure; hold on;grid on; box on;
plot_gmm_contour(gca,Priors_k,Mu_k,Sigma_k,[0 0 1],1);
plot(X(1,:),X(2,:),'r+');

for k=1:3
        %(D x N)
    x = repmat(Mu_k(:,k),1,size(dMu,2));
end

axis equal;

%% EM solution

EM(X, Priors_I, Mu_I, Sigma_I,'full');

%%

Priors_I = ones(1,3)./3;
Mu_I     = [ [-8;-2],[8;0],[0;8] ];
for i=1:3
    Sigma_I(:,:,i) = eye(2,2);
end

K       = 50;
options = statset('Display','final','MaxIter',K);
S       = struct('mu',Mu_I','Sigma',Sigma_I,'ComponentProportion',Priors_I);
GMModel = fitgmdist(X',3,'Options',options,'CovarianceType','full','Start',S);

Priors_k        = GMModel.ComponentProportion;
Mu_k            = GMModel.mu';
Sigma_k         = GMModel.Sigma;


function result=halfspacedepth(u,v,x,y)

%HALFSPACEDEPTH computes the halfspace depth of a (two-dimensional) point theta
% relative to a bivariate data set.
%
% The algoritm is described in:
%    Rousseeuw, P., Ruts, I. (1996),
%    "AS 307: Bivariate Location Depth",
%    Applied Statistics (JRSS-C), 45, 516-526.
%
% Required input arguments:
%            u : first coordinate of the point theta
%            v : second coordinate of the point theta
%            x : vector containing the first coordinates of all the data
%                points
%            y : vector containing the second coordinates of all the data
%                points
%
% I/O: [result] = halfspacedepth(u,v,x,y);
%
% This function is part of the Matlab Library for Robust Analysis,
% available at:
%           http://wis.kuleuven.be/stat/robust.html
%
% Written by Fabienne Verwerft
%
%
% Checking input
%
if not(length(x)==length(y))
    error('The vectors x and y must have the same length.')
end
if sum(isnan(x))>=1 || sum(isnan(y))>=1
    error('Missing values are not allowed')
end
%
% m is the number of data points that coincide with theta
%
eps=0.000001;
n=length(x);
norm=sqrt((x-u).^2 + (y-v).^2);
m=sum(norm<=eps);
ll=find(norm>eps);
norm=norm(ll);
xn=(x(ll)-u)./norm;
yn=(y(ll)-v)./norm;
%
% The vector containes the indices of the elements of x and y that satisfy
% the conditions.
%
k=find((abs(x(ll))>abs(y(ll))) & (xn>=0));
alfa(k)=asin(yn(k));
t=find(alfa(k)<0);
alfa(k(t))=2*pi+alfa(k(t));
k=find((abs(x(ll))>abs(y(ll))) & (xn<0));
alfa(k)=pi-asin(yn(k));
k=find((abs(x(ll))<=abs(y(ll))) & (yn>=0));
alfa(k)=acos(xn(k));
k=find((abs(x(ll))<=abs(y(ll))) & (yn<0));
alfa(k)=2*pi-acos(xn(k));
g=find(alfa>=(2*pi-eps));
alfa(g)=0;
%
nn=n-m;
if nn <= 1
    hdepth=m;
    result=hdepth;
    return
    % all data points coincide with theta
end
%
alfa=sort(alfa);
%
hoek=max(alfa(1)-alfa(nn)+2*pi,max(diff(alfa)));
if hoek > pi+eps
    hdepth=m;
    result=hdepth;
    return
    % hdepth=0 because theta lies outside the datacloud
end
%
% rotation around theta
% nu is the number of angles in the upper halfcircle
%
alfa=alfa-alfa(1);
nu=sum(alfa < (pi-eps));

if nu >= nn
    hdepth=m;
    result=hdepth;
    return
    % hdepth=0 every angle in the upper halfcircle so theta outside the
    % datacloud.
end
%
% construction of the array F
%
beta=alfa+pi;
alfatwee=alfa+2*pi;
A=[alfa,alfatwee,beta];
Aindex(1:2*nn)=1;
Aindex((2*nn+1):3*nn)=0;
[As,Asin]=sort(A);
Aindexs=Aindex(Asin);
pp=cumsum(Aindexs);
juisten=find(Aindexs==0);
F=pp(juisten);
%
% Adjust the array F for the angles that coincide with beta.
%
gelijkab=intersect(find(diff(As)<=eps)+1,juisten);
betagelijka=Asin(gelijkab);
if length(gelijkab)>0
    for i=1:length(gelijkab)
        aantal=sum((As(Aindexs==1)+eps)<As(gelijkab(i)));
        F(betagelijka(i)-2*nn)=aantal;
    end
end
%
gindex=find(diff(alfa)==0)+1;
G=0:(nn-1);
%
% Adjust the array G for angles alfa who coincide
%
if length(gindex)>0
    for i=1:length(gindex)
        aantal=sum(alfa(1:gindex(i))<alfa(gindex(i)));
        G(gindex(i))=aantal;
    end
end
%
k=F-G;
numh=min(min(k,(nn-k)));
result=(numh+m);


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION: computes the angular displacements of a damped pendulum under
%           gravity
%
% PURPOSE: to illustrate that changing the pendulum bob's radius results in
%          significant dynamical differences in the pendulum system
%
% Author: N.A. Battista
% Date: 12/13/2019
% Institution: The College of New Jersey
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function damped_pendulum_diff_r()

%
% Physical Parameters
%
m = 100;    % Mass of Pendulum bob
g=9.80665;  % Gravitational Acceleration;
L=0.2;      % Length of Pendulum

%
% Radii of Bobs (here - all different)
%
rVec = 100*[0.0025 0.005 0.01 0.015 0.02 0.025];

%
% Damping Parameter (here - all the same)
%
bVec = 50*ones(1,6);

%
% Temporal Parameters
%
t=0;        % initial time
tFinal = 24; % final-time
dt = 1e-3;  % time-step
ct=1;       % counter
tVec(ct)=t; % time vector storage

%
% Moment of Inertia
%
IVec = m*(0.5*rVec.^2+L^2);

%
% Initial Angular Displacement
%
ang = -(pi/2-pi/5)*ones(1,6);
phi = zeros( size( ang ) );

%
% Perform the time-stepping, e.g., solve the ODEs
%
while t<=tFinal

    % increment the storage counter
    ct = ct+1;

    % increment time
    t = t+dt;

    % save current time
    tVec(ct) = t;

    % solve 1st order ODE for angular displacement
    ang(ct,:) = ang(ct-1,:) + dt * ( phi(ct-1,:) );

    % solve 1st order ODE for angular velocity
    phi(ct,:) = phi(ct-1,:) + dt * ( -m*g*L ./IVec .* sin( ang(ct-1,:) ) - bVec.*phi(ct-1,:)./IVec );

end

%
% Defining Colors for Plotting Data
%
color2 = [0.635 0.078 0.184];  % dark red
color5 = [0.9 0.525 0.098];    % orange
color6 = [0.929 0.840 0.1250]; % dark yellow
color7 = [0.7 0.7 0];          % 'ugly' green
color13 = [0 0.5 0.5];             % green

%
% Note discrepancy is a bit off due to small angle approximation:
% sin(theta) ~ theta gives below period of oscillation
%
T1 = 2*pi*sqrt( IVec(2) / (m*g*L) );
%
% Actually computed value of period is:
T1 = 1.93;

%
% Make Figure of Angular Displacement vs. Non-dimensional Time (# of oscillations of 'r' case)
%
lw=6;
fs=18;
plot(tVec/T1,ang(:,1),'k-','LineWidth',lw); hold on;
plot(tVec/T1,ang(:,2),'b-','LineWidth',lw,'Color',color2); hold on;
plot(tVec/T1,ang(:,3),'g-','LineWidth',lw,'Color',color5); hold on;
plot(tVec/T1,ang(:,4),'r-','LineWidth',lw,'Color',color6); hold on;
plot(tVec/T1,ang(:,5),'c-','LineWidth',lw,'Color',color7); hold on;
plot(tVec/T1,ang(:,6),'c-','LineWidth',lw,'Color',color13); hold on;
plot(tVec/T1,ang(:,5),'c-','LineWidth',lw,'Color',color7); hold on;
plot(tVec/T1,ang(:,4),'r-','LineWidth',lw,'Color',color6); hold on;
plot(tVec/T1,ang(:,3),'g-','LineWidth',lw,'Color',color5); hold on;
plot(tVec/T1,ang(:,2),'b-','LineWidth',lw,'Color',color2); hold on;
plot(tVec/T1,ang(:,1),'k-','LineWidth',lw); hold on;
xlabel('Non-Dimensional Time (# periods of r-case)');
ylabel('Angular Displacement (Radians)');
axis([0 12 -1 1.5]);
leg=legend('$\frac{1}{2}$r','r','2r','3r','4r','5r','Orientation','horizontal','interpreter','latex');
set(gca,'FontSize',fs);
set(leg,'FontSize',fs+2);
leg.NumColumns=3;


  function x = sinc_periodic(t, K)
%|function x = sinc_periodic(t, K)
%| periodic sinc function, obtained by replicates of a sinc:
%| x(t) = \sum_l sinc(t - l K) = ... = sin(pi*t) / tan(pi*t/K) / K for K even.
%| This function is bandlimited and its samples are an impulse train.
%| It is closely related to the Dirichlet function diric() for odd K,
%| but it differs for even K.
%| Copyright 2003-11-2, Jeff Fessler, University of Michigan

if nargin < 1, ir_usage, end
if streq(t, 'test'), sinc_periodic_test, return, end

if ~rem(K,2) % even
	d = tan(pi*t/K);
	j = abs(d) > 1e-12;
	x = ones(size(t));
	t = t(j);
	d = d(j);
	x(j) = sin(pi*t) ./ d / K;
else
	x = nufft_diric(t, K, K, 1);
%	xo = diric(2*pi*t/K,K); % would require matlab's signal toolbox
%	max_percent_diff(xo, x)
end

%
% self test
%
function sinc_periodic_test

Klist = [4 5];
im clf, pl=220;
for kk=1:2
	K = Klist(kk);
	n = [0:(4*K)]';
	t = linspace(0,4*K,401)';
	x = @(t,K) sinc_periodic(t, K);
%	y = @(t,K) diric(2*pi*t/K,K); % would require matlab's signal toolbox
	y = @(t,K) nufft_diric(t,K,K,1);
	if im
		subplot(pl+kk+0)
		plot(t, x(t,K), '-', n, x(n,K), 'o')
		titlef('Sinc-Periodic K=%d', K)
		axis([0 4*K -1 1]), xtick([0:4]*K), grid
		subplot(pl+kk+2)
		plot(t, y(t,K), '-', n, y(n,K), 'o')
		titlef('Dirichlet K=%d', K)
		axis([0 4*K -1 1]), xtick([0:4]*K), grid
		ylabelf('K=%d', K)
	end
end


% solution of Poisson equation using sparse matrix
%
%  E.Holzbecher,    18.3.2011
%
%--------------------------------------------------
nx = 12; ny = 12;      % dimensions in x- and y-direction
h = 1/4;                % grid spacing

% boundary type indicators (1=Dirichlet, 0=Neumann no-flow)
ltop = logical(zeros(1,nx));         % top
lbottom = logical(zeros(1,nx));      % bottom
lleft = logical([ones(6,1) zeros(6,1)]);       % left
lright = logical([zeros(6,1) ones(6,1)]);      % right

% boundary values (Dirichlet only)
btop = ones(1,nx);                  % top
bbottom = zeros(1,nx);              % bottom
bleft = ones(ny,1);                 % left
bright = zeros(ny,1);               % right

q = 1*ones(nx,ny);                  % right hand side (source term)

N = nx*ny;
d = [-nx,-1,0,1,nx];
B = [ones(N,2) -4*ones(N,1) ones(N,2)];
q = reshape(q,N,1);
b = -h*h*q.*ones(N,1);
for i = 1:nx
    if ltop(i)
        b(i) = b(i)-btop(i);
    else
        B(i,3) = -3;
        %B(i-1,1) = 0;
    end
    if lbottom(i)
        b(N-nx+i) = b(N-nx+i)-bbottom(i);
    else
        B(N-nx+i,3) = -3;
        % B(N-nx+i,5) = 0;
    end
end
for i = 1:ny
    B(i*nx,2) = 0;
    if i<ny B(i*nx+1,4) = 0; end
    if lleft(i)
        b((i-1)*nx+1) = b((i-1)*nx+1)-bleft(i);
    else
        B((i-1)*nx+1,3) = B((i-1)*nx+1,3)+1;
    end
    if lright(i)
        b(i*nx) = b(i*nx)-bright(i);
    else
        B(i*nx,3) = B(i*nx,3)+1;
    end
end

A = spdiags(B,d,N,N);

% processing: solution
U = A\b;
U = reshape(U,nx,ny);

% check & visualize
4*del2(U)
surf (U)


function yp = p06_fun ( neqn, t, y )

%*****************************************************************************80
%
%% P06_FUN evaluates the function for problem P06.
%
%  Discussion:
%
%    y1' = 2 y1 * ( 1 - y2 )
%    y2' = - y2 * ( 1 - y1 )
%    y1(0) = 1
%    y2(0) = 3
%
%    2 equations.
%    Enright and Pryce nonstiff problem #B1.
%    Autonomous.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Wayne Enright, John Pryce,
%    Algorithm 648,
%    ACM Transactions on Mathematical Software,
%    Volume 13, Number 1, pages 28-34.
%
%  Parameters:
%
%    Input, integer NEQN, the number of equations.
%
%    Input, real T, Y(NEQN), the arguments of the derivative
%    function.
%
%    Output, real YP(NEQN), the value of the derivative function.
%
  yp = zeros ( neqn, 1 );

  yp(1) = 2.0 * y(1) * ( 1.0 - y(2) );
  yp(2) =     - y(2) * ( 1.0 - y(1) );

  return
end


function n = tetrahedron_unit_lattice_point_num_3d ( s )

%*****************************************************************************80
%
%% TETRAHEDRON_UNIT_LATTICE_POINT_NUM_3D counts lattice points.
%
%  Discussion:
%
%    The tetrahedron is assumed to be the unit tetrahedron:
%
%    ( (0,0,0), (1,0,0), (0,1,0), (0,0,1) )
%
%    or a copy of this tetrahedron scaled by an integer S:
%
%    ( (0,0,0), (S,0,0), (0,S,0), (0,0,S) ).
%
%    The routine returns the number of integer lattice points that appear
%    inside the tetrahedron, or on its faces, edges or vertices.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    03 July 2009
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Matthias Beck, Sinai Robins,
%    Computing the Continuous Discretely,
%    Springer, 2006,
%    ISBN13: 978-0387291390,
%    LC: QA640.7.B43.
%
%  Parameters:
%
%    Input, integer S, the scale factor.
%
%    Output, integer N, the number of lattice points.
%
  n = ( ( s + 3 ) * ( s + 2 ) * ( s + 1 ) ) / 6;

  return
end


%The purpose of this program is to implement Galerkin method over
% the entire domain for solving the following general 2nd order,
% homogeneous, Boundary Value problem (BVP) with constant coefficients, and
% then comparing the answer with the exact solution.
%==========================================================================
%               ax"(t)+bx'(t)+cx(t)=0 for t1<=t<=t2
%                   BC: x(t1)=x1 and x(t2)=x2
% >> BVP_Galerkin1(a,b,c,t1,t2,x1,x2,n)
% where "n" is the number of trial functions
% The output of this program is
% 1- The approximated solution of x(t) vs. exact solution of x(t)
% 2- The approximated x'(t) vs. exact x'(t)
% 3- The approximated x"(t) vs. exact x"(t)
% ======Example============================================================
% Equation                  x"(t)+ x'(t)+ x(t)=0
% Boundary values           x(1)=2,     x(10)=0;
% Solution: We have:
%                           a=1;    b=1;   c=1;
%                           t1=1;       t2=10;
%                           x1=2;       x2=0;
% Using n=8 tiral functions,
% >>BVP_Galerkin(1,2,3,1,10,2,0,8)
%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%                   October.26, 2010, Ramin Shamshiri
%                       ramin.sh@ufl.edu
%            Doctoral student at the University of Florida
%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function BVP_Galerkin1(a,b,c,t1,t2,x1,x2,n) % Declare function
dt=0.001; % increment
%% Begin Approximate solution via Galerkin method over the entire domain

for i=1:n
    for j=1:n
    K1(i,j)=(i*j)*(t2^(j+i-1)-t1^(j+i-1))/(i+j-1);          % K1 matrix corresponding to the x"(t)
    K2(i,j)=j*((t2^(i+j))-(t1^(i+j)))/(i+j);                % K2 matrix corresponding to the x'(t)
    K3(i,j)=(t2^(i+j+1)-(t1^(i+j+1)))/(i+j+1);              % K3 matrix corresponding to the x(t)
    end
end
% Overall Matrix
K=-a*K1+b*K2+c*K3;

%Applying boundary conditions and Solving nxn system of equations
for i=1:n-1
     for j=1:n
         A(i,j)=K(i,j)+((j*a*t2^(j+i-1))-(j*a*t1^(j+i-1)));

     end
end

%Applying boundary conditions
for j=1:n
    A(n-1,j)=(t1^j);
    A(n,j)=(t2^j);
end

for i=1:n-1
    B(i,1)=0;
end
B(n-1,1)=x1;
B(n,1)=x2;

C=inv(A)*B; % Ci: Coefficients of terms

t=t1:dt:t2;
t=t';
% Creating vertical axis values, x(t)
x=  zeros((t2-t1)/dt+1,1);
for i=1:(t2-t1)/dt+1
    for j=1:n
        x(i,1)=x(i,1)+ C(j,1)*(t(i,1)^j);
    end
end

% calculating x'(t)
dx=zeros((t2-t1)/dt+1,1);
for i=2:(t2-t1)/dt+1
    dx(i,1)=(x(i)-x(i-1))/dt;
end
% calculating x"(t)
d2x=zeros((t2-t1)/dt+1,1);
for i=3:(t2-t1)/dt+1
    d2x(i,1)=(dx(i)-dx(i-1))/dt;
end

 figure1 = figure('Color',[1 1 1]);
% Plotting approximate solution via Galerkin method over the entire domain
subplot(3,1,1,'Parent',figure1);
% Plotting the Approximate solution in green (Galerkin method over the entire domain)
plot(t,x,'-.', 'Color','r', 'LineWidth',2), grid on; hold on;
% Plotting the approximate dx
subplot(3,1,2,'Parent',figure1);
plot(t,dx, '-.', 'Color','r', 'LineWidth',2), grid on; hold on;
% Plotting the approximate d2u
subplot(3,1,3,'Parent',figure1);
plot(t,d2x, '-.', 'Color','r', 'LineWidth',2), grid on; hold on;
%% End of approximate solution via Galerkin method over the entire domain

%% ==============Begin Calculating Exact Soution==========================
r=roots([a b c]);   % Roots of auxiliary equation
r1=r(1);  r2=r(2);

% Bulding t-axis values
t=t1:dt:t2; t=t';
s=size(t);

% Bulding x(t) axis values
x=zeros(s(1),1);
if r1==r2   % For critically damped case

    C=inv([exp(r1*t1)  t1*exp(r2*t1);exp(r1*t2)  t2*exp(r2*t2)])*([x1;x2]);
    C1=C(1);
    C2=C(2);

    for i=1:s(1)
        x(i)=C1*exp(r1*t(i))+C2*t(i)*exp(r2*t(i));
    end

else        % For Under-damped or Over-damped case

    C=inv([exp(r1*t1) exp(r2*t1);exp(r1*t2) exp(r2*t2)])*([x1;x2]);
    C1=C(1);
    C2=C(2);

    for i=1:s(1)
        x(i)=C1*exp(r1*t(i))+C2*exp(r2*t(i));
    end
end

% calculating x'(t)
dx=zeros(s(1),1);
for i=2:s(1)
    dx(i,1)=(x(i)-x(i-1))/dt;
end

% calculating x"(t)
d2x=zeros(s(1),1);
for i=3:s(1)
    d2x(i,1)=(dx(i)-dx(i-1))/dt;
end

% Plotting Exact solution
subplot(3,1,1,'Parent',figure1);
% Plotting the exact solution x(t) in blue
plot(t,x, 'Color','b', 'LineWidth',2);
xlabel('Time (sec)','FontSize',12);
ylabel('x(t) (m)','FontSize',12);
legend1 = legend(subplot(3,1,1),'show');
legend('Approximate x(t)','Exact x(t)')

% Plotting the exact solution x'(t) in blue
subplot(3,1,2,'Parent',figure1);
plot(t,dx, 'Color','b', 'LineWidth',2);
xlabel('Time (sec)','FontSize',12);
ylabel('dx/dt (m/s)','FontSize',12);
legend1 = legend(subplot(3,1,2),'show');
legend('Approximate dx(t)','Exact dx(t)')

% Plotting the exact solution x"(t) in blue
subplot(3,1,3,'Parent',figure1);
plot(t,d2x, 'Color','b', 'LineWidth',2);
xlabel('Time (sec)','FontSize',12);
ylabel('d^2x/dt^2 m/s^2','FontSize',12);
legend1 = legend(subplot(3,1,3),'show');
legend('Approximate d2x(t)','Exact dx(t)')
clc
%% =====================End of exact solution==============================


function [S,C]=allsums(varargin)
% ALLSUMS Distribution of unique sums among all combinations of vectors.
%   [S,C]=ALLSUMS(IN) depending on input IN, will do one of two different
%   procedures for calculating all unique combinations of sums.
%
%   The output vectors, S and C, are respectively the list of unique
%   sums, and the count distribution for those sums among all combinations.
%
%
%   SINGLE INPUT:
%
%   [S,C]=ALLSUMS(VEC) for a single input vector of length N, returns the
%   distribution of unique sums among the (2^N)-1 combinations of
%   non-empty subsets of elements within VEC.
%
%    EXAMPLE:
%      Number of ways to have a total of 250 using only the odd numbers
%      from 1 to 100.
%      [S,C]=allsums(1:2:100);
%      num=C(S==250)
%
%
%   MULTIPLE INPUTS:
%
%   [S,C]=ALLSUMS(VEC,K) with vector VEC of length N, assumes the
%   equivalent scenario of rolling a N-sided die, with values VEC,
%   K times and returns the distributions of unique sums among all
%   N^K combinations of values.
%
%   [S,C]=ALLSUMS(VEC1,K1,VEC2,K2,...) with vectors of length N1, N2, ...
%   assumes the equivalent scenario of rolling a N1-sided die, with
%   values VEC1, K1 times; then rolling a N2-sided dice, with values VEC2,
%   K2 times; etc. and returns the distribution of unique sums among
%   all (N1^K1)*(N2^K2)*... combinations of values
%
%    SINGLE VECTOR, REPEATED
%      Probability distribution of rolling a regular 6-sided die 100 times
%      [S,C]=allsums(1:6,100);
%      plot(S,C./sum(C)), grid on
%
%    MULTIPLE VECTORS, REPEATED
%      Probability of the total yielding exactly zero when rolling a
%      A) six-sided die with values [-5:0] ten times, and then a
%      B) ten-sided die with values [-4:5] twenty times.
%      [S,C]=allsums([-5:0],10,[-4:5],20);
%      prob=C(S==0)/sum(C)
%

%   Mike Sheppard
%   Last Modified: 27-Oct-2011

%ERROR CHECKING
ninputs=numel(varargin);
switch ninputs
    case 0
        error('allsums:Inputs','Requires at least one input');
    case 1
        VEC=varargin{1}; %Input vector
        if any(~isfinite(VEC))
            error('allsums:Inputs','Requires input vector to be numeric');
        end
    otherwise
        num=ninputs/2;
        if mod(ninputs,2)~=0
            error('allsums:Inputs','Requires inputs to be in [Vector],[Number] order');
        end
        for k=1:num
            ALLVEC{k}=varargin{2*k-1}; ALLNUMR{k}=varargin{2*k}; numr=ALLNUMR{k};
            if any(~isfinite(ALLVEC{k}))
                error('allsums:Inputs','Requires all input vectors to be numeric');
            end
            if any([~isfinite(numr) ~isscalar(numr) numr~=round(numr) numr<=0])
                error('allsums:Inputs','Requires number of repetitions to be a positive scalar integer');
            end
        end
end

%ALGORITHM
switch ninputs
    case 1
       % Distribution of unique sums among the (2^N)-1 combinations of
       % non-empty subsets of elements within VEC.
        S=[]; C=[];
        for k=1:numel(VEC)
            [S,ign,indx]=unique([S VEC(k) S+VEC(k)]);
            C=accumarray(indx',[C 1 C])';
        end
        S=S(:); C=C(:);
    otherwise
        % Distribution of unique sums among all (N1^K1)*(N2^K2)*...
        % combinations of vectors of length N_k repeated K_k times,
        % with values VEC_k each.
        S=0; C=1;
        for k=1:num
            VEC=ALLVEC{k}; VEC=VEC(:); numr=ALLNUMR{k};
            for n=1:numr
                tempv=bsxfun(@plus,S',VEC);
                tempc=repmat(C',length(VEC),1);
                [S,ign,indx]=unique(tempv(:));
                C=accumarray(indx,tempc(:));
            end
        end
end

end


function OUT = MovCorrCent(X, window, i)
% =======================================================================
% Computes correlation between X_{i} and X_j for all j different
% of i, from windowdowSize to the number of observations.  The
% first windowdowSize rows are NaN.
% =======================================================================
% OUT = MovCorr(X, windowdowSize, i)
% -----------------------------------------------------------------------
% INPUT
%   - X: panel time series T observations x N variables
%   - windowdow: size of the moving windowdow
%   - i: the variable X_i against which correlations should be returned
% -----------------------------------------------------------------------
% OUTPUT
%   - OUT: matrix with moving correlation T observations x N-1
%       variables. The first windowdowSize-1 rows are NaN.
% =======================================================================
% EXAMPLE
% X = rand(100,5);
% OUT = MovCorrCent(X,10,1)
% =======================================================================
% Ambrogio Cesa Bianchi, March 2015

[nobs,nvars] = size(X);
OUT = nan(nobs,nvars-1);

for tt = window+1:nobs-window
    C = corrcoef(X(tt-window:tt+window, :));
    idx = setdiff(1:nvars, i);
    OUT(tt, :) = C(i, idx);
end


% <Purpose>
%    Computing the numerical rank of a downdated matrix.
%
% <Syntax>
%    [r,Basis,C] = NumericalRankDowndate(A,pth,C,RC)
%
% <Input Parameters>
%  1.   A -- the target matrix;
%  2. pth -- the index of row/column to be deleted;
%  3.   C -- cell array contains information required by updating/downdating;
%  4.  RC -- Set to 'row', then the pth row will be deleted.
%            Set to 'column', then the pth column will be deleted.
%
% <Output Parameters>
%  1. r     -- the numerical rank of the downdated matrix;
%  2. Basis --
%         For high rank cases...
%             a matrix whose columns form an orthonormal basis of
%             the numerical kernel;
%
%         For low rank cases...
%             a matrix whose columns form an orthonormal basis of
%             the numerical range;
%
%  3.     C -- Matlab cell array
%
%     For high rank cases...
%         C{1,1} = rank : the numerical rank of the downdated matrix;
%         C{2,1} = Basis : matrix whose columns form an orthonormal kernel basis;
%         C{3,1} = Q : the Q in the QR decomposition of the kernel stacked matrix;
%         C{4,1} = R : the R in the QR decomposition of the kernel stacked matrix;
%         C{5,1} = tau : scaling factor in the kernel stacked matrix;
%         C{6,1} = tol : the rank decision threshold;
%
%     For low rank cases...
%         C{1,1} = rank : the numerical rank of the downdated matrix;
%         C{2,1} = U : the U in the USV+E decomposition of the downdated matrix;
%         C{3,1} = V : the V in the USV+E decomposition of the downdated matrix;
%         C{4,1} = S : the S in the USV+E decomposition of the downdated matrix;
%         C{5,1} = tol : the rank decision threshold;
%
% <Reference>
%   [1] T.Y. Li and Z. Zeng, "A Rank-Revealing Method with Updating, Downdating
%       and Applications", SIAM J. Matrix Anal. and Appl., 26 (2005), pp. 918--946.
%
%   [2] T.L. Lee, T.Y. Li and Z. Zeng, "A Rank-Revealing Method with Updating,
%       Downdating and Applications, Part II", SIAM J. Matrix Anal. and Appl. (2009).


function value = r8vec_length ( dim_num, x )

%*****************************************************************************80
%
%% R8VEC_LENGTH returns the Euclidean length of an R8VEC
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 August 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the spatial dimension.
%
%    Input, real X(DIM_NUM), the vector.
%
%    Output, real VALUE, the Euclidean length of the vector.
%
  value = sqrt ( sum ( ( x(1:dim_num) ).^2 ) );

  return
end


function ndbi = NDBI( nir, swir )
%NDBI Calculate Normalized Difference Build-up Index (NDBI) using NIR and
%     SWIR bands.
% Syntax
%
%     ndbi = NDBI(swir,nir)
%
% Description
%
%     This function calculates Normalized Difference Build-up Index (NDBI)
%     using SWIR and NIR bands (as following equation).
%
% Input arguments
%
%     swir        Short-wave infrared band
%     nir         Near infrared band
%
% Output arguments
%
%     ndbi        Normalized Difference Build-up Index
%
%
% Author: Shi Qiu (shi.qiu@ttu.edu)
% Date: 19. Dec., 2017

    % calculate NDBI
    ndbi=(swir-nir)./(swir+nir);

    % fix unnormal pixels
    % not 0.01 any more because we will identify urban pixel using ndbi more than 0.
%     ndbi((nir+swir)==0)=0.0;

end


function value = g_hofstadter ( n )

%*****************************************************************************80
%
%% G_HOFSTADTER computes the Hofstadter G sequence.
%
%  Discussion:
%
%    G(N) = 0                      if N = 0
%         = N - G ( G ( N - 1 ) ), otherwise.
%
%    G(N) is defined for all nonnegative integers.
%
%    The value of G(N) turns out to be related to the Zeckendorf
%    representation of N as a sum of non-consecutive Fibonacci numbers.
%    To compute G(N), determine the Zeckendorf representation:
%
%      N = sum ( 1 <= I <= M ) F(I)
%
%    and reduce the index of each Fibonacci number by 1:
%
%      G(N) = sum ( 1 <= I <= M ) F(I-1)
%
%    However, this is NOT how the computation is done in this routine.
%    Instead, a straightforward recursive function call is defined
%    to correspond to the definition of the mathematical function.
%
%  Table:
%
%     N  G(N)  Zeckendorf   Decremented
%    --  ----  ----------   -----------
%
%     1   1    1            1
%     2   1    2            1
%     3   2    3            2
%     4   3    3 + 1        2 + 1
%     5   3    5            3
%     6   4    5 + 1        3 + 1
%     7   4    5 + 2        3 + 1
%     8   5    8            5
%     9   6    8 + 1        5 + 1
%    10   6    8 + 2        5 + 1
%    11   7    8 + 3        5 + 2
%    12   8    8 + 3 + 1    5 + 2 + 1
%    13   8    13           8
%    14   9    13 + 1       8 + 1
%    15   9    13 + 2       8 + 1
%    16  10    13 + 3       8 + 2
%    17  11    13 + 3 + 1   8 + 2 + 1
%    18  11    13 + 5       8 + 3
%    19  12    13 + 5 + 1   8 + 3 + 1
%    20  12    13 + 5 + 2   8 + 3 + 1
%    21  13    21           13
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 July 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Douglas Hofstadter,
%    Goedel, Escher, Bach,
%    Basic Books, 1979.
%
%  Parameters:
%
%    Input, integer N, the argument of the function.
%
%    Output, integer VALUE, the value of the function.
%
  if ( n <= 0 )
    value = 0;
  else
    value = n - g_hofstadter ( g_hofstadter ( n-1 ) );
  end

  return
end