function [x,f,info]=convexQuadProgSOCP(G,a,C,b,numEqConst,params)
%%CONVEXQUADPROGSOCP Perform quadratic programming on a convex problem.
%                Specifically, this algorithm solves the optimization
%                problem
%                minimize_x a'*x+(1/2)*x'*G*x
%                such that C(:,1:numEqConst)'*x=b
%                      and C(:,(numEqConst+1):end)'*x>=b
%                Convexity means that G is positive (semi)definite. This
%                reformulates the problem as a second order cone problem
%                and then uses splittingConicSolver to solve the problem.
%                Unlike the active set method of [2], this formulation
%                tends to converge slowly on large problems (large being,
%                for example, 81 dimensions).
%
%INPUTS: G An nXn real, positive definite symmetric matrix (n>0).
%        a An nX1 real vector.
%        C An nXm real matrix (m>=0). The first numEqConst constraints (the
%          equality constraints) must be linearly independent or the
%          algorithm will identify the problem as infeasible.
%        b An mX1 vector.
% numEqConst The number of constraints in C that are equality constraints
%          (numEqConst<=m). If this parameter is omitted or an empty matrix
%          is passed, the default numEqConst=0 is used.
%   params Parameters that affect how the function splittingConicSolver,
%          which is used by this function, works. See the comments to
%          splittingConicSolver for more information.
%
%OUTPUTS: x The nX1 solution to the optimization problem or an empty matrix
%           if the problem is infeasible or unbounded.
%         f The value of the objective function at x, or an empty matrix
%           if the problem is infeasible or unbounded.
%      info The problem is formulated as a second-order cone optimization
%           problem. This is the information regarding the termination
%           state returned by the splittingConicSolver function.
%
%As shown in [1], the equivalent second order cone optimization problem is
%minimize t
%subject to norm(SG*x+SG\a)<=t
%       and C(:,1:numEqConst)'*x=b(1:numEqConst)
%       and C(:,(numEqConst+1):end)'*x>=b((numEqConst+1):end)
%       where SG=sqrtm(G)
%The function splittingConicSolver is used to solve the problem.
%
%EXAMPLE 1:
%This is the example worked out step-by-step in [2]:
% G=[4, -2;-2, 4];
% b=[0;0;2];
% a=[6;0];
% C=[1,0,1;
%    0,1,1];
% [x,f,info]=convexQuadProgSOCP(G,a,C,b)
%The optimal solution can be seen to be x=[0.5;1.5] and f=6.5;
%
%EXAMPLE 3:
%This is an example of a problem having both inequality and equality
%constraints:
% G=[4, -2;-2, 4];
% b=[2;1.6];
% a=[6;0];
% C=[1,0;
%    1,1];
% numEqConst=1;%One equality constraint.
% [x,f,exitCode]=convexQuadProgSOCP(G,a,C,b,numEqConst)
%The optimal solution is x=[0.4;1.6] and f=6.56.
%
%REFERENCES:
%[1] S. Lobo, Miguel, L. Vandenberg, S. Boyd, and H. Lebret, "Applications
%    of second-order cone programming," Linear Algebra and its
%    Applications, vol. 284, no. 1, pp. 193-228, 1998.
%[2] D.Goldfarb and A. Idnani, "A numerically stable dual method for
%    solving strictly convex quadratic programs," Mathematical Programming,
%    vol. 27, no. 1, pp. 1-33, Sep. 1983.
%
%February 2016 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

if(nargin<5||isempty(numEqConst))
   numEqConst=0;
end

if(nargin<6)
   params=[];
end

if(numEqConst>size(C,1))
   error('numEqConst is larger than the number of constraints in C')
end

P0=G;
%The real command can help deal with finite precision issues.
P0Root=real(sqrtm(P0));
q0=a;
Aeq=C(:,1:numEqConst)';
beq=b(1:numEqConst);
ALeq=-C(:,(numEqConst+1):end)';
bLeq=-b((numEqConst+1):end);

numIneqConst=length(bLeq);

%The extra variable t is appended to the end.
numDim=length(a);
c=zeros(numDim+1,1);
c(end)=1;

%Allocate space.
numVar=numEqConst+numIneqConst+numDim+1;
F=zeros(numVar,numDim+1);
g=zeros(numVar,1);

%First, the equality constraints.
F(1:numEqConst,1:numDim)=Aeq;
g(1:numEqConst)=beq;
curRow=numEqConst+1;
cone=[];
cone.f=numEqConst;

%Next, the inequality constraints
sel=curRow:(curRow+numIneqConst-1);
F(sel,1:numDim)=ALeq;
g(sel)=bLeq;
cone.l=numIneqConst;
curRow=curRow+numIneqConst;

%Finally, the quadratic constraint.
F(curRow,:)=-c';
g(curRow)=0;
curRow=curRow+1;

sel=curRow:(curRow+numDim-1);
F(sel,1:numDim)=-P0Root;
%g(sel)=P0Root\q0;
g(sel)=pinv(P0Root)*q0;
cone.q=numDim+1;

[x,~,~,info]=splittingConicSolver(F,g,c,cone,params);

if(~isempty(x))
    x=x(1:numDim);%Get rid of the auxiliary variable.
    f=a'*x+(1/2)*x'*G*x;
else
    f=[];
end

end

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


function[varargout]=ecconv(varargin)
%ECCONV  Converts between eccentricity measures.
%
%   Y=ECCONV(X,STR) converts the eccentricity measure X into eccentricity
%   measure Y as specified by the string STR.
%
%   STR is of the form 'in2out' where the names 'in' and 'out' may be
%   chosen from the following table.
%
%       STR        Name                    Definition
%       ----------------------------------------------------------------
%      'ecc'       Eccentricity            sgn(b)*sqrt(1-b^2/a^2)
%      'ell'       Ellipticity             b/a
%      'lin'       Linearity               sgn(b)*(a^2-b^2)/(a^2+b^2)
%      'circ'      Circularity             2ab/(a^2+b^2)
%      'nu'        Eccentricity angle      asin(b/sqrt(a^2 + b^2))
%      'rot'       Rotary ratio            sgn(b)*(a-abs(b))/(a+abs(b))
%
%   where "a" and "b" are the semi-major and semi-minor axes respective.
%   For example, ECC=ECCONV(L,'lin2ecc') converts the ellipse linearity L
%   into eccentricity ECC.
%
%   All quantities are positive for mathematically positive rotation
%   and negative for mathematically negative rotation.  Note the linearity
%   is undefined for the case of purely circular rotation a=abs(b);
%
%   For further details, see Lilly and Gascard (2006).
%   ____________________________________________________________________
%
%   Cell array input/output
%
%   If ECCONV is given cell array input, it returns cell array output.
%
%   Thus X may be a cell arrays of numerical arrays, and the output Y will
%   also be a cell array having an identical size as X.
%   ____________________________________________________________________
%
%   See also ELLCONV, ELLDIFF, TRANSCONV.
%
%   Usage:   lin=ecconv(b./a,'ell2lin');
%            ecc=ecconv(lin,'lin2ecc');
%
%   'ecconv --t' runs a test.
%   'ecconv --f' generates a sample figure.
%   _________________________________________________________________
%   This is part of JLAB --- type 'help jlab' for more information
%   (C) 2005--2015 J.M. Lilly --- type 'help jlab_license' for details

if strcmpi(varargin{1}, '--t')
  ecconv_test,return
end
if strcmpi(varargin{1}, '--f')
  type makefigs_ecconv
  makefigs_ecconv;
  return
end

%if nargin==2

x=varargin{1};
str=varargin{2};
ecconv_checkstr(str);

if ~iscell(x)
   y=ecconv_one(x,str);
   y(isinf(x))=inf;
else
    for i=1:length(x)
         y{i,1}=ecconv_one(x{i},str);
         y{i}(isinf(x{i}))=inf;
    end
end

varargout{1}=y;

function[y]=ecconv_one(x,str)

sizex=size(x);
x=x(:);

str1=str(1:strfind(str,'2')-1);
str2=str(strfind(str,'2')+1:end);
if aresame(str1,'circ')&&~aresame(str2,'circ')
    lin=sign(x).*sqrt(1-x.^2);
    eval(['y=lin2' str2 '(x);'])
elseif ~aresame(str1,'circ')&&aresame(str2,'circ')
    eval(['lin=' str1 '2lin(x);'])
    y=sign(lin).*sqrt(1-lin.^2);
else
    eval(['y=' str '(x);'])
end
y=reshape(y,sizex);

% elseif nargin==3
%   x1=varargin{1};
%   x2=varargin{2};
%   str=varargin{3};
%   ecconv_checkstr(str);
%   eval(['[y1,y2]=' str '(x1,x2);'])
%   varargout{1}=y1;
%   varargout{2}=y2;
% end

function[]=ecconv_checkstr(str)
ii=strfind(str,'2');
if isempty(ii)
  error('STR should be of the form ''ecc2lin''.')
end
str1=str(1:ii-1);
str2=str(ii+1:end);

if ~aresame(str1,'nu') && ~aresame(str1,'ecc') && ~aresame(str1,'lin') && ~ ...
      aresame(str1,'rot') && ~aresame(str1,'ell') && ~aresame(str1,'circ')
  error(['Input parameter name ' str1 ' is not supported.'])
end
if ~aresame(str2,'nu') && ~aresame(str2,'ecc') && ~aresame(str2,'lin') && ~ ...
      aresame(str2,'rot') && ~aresame(str2,'ell') &&~aresame(str2,'circ')
  error(['Output parameter name ' str2 ' is not supported.'])
end

function[nu]=ell2nu(ell)
nu=atan(ell);
function[ell]=nu2ell(nu)
ell=tan(nu);
function[ecc]=ell2ecc(ell)
ecc=nu2ecc(ell2nu(ell));
function[ell]=ecc2ell(ecc)
ell=nu2ell(ecc2nu(ecc));
function[rot]=ell2rot(ell)
rot=nu2rot(ell2nu(ell));
function[ell]=rot2ell(rot)
ell=nu2ell(rot2nu(rot));
function[lin]=ell2lin(ell)
lin=nu2lin(ell2nu(ell));
function[ell]=lin2ell(lin)
ell=nu2ell(lin2nu(lin));

function[ecc]=nu2ecc(nu)
ecc=sign(nu).*sqrt(1-squared(tan(nu)));
vindexinto(ecc,1,find(nu==0),1);
vindexinto(ecc,0,find(abs(nu)==pi/4),1);

function[nu]=ecc2nu(ecc)
nu=sign(ecc).*atan(sqrt(1-squared(ecc)));
vindexinto(nu,pi/4,find(ecc==0),1);

function[lambda]=nu2lin(nu)
lambda=sign(nu).*cos(2*nu);
vindexinto(lambda,1,find(nu==0),1);
vindexinto(lambda,0,find(abs(nu)==pi/4),1);

function[nu]=lin2nu(lambda)
nu=sign(lambda).*atan(sqrt(frac(1-abs(lambda),1+abs(lambda))));
vindexinto(nu,pi/4,find(lambda==0),1);

function[alpha]=nu2rot(nu)
alpha=sign(nu).*frac(1-abs(tan(nu)),1+abs(tan(nu)));
vindexinto(alpha,1,find(nu==0),1);
vindexinto(alpha,0,find(abs(nu)==pi/4),1);

function[nu]=rot2nu(alpha)
nu=sign(alpha).*atan(frac(1-abs(alpha),1+abs(alpha)));
vindexinto(nu,pi/4,find(alpha==0),1);

function[ecc]=lin2ecc(lambda)
ecc=sign(lambda).*sqrt(frac(2*abs(lambda),1+abs(lambda)));
vindexinto(ecc,0,find(lambda==0),1);

function[lambda]=ecc2lin(ecc)
lambda=sign(ecc).*frac(squared(ecc),2-squared(ecc));
vindexinto(lambda,0,find(ecc==0),1);

function[alpha]=lin2rot(lambda)
alpha=nu2rot(lin2nu(lambda));
vindexinto(alpha,0,find(lambda==0),1);

function[lambda]=rot2lin(alpha)
lambda=nu2lin(rot2nu(alpha));
vindexinto(lambda,0,find(alpha==0),1);

function[alpha]=ecc2rot(ecc)
alpha=nu2rot(ecc2nu(ecc));
vindexinto(alpha,0,find(ecc==0),1);

function[ecc]=rot2ecc(alpha)
ecc=nu2ecc(rot2nu(alpha));
vindexinto(ecc,0,find(alpha==0),1);

function[x]=rot2rot(x)
function[x]=nu2nu(x)
function[x]=ecc2ecc(x)
function[x]=lin2lin(x)
function[x]=ell2ell(x)
function[x]=circ2circ(x)

%/********************************************************
function[]=ecconv_test
str{1}='nu';
str{2}='ecc';
str{3}='lin';
str{4}='rot';
str{5}='ell';

x=rand(100,1)*2-1;
x(end+1,1)=1;  %Add an exact one
x(end+1,1)=0;  %Add an exact zero

clear y z x2 bool

%Turn lambda into all others
for i=1:length(str)
  y(:,i)=ecconv(x,['lin2' str{i}]);
end

%Turn all others into everything else
for i=1:length(str)
  for j=1:length(str)
     z(:,i,j)=ecconv(y(:,i),[str{i} '2' str{j}]);
  end
end

%Turn everything back into lambda
for i=1:length(str)
  for j=1:length(str)
     x2(:,i,j)=ecconv(z(:,i,j),[str{j} '2lin']);
  end
end

for i=1:size(x2,2)
  for j=1:size(x2,2)
    bool(i,j)=aresame(squeeze(x2(:,i,j)),x,1e-14);
  end
end

reporttest('ECCONV', allall(bool))
%\********************************************************

% %Not currently used
% figure
% lambda=(0:.001:1)';
%
% ecc=ecconv(lambda,'lin2ecc');
% alpha=ecconv(lambda,'lin2rot');
% ecc1=sqrt(2)*sqrt(lambda);
% alpha1=lambda/2;
%
% plot(lambda,[ecc,alpha,ecc1,alpha1]);
% linestyle k 2k k-- 2k--
% axis([0 1 0 1]),axis square
% text(0.4,0.7,'\epsilon')
% text(0.7,0.5,'\alpha')
% title('Eccentricity measures')
% xlabel('Ellipse parameter \lambda')
% ylabel('Eccentricity \epsilon or rotary ratio \alpha')
% set(gcf,'paperposition', [2 2 3.5 3.5])
% xtick(.1),ytick(.1),fixlabels(-1)
% fontsize 14 14 14 14

% function[kappa,nu]=ab2kn(a,b)
% kappa=frac(1,sqrt(2))*sqrt(squared(a)+squared(b));
% nu=atan(frac(b,a));
%
% function[a,b]=kn2ab(kappa,nu)
% a=cos(nu).*kappa*sqrt(2);
% b=sin(nu).*kappa*sqrt(2);
%
% function[nu]=ab2nu(a,b)
% nu=atan(frac(b,a));


function [tx, ty] = rectToPolygon(rect)
%RECTTOPOLYGON Convert a rectangle into a polygon (set of vertices)
%
%   POLY = rectToPolygon(RECT);
%   Converts rectangle given as [X0 Y0 W H] or [X0 Y0 W H THETA] into a
%   4-by-2 array double, containing coordinate of rectangle vertices.
%   X0 and Y0 are the coordinates of the "lower left" vertex (before
%   applying rotation), W and H are the width and the height of the
%   rectangle, and THETA is the rotation angle around the first vertex, in
%   degrees.
%
%   See also:
%   orientedBoxToPolygon, ellipseToPolygon, drawRect, drawPolygon
%
%

% ---------
% Author: David Legland
% e-mail: david.legland@nantes.inra.fr
% INRA - TPV URPOI - BIA IMASTE
% created the 06/04/2005.
%

% HISTORY

% extract rectangle parameters
theta = 0;
x0  = rect(1);
y0  = rect(2);
w   = rect(3);
h   = rect(4);
if length(rect) > 4
    theta = rect(5);
end

% precompute angular quantities
cot = cosd(theta);
sit = sind(theta);

% compute vertex coordinates
tx = zeros(4, 1);
ty = zeros(4, 1);
tx(1) = x0;
ty(1) = y0;
tx(2) = x0 + w * cot;
ty(2) = y0 + w * sit;
tx(3) = x0 + w * cot - h * sit;
ty(3) = y0 + w * sit + h * cot;
tx(4) = x0 - h * sit;
ty(4) = y0 + h * cot;

% format output
if nargout <= 1
    tx = [tx ty];
end


function polygons3d(varargin)
%POLYGONS3D Description of functions operating on 3D polygons
%
%   A 3D polygon is simply a set of 3D points (called vertices) which are
%   assumed to be located in the same plane.
%   Several functions are provided for computing basic geometrical
%   parameters (centroid, angles), or intersections with lines or planes.
%
%   See also:
%   polygonArea3d, triangleArea3d, polygonCentroid3d, polygon3dNormalAngle
%   intersectLinePolygon3d, intersectLineTriangle3d, intersectRayPolygon3d
%   clipConvexPolygon3dHP
%   drawPolygon3d, drawPolyline3d, fillPolygon3d
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2008-10-13,    using Matlab 7.4.0.287 (R2007a)
% Copyright 2008 INRA - BIA PV Nantes - MIAJ Jouy-en-Josas.


function W = SimGraph_Full(M, sigma)
% SIMGRAPH_FULL Returns full similarity graph
%   Returns adjacency matrix for a full similarity graph where
%   a Gaussian similarity function with parameter sigma is
%   applied.
%
%   'M' - A d-by-n matrix containing n d-dimensional data points
%   'sigma' - Parameter for Gaussian similarity function
%
%   Author: Ingo Buerk
%   Year  : 2011/2012
%   Bachelor Thesis

% Compute distance matrix
W = squareform(pdist(M'));

% Apply Gaussian similarity function
W = simGaussian(W, sigma);

end


function gbasis=groebner(polyset,ord,varnames,tol)
% GROEBNER - calculate the reduced Groebner basis of a set of polynomials
%  usage: gbasis = groebner(polyset,ord)
%         gbasis = groebner(polyset,ord,varnames)
%         gbasis = groebner(polyset,ord,varnames,tol)
%
% INPUTS: polyset, ord, varnames, tol
%  polyset is a cell array of multivariate polynomial coefficients
%    the cell elements can be all strings or all arrays.
%    If the polynomials are specified with arrays, each row of the array
%    represents a single term.  The first element is the coefficient and
%    the others are the degrees of each unknown in the term.
%    e.g. [-1,2,1;1,0,1] represents -x1^2*x2+x2
%    If the polynomials are specified as strings, they must use variable
%    names 'x1','x2',... (unless varnames is provided) and be valid inputs
%    for petschel.str2poly.m
%  ord is a string specifying the monomial ordering:
%    'lex': lexicographical, order by highest power of most significant
%      indeterminate, e.g. x1>x2^2, x1*x2>x1.
%    'grlex': graded lex, order by total degree then lex,
%      e.g. x1^2*x2 > x1*x2^2 > x1^2
%    'grevlex': graded reverse lex, order by total degree then by lowest
%      power of least significant indeterminate, e.g. x1*x2^2 > x1*x2*x3
%    (for all cases have x1>x2>...>xn)
%    note: revlex is not a well-ordering because 1>x1>x1^2>...
%  varnames (optional) is a cell array of variable names if polyset is a
%    cell array of strings and the variable names are not 'x1', 'x2', etc.
%    If specified, there must always be at least 2 variables.
%  tol (optional) is the zero tolerance for coefficients, otherwise
%    catastrophic cancellation may occur.  Default value is 0
%
% OUTPUTS: gbasis
%  gbasis is the reduced Groebner basis of the set of polynomials, in the
%    same format (strings or matrices) as polyset{1}.
%
% ALGORITHM:
%  A modified Buchberger's algorithm is used.  In Buchberger's algorithm,
%  at each step calculate Sij = (Lij/ai)*Pi - (Lij/aj)*Pj, for all pairs of
%  polynomials Pi, Pj, where ai and aj are the leading terms of Pi and Pj,
%  and Lij is the least common multiple of ai and aj; then reduce Sij with
%  respect to the polynomials and add it to the set (note that Sij always
%  reduces to zero if ai and aj have no variables in common).  The
%  algorithm terminates when no new polynomials can be added to the set.
%  This function reduces the polynomials at each step in order to find the
%  reduced Groebner basis.
%
% EXAMPLE: simplify equations x^2+2xy^2=0, xy+2y^3=1
%  A1=[1,2,0;2,1,2]; % 1*x^2*y^0 + 2*x^1*y^2
%  A2=[-1,0,0;1,1,1;2,0,3]; % -1*x^0*y^0 + 1*x^1*y^1 + 2*x^0*y^3
%  y=groebner({A1,A2},'lex');
%  petschel.poly2str(y) % returns {'x2^3-0.5', 'x1'}
%
% EXAMPLE: same, but with equations specified as strings:
%  groebner({'x^2+2*x*y^2','x*y+2*y^3-1'},'lex',{'x','y'})
%  % returns {'y^3-0.5','x'}
%
% EXAMPLE: show that a set of equations is inconsistent
%  groebner({'x + y', 'x^2 - 1', 'y^2 - 2*x'}, 'lex', {'x', 'y'})
%  % returns {'1'}
%
%
% KNOWN ISSUES
%
%  0. GENERAL: while a significant effort has been made to ensure that the
%    program works as described, unidentified bugs may remain and the results
%    should be regarded with caution.  In particular, the suite of tests
%    performed was by no means comprehensive.
%
%  1. ACCURACY: the algorithm by default works in floating-point which
%    ultimately cannot perform exact arithmetic, so unexpected silent errors may
%    occur even when the coefficients are specified as integers.  A workaround
%    is to use other data types but this has its own issues (see below).
%
%  1a. EXAMPLE (roundoff - linearly independent polynomials)
%    eps % returns 2.2204e-16 (32-bit PC windows machine epsilon)
%    groebner({'x1+x2','x1+1.000000000000001*x2'},'lex') % ok, returns {'x2','x1'}
%    groebner({'x1+x2','x1+1.0000000000000001*x2'},'lex') % not ok, returns {'x2+x1'}
%
%  1b. EXAMPLE (roundoff - linearly dependent polynomials)
%    2/sqrt(2)-sqrt(2) % expect 0, returns -2.2204e-016
%    petschel.poly2str(groebner({[1,1,0;sqrt(2),0,1],[1/sqrt(2),1,0;1,0,1]},'lex')) % ok, returns {'1.41421*x2+x1'}
%    petschel.poly2str(groebner({[1,1,0;sqrt(2),0,1],[sqrt(2),1,0;2,0,1]},'lex')) % not ok, returns {'x2','x1'}
%    petschel.poly2str(groebner({[1,1,0;sqrt(2),0,1],[sqrt(2),1,0;2,0,1]},'lex',{},1e-14)) % ok, returns {'1.41421*x2+x1'}
%
%  1c. EXAMPLE (courtesy of Christophe Lauwerys - catastrophic cancellation & tolerance bug)
%    groebner({'t^3+x+y','t^2+0.5*x^2-x-z^2','t^2+y-z^2'},'lex',{'t','x','y','z'}) % ans{1} contains Inf
%
%  1d. EXAMPLE (from Mathematica documentation - catastrophic cancellation because of large intermediate coefficients)
%    % expect 3 polynomials returns, one of degree 8 in z; instead can get '1'
%    groebner({'x^2 + y^2 + z^2 - 1', 'x*y - z + 2', 'z^2 - 2*x + 3*y'}, 'lex', {'x', 'y','z'})
%
%  2. NON-DOUBLE INPUTS: use of non-double coefficients is not supported.  While
%    it may be tempting to introduce symbolic coefficients, it is not clear how
%    they should be consistently treated - for example 'A*x' could reduce to '0'
%    or 'x' or both, depending upon the assumptions on the coefficient A.
%
%  3. EFFICIENCY: The reduction algorithms aren't terribly efficient.  One of
%    the major bottlenecks at present is the calculation of the leading term,
%    which currently involves a call to sortrows each time.  It could be more
%    efficient to maintain an ordered list or even a priority queue (e.g.
%    implemented as a heap).  Also lattice reduction algorithms such as LLL
%    might speed things up.
%
%
% SEE ALSO:
%  petschel.poly2str, petschel.str2poly, petschel.polynsolve

% Author: Ben Petschel 19/6/2009
%
% Change history:
%  19/6/2009 - first release (ord='grlex' and ord='grevlex' not
%    implemented yet)
%  22/6/2009 - implemented ord='grlex' and ord='grevlex'
%    reduction algorithm now reduces lower-order terms as well
%  23/6/2009 - removed ord='revlex' because it is not a well-ordering
%  17/7/2009 - fixed bug in handling polynomials with >=3 variables
%  20/3/2010 - changed polynomial representation from multidimensional
%    arrays to 2d arrays (more memory efficient with large number of vars)
%  11/10/2010 - bugfix for handling error tolerance

if (numel(polyset)>0) && ischar(polyset{1})

    charout = true;

    if nargin<3

        polyset = petschel.str2poly(polyset);

    else

        polyset = petschel.str2poly(polyset,varnames);

    end

else

    charout = false;

end

if nargin<4

    tol = 0;

end

% determine the number of degrees
nd=max(cellfun(@(x)size(x,2)-1,polyset)); % error if = 0

if nd == 0

    error('number of variables must be >= 1');

end

gbasis = fullreduce(polyset,ord,tol,nd);

oldgbasis = {};

while ~isequal(oldgbasis,gbasis)

    oldgbasis = gbasis;

    Qset = SPoly(gbasis,ord,tol,nd);

    gbasis = fullreduce([gbasis,Qset],ord,tol,nd);

end

if charout

    if nargin<3

        gbasis = petschel.poly2str(gbasis);

    else

        gbasis = petschel.poly2str(gbasis,varnames);

    end

end

end % main function groebner(...)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Qset = SPoly(Pset,ord,tol,nd)
% calculates all reduced S-polynomials of Pset (Pset must be reduced)
%   Sij = (Lij/ai)*Pi - (Lij/aj)*Pj,
% for all pairs of polynomials Pi, Pj, where ai and aj are the leading
% terms of Pi and Pj, and Lij is the least common multiple of ai and aj
% then reduces Sij wrt Pset

Qset = {};

for i=1:numel(Pset)-1

    for j=i+1:numel(Pset)

        [c1,d1] = leadterm(Pset{i},ord,tol,nd); %#ok<*ASGLU>

        [c2,d2] = leadterm(Pset{j},ord,tol,nd);

        if any(and(d1>0,d2>0))
            % leading terms have a variable in common, so S-poly is nontrivial
            L = max(d1,d2); % LCM of leading terms

            S = addpolys(multiplyterm(Pset{i},L-d1),multconst(multiplyterm(Pset{j},L-d2),-1));

            S = reduceset(S,Pset,ord,tol,nd);

            %if any(S(:)~=0),
            if abs(leadterm(S,ord,tol,nd))>tol

                Qset{end+1}=S; % add S to the list

            end

        end

    end

end

end % helper function SPoly(...)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Qset = fullreduce(Pset,ord,tol,nd)
% reduces all polynomials wrt each other
Qset = Pset;

oldQset = {};

while ~isequal(oldQset,Qset)

    oldQset = Qset;

    for i=1:numel(Qset)-1

        for j=i+1:numel(Qset)

            Qset{i}=reduce(Qset{i},Qset{j},ord,tol,nd);

            Qset{j}=reduce(Qset{j},Qset{i},ord,tol,nd);

        end

    end

end

% keep only the nonzero results (to within zero tolerance tol)
Qset = Qset(cellfun(@(x)abs(leadterm(x,ord,tol,nd))>tol,Qset));

if numel(Qset)==1

    % special case, a single equation can slip through without being reduced
    c = leadterm(Qset{1},ord,tol,nd);

    % coefficients occupy first column of the array
    Qset{1} = multconst(Qset{1},1/c); % know c~=0 because have already removed zero eqns

end

end % helper function fullreduce(...)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Q = reduceset(P,Pset,ord,tol,nd)
% reduces P wrt all polynomials in Pset
Q = P;

oldQ = [];

while ~isequal(oldQ,Q)

    oldQ = Q;

    for i=1:numel(Pset)

        Q=reduce(Q,Pset{i},ord,tol,nd);

    end

end

end % helper function reduceset(...)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Q1=reduce(P1,P2,ord,tol,nd)
% reduces a polynomial P1 by subtracting multiples of P2 so that leading
% term coefficient is 1 and leading term of P2 does not divide that of P1

Q2=P2;

[c2,d2] = leadterm(Q2,ord,tol,nd);

if abs(c2)<=tol

    % ignore terms less than tol
    keepgoing = false;

    Q1 = P1;

else

    keepgoing = true;

    Q2 = multconst(Q2,1/c2);

    Q1 = 0; % will successively add terms to Q
    % remove the leading terms, in order to reduce wrt lower terms
    remain = P1;

end

while keepgoing

    [c1,d1] = leadterm(remain,ord,tol,nd);

    if abs(c1)<=tol

        % ignore terms less than tol
        keepgoing = false;

    else
        %reduce remain by Q2, if possible, or remove leading term
        if d1>=d2
            % can reduce Q1 by Q2, so subtract a multiple of Q2 from Q1
            remain = addpolys(remain,multconst(multiplyterm(Q2,d1-d2),-c1));

        else
            % cannot reduce any further wrt leading term, but try lower terms
            lead = multiplyterm(c1,d1);

            remain = addpolys(remain,multconst(lead,-1));

            Q1 = addpolys(Q1,lead); % add irreducible terms to Q1

        end

    end

end

% reduce leading coefficient, if possible
c1 = leadterm(Q1,ord,tol,nd);

if abs(c1)>tol

    Q1 = multconst(Q1,1/c1);

end

end % helper function reduce(...)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Q=multconst(P,c)
% returns c*P where c is a constant

Q = P;

Q(:,1)=Q(:,1)*c;

end % helper function multconst(...)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Q=addpolys(P1,P2)
% adds two polynomials

s1 = size(P1,2);

s2 = size(P2,2);

if s1>s2

    Q = [P1;P2,zeros(size(P2,1),s1-s2)];

else

    Q = [P1,zeros(size(P1,1),s2-s1);P2];

end

Q = sortrows(Q,2:size(Q,2));

i=1;

while i<size(Q,1)
    % merge rows representing terms with the same exponents
    if Q(i,1)==0

        Q(i,:)=[];

    elseif all(Q(i,2:end)==Q(i+1,2:end))

        Q(i,1)=Q(i,1)+Q(i+1,1);

        Q(i+1,:)=[];

        if Q(i,1)==0

            % remove terms that add to zero
            Q(i,:)=[];

        end

    else

        i=i+1;

    end

end

end % helper function addpolys

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Q=multiplyterm(P,d)
% multiplies a polynomial by a term (no coefficient)

% padding a matrix at the end is same as multiplying by x
d=d(:).';

sP = size(P,2);

sd = size(d,2)+1; % d doesn't include coefficient

if sP<sd

    Q=[P,zeros(size(P,1),sd-sP)];

else

    Q=P;

    d=[(d(:)).',zeros(1,sP-sd)];

end

Q=Q+repmat([0,d],size(Q,1),1);

end % helper function multiplyterm

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [coeff,deg]=leadterm(P,ord,tol,nd)
% returns the leading term of P
% deg is a row vector of length size(P,2)-1
% coeff is the leading coefficient, deg(i) is the degree of xi
% ignores terms with coefficients <= tol
% nd is the minimum number of degrees (in order to handle cases where deg=0)

d=size(P,2);

if all(abs(P(:,1))<=tol)
    % P=0
    coeff=0;
    deg=zeros(1,d-1);
else
    switch ord
        case 'lex'
            P=sortrows(P,2:d);

        case 'revlex'
            error('revlex is not a well-ordering');

        case 'grlex'
            P = [P,sum(P(:,2:d),2)];
            P = sortrows(P,[d+1,2:d]);
            P = P(:,1:d);

        case 'grevlex'
            P = [P,sum(P(:,2:d),2)];
            P = sortrows(P,[d+1,-(d:-1:2)]);
            P = P(:,1:d);

        otherwise
            error('ordering %s not recognized',ord);

    end % switch ord

    ind = find(abs(P(:,1))>tol,1,'last');

    if isempty(ind)

        coeff = 0;

        deg = zeros(1,d-1);

    else

        coeff = P(ind,1);

        deg = P(ind,2:end);

    end

end % if all(P(:)==0)

if nd>d-1

    deg = [deg,zeros(1,nd-d+1)];

end

end % helper function leadterm(...)


function J = redblue(m,whiteloc)
% Usage: J=redblue([m],[whiteloc])
% redblue: A colormap from red to white to blue. Optionally specify the
% colormap size in "m" and the normalized location of the white point in
% "whiteloc", with 0 being the minimum and 1 being the maximum.
%
%   Example:
%      load clown
%      imagesc(X);
%      colormap redblue

% Written 17 July 2009 by Douglas H. Kelley, dhk [at] dougandneely.com.

whitelocdefault=0.5;

if ~exist('m','var') || isempty(m)
   m = size(get(gcf,'colormap'),1);
end
if ~exist('whiteloc','var') || isempty(whiteloc)
    whiteloc=whitelocdefault;
end

if floor(whiteloc*m)==0
    J=[ ones(m,1) linspace(1,0,m)' linspace(1,0,m)' ];
elseif floor(whiteloc*m)==m
    J=[ linspace(0,1,m)' linspace(0,1,m)' ones(m,1)];
else
    J=[ [linspace(0,1,floor(whiteloc*m))'; ones(m-floor(whiteloc*m),1)]...
        [linspace(0,1,floor(whiteloc*m))'; linspace(1,0,m-floor(whiteloc*m))']...
        [ones(floor(whiteloc*m),1); linspace(1,0,m-floor(whiteloc*m))'] ];
end


function h = mrUtilScattercloud(x,y,n,l,clm,cmap)
%SCATTERCLOUD display density of scatter data
%   SCATTERCLOUD(X,Y) creates a scatterplot of X and Y, displayed over a
%   surface representing the smoothed density of the points.  The density is
%   determined with a 2D histogram, using 25 equally spaced bins in both
%   directions.
%   SCATTERCLOUD(X,Y,N) uses N equally spaced bins.
%   SCATTERCLOUD(X,Y,N,L) uses L as a parameter to the smoothing algorithm.
%    Defaults to 1.  Larger values of L lead to a smoother density, but a
%    worse fit to the original data.
%   SCATTERCLOUD(X,Y,N,L,CLM) uses CLM as the color/linestyle/marker for
%    the scatter plot.  Defaults to 'k+'.
%   SCATTERCLOUD(X,Y,N,L,CLM,CMAP) uses CMAP as the figure's colormap.  The
%    default is 'flipud(gray(256))'.
%   H = SCATTERCLOUD(...) returns the handles for the surface and line
%    objects created.
%
%   Example:
%
%     scattercloud(1:100 + randn(1,100), sin(1:100) + randn(1,100),...
%                  50,.5,'rx',jet(256))

error(nargchk(2,6,nargin),'struct');

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

if length(x) ~= length(y)
    error('SCATTERCLOUDDataVectorSizesDoNotMatch','The number of elements in x and y do not match')
end

if nargin < 6
    cmap = flipud(gray(256));
end

if nargin < 5
    clm = 'k+';
end

if nargin < 4
    l = 1;
end

if nargin < 3
    n = 25;
end

% min/max of x and y
minX = min(x);
maxX = max(x);
minY = min(y);
maxY = max(y);

% edge locations
xEdges = linspace(minX,maxX,n);
yEdges = linspace(minY,maxY,n);

% shift edges
xDiff = xEdges(2) - xEdges(1);
yDiff = yEdges(2) - yEdges(1);
xEdges = [-Inf, xEdges(2:end) - xDiff/2, Inf];
yEdges = [-Inf, yEdges(2:end) - yDiff/2, Inf];

% number of edges
numX = numel(xEdges);
numY = numel(yEdges);

% hold counts
C = zeros(numY,numX);

% do counts
for i = 1:numY-1
    for j = 1:numX-1
        C(i,j) = length(find(x >= xEdges(j) & x < xEdges(j+1) &...
                             y >= yEdges(i) & y < yEdges(i+1)));
    end
end

% get rid of Infs from the edges
xEdges = [xEdges(2) - xDiff,xEdges(2:end-1), xEdges(end-1) + xDiff];
yEdges = [yEdges(2) - yDiff,yEdges(2:end-1), yEdges(end-1) + yDiff];

% smooth the density data, in both directions.
C = localSmooth(localSmooth(C,l)',l)';

% create the graphics
ax = newplot;
s = surf(xEdges,yEdges,zeros(numY,numX),C,...
         'EdgeColor','none',...
         'FaceColor','interp');
view(ax,2);
colormap(ax,cmap);
grid(ax,'off');
holdstate = get(ax,'NextPlot');
set(ax,'NextPlot','add');
p = plot(x,y,clm);
axis(ax,'tight');
set(ax,'NextPlot',holdstate)

% outputs
if nargout
    h = [s;p];
end

function B = localSmooth(A,L)
r = size(A,1);
I = eye(r);
D1 = diff(I);
D2 = diff(I,2);
B = (I + L ^ 2 * D2' * D2 + 2 * L * D1' * D1) \ A;


function ndx = array2ind( siz, in_array, ~ )
%ARRAY2IND Linear index from multiple subscripts.
%   ARRAY2IND is used to determine the equivalent single index
%   corresponding to a given set of subscript values.
%
%   IND = ARRAY2IND(SIZ,[I,J]) returns the linear index equivalent to the
%   row and column subscripts in the arrays I and J for a matrix of
%   size SIZ.
%
%   IND = ARRAY2IND(SIZ,[I1,I2,...,IN]) returns the linear index
%   equivalent to the N subscripts in the arrays I1,I2,...,IN for an
%   array of size SIZ.
%
%   I1,I2,...,IN must have the same size, and IND will have the same size
%   as I1,I2,...,IN. For an array A, if IND = ARRAY2IND(SIZE(A),I1,...,IN)),
%   then A(IND(k))=A(I1(k),...,IN(k)) for all k.
siz = double(siz);
if length(siz)<2
    error('Invalid Input Size');
end

if length(siz)~=length(in_array)
    error('Invalid Input Size');
end

%Compute linear indices
k = [1 cumprod(siz(1:end-1))];
ndx = 1;
s = size(in_array(1)); %For size comparison

for i = 1:length(siz),
    v = in_array(i);
    %%Input checking
    if ~isequal(s,size(v))
        %Verify sizes of subscripts
        error('SubscriptVectorSize');
    end
    if (any(v(:) < 1)) || (any(v(:) > siz(i)))
        %Verify subscripts are within range
        error('IndexOutOfRange');
    end
    ndx = ndx + (v-1)*k(i);
end

end


function X_rec = recoverData(Z, U, K)
%RECOVERDATA Recovers an approximation of the original data when using the
%projected data
%   X_rec = RECOVERDATA(Z, U, K) recovers an approximation the
%   original data that has been reduced to K dimensions. It returns the
%   approximate reconstruction in X_rec.
%

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

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the approximation of the data by projecting back
%               onto the original space using the top K eigenvectors in U.
%
%               For the i-th example Z(i,:), the (approximate)
%               recovered data for dimension j is given as follows:
%                    v = Z(i, :)';
%                    recovered_j = v' * U(j, 1:K)';
%
%               Notice that U(j, 1:K) is a row vector.
%
U_reduce = U(:,1:K);
X_rec = Z*U_reduce';

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

end


function y = winconv(x,varargin)
%WINCONV   Discrere time convolution of a sequence with a window.
%   y = WINCONV(X) convolves the sequence X with a rectangular window. The
%   length of the window is same as that of X.
%
%   y = WINCONV(X,WINTYPE) convolves the sequence X with the window
%   specified by WINTYPE. WINTYPE can be either 'rect', or 'hamming', or
%   'hanning', or 'bartlett', or 'blackman'. The length of the window is
%   same as that of X.
%
%   y = WINCONV(X,WINTYPE,WINAMP) convolves the sequence X with the window
%   specified by WINTYPE. The amplitude of the window is set by WINAMP. So
%   WINAMP must be a real number/vector. The length of the window is same
%   as that of X. WINAMP could be a real constant or a vector with WINLEN
%   elements.
%
%   y = WINCONV(X,WINTYPE,WINAMP,WINLEN) convolves the sequence X with the
%   window specified by WINTYPE having amplitude WINAMP and length WINLEN.
%
%   See also CONV, FFT, RECTWIN, HAMMING, HANNING, BARTLETT, BLACKMAN.
%
%   Author: Nabin Sharma
%   Date: 2009/03/15

error(nargchk(1,4,nargin,'struct'));

len = length(varargin);
switch len
    case 0
        wintype = 'rectwin';
        A = 1;
        L = length(x);
    case 1
        if ischar(varargin{1})
            wintype = lower(varargin{1});
            A = 1;
            L = length(x);
        end
    case 2
        if ischar(varargin{1}) && isreal(varargin{2})
            wintype = lower(varargin{1});
            A = varargin{2};
            L = length(x);
        end
    case 3
        if ischar(varargin{1}) && isreal(varargin{2}) &&...
                isreal(varargin{3})
            wintype = lower(varargin{1});
            A = varargin{2};
            L = varargin{3};
        end
end

% generate the window
w1 = (window(str2func(wintype),L)).'; A = A(:).';
w = A.*w1;

% perform the convolution using FFT
NFFT = 2^(nextpow2(length(x)+L));
X = fft(x,NFFT); W = fft(w,NFFT);
Y = X.*W;
y = ifft(Y,NFFT);


function G = filterDog2d( r, var, order, show )
% Difference of Gaussian (Dog) Filter.
%
% Adapted from code by Serge Belongie.  Takes a "Difference of Gaussian" -
% all centered on the same point but with different values for sigma. Also
% serves as an approximation to an Laplacian of Gaussian (LoG) filter (if
% order==1).
%
% USAGE
%  G = filterDog2d( r, var, order, [show] )
%
% INPUTS
%  r       - Final filter will be 2*r+1 on each side
%  var     - variance of central Gaussian
%  order   - should be either 1-LoG or 2-difference of 3 Gaussians
%  show    - [0] figure to use for optional display
%
% OUTPUTS
%  G       - filter
%
% EXAMPLE
%  G = filterDog2d( 40, 40, 1, 1 ); %order=1 (LoG)
%  G = filterDog2d( 40, 40, 2, 3 ); %order=2
%
% See also FILTERDOOG, FILTERGAUSS
%
% Piotr's Image&Video Toolbox      Version 2.0
% Copyright 2012 Piotr Dollar.  [pdollar-at-caltech.edu]
% Please email me if you find bugs, or have suggestions or questions!
% Licensed under the Simplified BSD License [see external/bsd.txt]

if( nargin<4 || isempty(show) ); show=0; end

% create filter
N = 2*r+1;
if (order==1)
  Ga = filterGauss( [N N], [], .71*var );
  Gb = filterGauss( [N N], [], 1.14*var );
  a=1; b=-1; G = a*Ga + b*Gb;

elseif (order==2)
  Ga = filterGauss( [N N], [], 0.62*var );
  Gb = filterGauss( [N N], [], var );
  Gc = filterGauss( [N N], [], 1.6*var );
  a=-1; b=2; c=-1; G = a*Ga + b*Gb + c*Gc;

else
  error('order must be 1 or 2');
end

% normalize
G=G-mean(G(:));
G=G/norm(G(:),1);

% display
if(show); filterVisualize( G, show, 'row' ); end


function y = nigpdf(x, alpha, beta, mu, delta)
%NIGPDF Probability density function (pdf) for Normal-Inverse-Gaussian distribution.
%   Y = NIGPDF(X, ALPHA, BETA, MU, DELTA) returns the pdf of the
%   Normal-Inverse-Gaussian distribution with the parameter BETA which
%   determines the skewness, shape parameter ALPHA, location parameter MU
%   and scale parameter DELTA, evaluated at the values in X.
%
%   ALPHA, BETA, MU, DELTA must be scalar values.
%   ALPHA and DELTA must be positive values.
%   ALPHA > |BETA| must hold.
%
%   Default values for ALPHA = 1, BETA = 0; MU = 0; DELTA = 1.
%
%   See also NIGCDF, NIGINV, NIGRND, NIGSTATS.
%
%   References:
%   [1] Prause, K. (1999). The Generalized Hyperbolic Model

% -------------------------------------------------------------------------
%
% Allianz, Group Risk Controlling
% Risk Methodology
% Koeniginstr. 28
% D-80802 Muenchen
% Germany
% Internet:    www.allianz.de
% email:       ralf.werner@allianz.de
%
% Implementation Date:  2006 - 05 - 01
% Author:               Dr. Ralf Werner
%
% -------------------------------------------------------------------------

%% Default input values
if nargin < 2
    alpha = 1;
end
if nargin < 3
    beta = 0;
end
if nargin < 4
    mu = 0;
end
if nargin < 5
    delta = 1;
end

%% Constraints for the parameters
if alpha <= 0
    error('ALPHA must be positive.');
end
if delta <= 0
    error('DELTA must be positive.');
end
if abs(beta)>=alpha
    error('|BETA| must be smaller than ALPHA');
end

% transform input into column vector
[nx, mx] = size(x);
x = reshape(x, nx * mx, 1);

% calculate leading factor
q = (delta * alpha / pi) * exp(delta * sqrt(alpha^2 - beta^2));
xbar = x - mu;
z = sqrt(delta^2 + xbar .* xbar);

% modified Bessel function of the third kind
K = besselk(1, (alpha * z));

y = q ./ z .* K .* exp(beta * (x - mu));

% transform input vector back to input format
y = reshape(y, nx, mx);
y(isinf(x)) = 0;


function tauc = taucv(alfa,f,n)
%TAUCV  Upper percentage point of the tau distribution.
%       tauc=taucv(alfa,f,n) computes the critical value of tau distribution
%       for the Type I error--significance level (alfa), degree of freedom (f)
%       and the number of observations (n). It is used in Pope test for outliers.
%
%       References:
%       [1] Koch KR,1999, Parameter estimation and hypothesis testing in linear models,
%       Springer Verlag, Berlin
%       [2] Pope AJ,1976, The  statistics  of residuals and the detection of outliers.
%       NOAA Technical Report NOS65 NGS1, US Department of Commerce, National Geodetic
%       Survey,Rockville, Maryland
%       -----------------------------------------------------------------------------
%       Written by Cuneyt AYDIN, 2003, Yildiz Technical University, Geodesy Division
%       e-mail:caydin@yildiz.edu.tr
%       -----------------------------------------------------------------------------

if nargin < 3,
    error('requires at least three input arguments; alfa,f and n');
 end

if f==1
   error('degree of freedom must be larger than 1 (f>1)')

end

fdist=finv((1-alfa/n),1,(f-1));
tauc=sqrt((f*fdist)/(f-1+fdist));


function [a,r,f] = femq1_diff(xy,ev)
%femq1_diff  vectorized bilinear coefficient matrix generator
%   [A,Q,f] = femq1_diff(xy,ev);
%   input
%          xy         vertex coordinate vector
%          ev         element mapping matrix
%   output
%          A          stiffness matrix
%          Q          mass matrix
%          f          rhs vector
%
%   Natural boundary conditions apply. Dirichlet conditions
%   must be explicitly enforced by calling function nonzerobc.
%   IFISS function: DJS; 4 March 2005.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage
x=xy(:,1); y=xy(:,2);
nvtx=length(x);
nel=length(ev(:,1));
lx=max(x)-min(x); ly=max(y)-min(y);
hx=max(diff(x)); hy=max(diff(y));
fprintf('setting up Q1 diffusion matrices...  ')
%
% initialise global matrices
      a = sparse(nvtx,nvtx);
      r = sparse(nvtx,nvtx);
      f = zeros(nvtx,1);
%
% set up 2x2 Gauss points
      gpt=1.0e0/sqrt(3.0e0);
      s(1) = -gpt;  t(1) = -gpt;
      s(2) =  gpt;  t(2) = -gpt;
      s(3) =  gpt;  t(3) =  gpt;
      s(4) = -gpt;  t(4) =  gpt;
%
% inner loop over elements
        for ivtx = 1:4
        xl_v(:,ivtx) = x(ev(:,ivtx));
        yl_v(:,ivtx) = y(ev(:,ivtx));
	    end
        ae = zeros(nel,4,4);
        re = zeros(nel,4,4);
        fe = zeros(nel,4);
%  loop over 2x2 Gauss points
         for igpt = 1:4
         sigpt=s(igpt);
         tigpt=t(igpt);
%  evaluate derivatives etc
         [jac,invjac,phi,dphidx,dphidy] = deriv(sigpt,tigpt,xl_v,yl_v);
         rhs = gauss_source(sigpt,tigpt,xl_v,yl_v);
            for j = 1:4
               for i = 1:4
               ae(:,i,j) = ae(:,i,j)  + dphidx(:,i).*dphidx(:,j) .* invjac(:);
               ae(:,i,j) = ae(:,i,j)  + dphidy(:,i).*dphidy(:,j) .* invjac(:);
               re(:,i,j) = re(:,i,j)  + phi(:,i).*phi(:,j) .* jac(:);
               end
            fe(:,j) = fe(:,j)  + rhs(:) .* phi(:,j) .* jac(:);
	        end
% end of Gauss point loop
         end
% perform assembly of global matrix  and source vector
      for krow=1:4
	  nrow=ev(:,krow);
          for kcol=1:4
		  ncol=ev(:,kcol);
          a = a + sparse(nrow,ncol,ae(:,krow,kcol),nvtx,nvtx);
          r = r + sparse(nrow,ncol,re(:,krow,kcol),nvtx,nvtx);
          end
      f(nrow,1) = f(nrow,1) + fe(:,krow);
      end
%
fprintf('done\n')
return


function [u, v] = HS(im1, im2, alpha, ite, uInitial, vInitial, displayFlow, displayImg)
% Horn-Schunck optical flow method
% Horn, B.K.P., and Schunck, B.G., Determining Optical Flow, AI(17), No.
% 1-3, August 1981, pp. 185-203 http://dspace.mit.edu/handle/1721.1/6337
%
% Usage:
% [u, v] = HS(im1, im2, alpha, ite, uInitial, vInitial, displayFlow)
% For an example, run this file from the menu Debug->Run or press (F5)
%
% -im1,im2 : two subsequent frames or images.
% -alpha : a parameter that reflects the influence of the smoothness term.
% -ite : number of iterations.
% -uInitial, vInitial : initial values for the flow. If available, the
% flow would converge faster and hence would need less iterations ; default is zero.
% -displayFlow : 1 for display, 0 for no display ; default is 1.
% -displayImg : specify the image on which the flow would appear ( use an
% empty matrix "[]" for no image. )
%
% Author: Mohd Kharbat at Cranfield Defence and Security
% mkharbat(at)ieee(dot)org , http://mohd.kharbat.com
% Published under a Creative Commons Attribution-Non-Commercial-Share Alike
% 3.0 Unported Licence http://creativecommons.org/licenses/by-nc-sa/3.0/
%
% October 2008
% Rev: Jan 2009

%% Default parameters
if nargin<1 || nargin<2
    im1=imread('yos9.tif');
    im2=imread('yos10.tif');
end
if nargin<3
    alpha=1;
end
if nargin<4
    ite=100;
end
if nargin<5 || nargin<6
    uInitial = zeros(size(im1(:,:,1)));
    vInitial = zeros(size(im2(:,:,1)));
elseif size(uInitial,1) ==0 || size(vInitial,1)==0
    uInitial = zeros(size(im1(:,:,1)));
    vInitial = zeros(size(im2(:,:,1)));
end
if nargin<7
    displayFlow=1;
end
if nargin<8
    displayImg=im1;
end

%% Convert images to grayscale
if size(size(im1),2)==3
    im1=rgb2gray(im1);
end
if size(size(im2),2)==3
    im2=rgb2gray(im2);
end
im1=double(im1);
im2=double(im2);

im1=smoothImg(im1,1);
im2=smoothImg(im2,1);

tic;

%%
% Set initial value for the flow vectors
u = uInitial;
v = vInitial;

% Estimate spatiotemporal derivatives
[fx, fy, ft] = computeDerivatives(im1, im2);

% Averaging kernel
kernel_1=[1/12 1/6 1/12;1/6 0 1/6;1/12 1/6 1/12];

% Iterations
for i=1:ite
    % Compute local averages of the flow vectors
    uAvg=conv2(u,kernel_1,'same');
    vAvg=conv2(v,kernel_1,'same');
    % Compute flow vectors constrained by its local average and the optical flow constraints
    u= uAvg - ( fx .* ( ( fx .* uAvg ) + ( fy .* vAvg ) + ft ) ) ./ ( alpha^2 + fx.^2 + fy.^2);
    v= vAvg - ( fy .* ( ( fx .* uAvg ) + ( fy .* vAvg ) + ft ) ) ./ ( alpha^2 + fx.^2 + fy.^2);
end

u(isnan(u))=0;
v(isnan(v))=0;

%% Plotting
if displayFlow==1
    plotFlow(u, v, displayImg, 5, 5);
end


%% squircle
% Below is a demonstration of the features of the |squircle| function

%%
clear; close all; clc;

%% Syntax
% |[V]=squircle(r,f,n);|

%% Description
% The squircle is a shape intermediate between a circle and a square. This
% function outputs the coordinates V for a squircle using the input radius
% r, the weighting parameter f, and the number of points n.
%
% See also: https://en.wikipedia.org/wiki/Squircle
%
% This implementation is based on:
% https://arxiv.org/vc/arxiv/papers/1604/1604.02174v1.pdf

%% Examples
%

%% Example 1: Constructing a squircle
n=200; %Number of points on curve
r=2; %Squircle radius

%%

f=0.5;
[V]=squircle(r,f,n);

%%

t=linspace(0,2*pi,n)';
Vc=r*[cos(t) sin(t) zeros(size(t))]; %Circle coordinates
Vs=r*[-1 -1 0; 1 -1 0; 1 1 0; -1 1 0; -1 -1 0];

%%
% Visualization

cFigure; hold on
hp1=plotV(Vc,'r-' ,'LineWidth',2);
hp2=plotV(Vs,'b-' ,'LineWidth',2);
hp3=plotV(V ,'k.-','LineWidth',5);

axis equal; axis tight; grid on; box on;
set(gca,'FontSize',25);
axis(r*[-1.25 1.25 -1.25 1.25]);
legend([hp1 hp2 hp3],{'Circle','Square',['Squircle ','f=',num2str(f)]},'Location','NorthEastOutSide')
drawnow;

%% Example 2: Animate effect of varying f

n=104; %Number of points on curve
r=1; %Squircle radius

nSteps=25; %Number of animation steps
f=linspace(0,1,nSteps);

%%

hf=cFigure; hold on
ht=gtitle(['f=',sprintf('%.3f',f(1))],25);
c=spectral(nSteps);
for q=1:1:nSteps
    [V]=squircle(r,f(q),n);
    hp1=plotV(V,'k-','LineWidth',2);
    hp1.Color=c(q,:);
end

hp2=plotV(V,'k.-','LineWidth',4,'MarkerSize',25);
axis equal; axis tight; grid on; box on;
colormap(c); colorbar; caxis([0 1]);
set(gca,'FontSize',25);
drawnow;

%%
%Populate the animation structure

%Create the time vector
animStruct.Time=linspace(0,1,nSteps);

for q=1:1:nSteps
    [V]=squircle(r,f(q),n);

    %Set entries in animation structure
    animStruct.Handles{q}=[hp2 hp2 ht]; %Handles of objects to animate
    animStruct.Props{q}={'XData','YData','String'}; %Properties of objects to animate
    animStruct.Set{q}={V(:,1),V(:,2),['f=',sprintf('%.3f',f(q))]}; %Property values for to set in order to animate
end

anim8(hf,animStruct);

%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function [yi, ypi] = trigint(x, y, xi, c)

% hRIGINT 1-D piecewise trigonometric interpolation
%    TRIGINT(X,Y,XI,C) interpolates to find YI, the values of the
%    underlying function Y at the points in the array XI, using
%    piecewise trigonometric interpolation.  X and Y must be vectors
%    of length N.
%
%    C specifies the number of data points to use in the
%    interpolation.  The default is to use all points.
%
%    [YI,YPI] = TRIGINT() also returns the interpolated derivative
%    of the underlying function Y at points XI.

% Joe Henning - Fall 2012

% On the Interpolation Trigonometric Polynomial with an Arbitrary Even Number of Nodes
% Ernest Scheiber
% 2011 13th International Symposium on Symbolic and Numeric Algorithms for Scientific Computing
% 978-0-7695-4630-8/11 2011 IEEE
% DOI 10.1109/SYNASC.2011.13

if (nargin < 4)
   c = 0;
end

n = length(x);

if (n < c)
   fprintf('??? Bad c input to trigint ==> c <= length(x)\n');
   yi = [];
   ypi = [];
   return
end

for i = 1:length(xi)
   % Find the right place in the table by means of a bisection.
   klo = 1;
   khi = n;
   while (khi-klo > 1)
      k = fix((khi+klo)/2.0);
      if (x(k) > xi(i))
         khi = k;
      else
         klo = k;
      end
   end

   h = x(khi) - x(klo);
   if (h == 0.0)
      fprintf('??? Bad x input to trigint ==> x values must be distinct\n');
      yi(i) = NaN;
      ypi(i) = NaN;
      continue;
   end

   % Evaluate lagrange polynomial
   yi(i) = 0;
   ypi(i) = 0;
   if (c == 0)
      if (mod(n,2) == 0)   % even
         for k = 1:n
            sumx = 0;
            for m = 1:n
               sumx = sumx + x(m);
            end
            term = y(k)*(cos(0.5*(xi(i)-x(k))) + sin(0.5*(xi(i)-x(k)))*cot(0.5*sumx));
            termp = 0;
            termp2 = y(k)*0.5*(-sin(0.5*(xi(i)-x(k))) + cos(0.5*(xi(i)-x(k)))*cot(0.5*sumx));
            for m = 1:n
               if (k ~= m)
                  term = term*sin(0.5*(xi(i)-x(m)))/sin(0.5*(x(k)-x(m)));
                  prod = 0.5*cos(0.5*(xi(i)-x(m)));
                  for j = 1:n
                     if ((k ~= j) && (m ~= j))
                        prod = prod*sin(0.5*(xi(i)-x(j)))/sin(0.5*(x(k)-x(j)));
                     end
                  end
                  termp = termp + y(k)*(cos(0.5*(xi(i)-x(k))) + sin(0.5*(xi(i)-x(k)))*cot(0.5*sumx))*prod/sin(0.5*(x(k)-x(m)));
                  termp2 = termp2*sin(0.5*(xi(i)-x(m)))/sin(0.5*(x(k)-x(m)));
               end
            end
            yi(i) = yi(i) + term;
            ypi(i) = ypi(i) + termp + termp2;
         end
      else   % odd
         for k = 1:n
            term = y(k);
            termp = 0;
            for m = 1:n
               if (k ~= m)
                  term = term*sin(0.5*(xi(i)-x(m)))/sin(0.5*(x(k)-x(m)));
                  prod = 0.5*cos(0.5*(xi(i)-x(m)));
                  for j = 1:n
                     if ((k ~= j) && (m ~= j))
                        prod = prod*sin(0.5*(xi(i)-x(j)))/sin(0.5*(x(k)-x(j)));
                     end
                  end
                  termp = termp + y(k)*prod/sin(0.5*(x(k)-x(m)));
               end
            end
            yi(i) = yi(i) + term;
            ypi(i) = ypi(i) + termp;
         end
      end
   else
      if (mod(c,2) == 0)   % even
         c2 = c/2;
         if (klo < c2)
            klo = c2;
         end
         if (klo > n-c2)
            klo = n-c2;
         end
         khi = klo + 1;
         for k = klo-(c2-1):klo+c2
            sumx = 0;
            for m = klo-(c2-1):klo+c2
               sumx = sumx + x(m);
            end
            term = y(k)*(cos(0.5*(xi(i)-x(k))) + sin(0.5*(xi(i)-x(k)))*cot(0.5*sumx));
            termp = 0;
            termp2 = y(k)*0.5*(-sin(0.5*(xi(i)-x(k))) + cos(0.5*(xi(i)-x(k)))*cot(0.5*sumx));
            for m = klo-(c2-1):klo+c2
               if (k ~= m)
                  term = term*sin(0.5*(xi(i)-x(m)))/sin(0.5*(x(k)-x(m)));
                  prod = 0.5*cos(0.5*(xi(i)-x(m)));
                  for j = 1:n
                     if ((k ~= j) && (m ~= j))
                        prod = prod*sin(0.5*(xi(i)-x(j)))/sin(0.5*(x(k)-x(j)));
                     end
                  end
                  termp = termp + y(k)*(cos(0.5*(xi(i)-x(k))) + sin(0.5*(xi(i)-x(k)))*cot(0.5*sumx))*prod/sin(0.5*(x(k)-x(m)));
                  termp2 = termp2*sin(0.5*(xi(i)-x(m)))/sin(0.5*(x(k)-x(m)));
               end
            end
            yi(i) = yi(i) + term;
            ypi(i) = ypi(i) + termp + termp2;
         end
      else   % odd
         c2 = floor(c/2);
         if (klo < c2+1)
            klo = c2+1;
         end
         if (klo > n-c2)
            klo = n-c2;
         end
         khi = klo + 1;
         for k = klo-c2:klo+c2
            term = y(k);
            termp = 0;
            for m = klo-c2:klo+c2
               if (k ~= m)
                  term = term*sin(0.5*(xi(i)-x(m)))/sin(0.5*(x(k)-x(m)));
                  prod = 0.5*cos(0.5*(xi(i)-x(m)));
                  for j = 1:n
                     if ((k ~= j) && (m ~= j))
                        prod = prod*sin(0.5*(xi(i)-x(j)))/sin(0.5*(x(k)-x(j)));
                     end
                  end
                  termp = termp + y(k)*prod/sin(0.5*(x(k)-x(m)));
               end
            end
            yi(i) = yi(i) + term;
            ypi(i) = ypi(i) + termp;
         end
      end
   end
end


%
%  Sort the terms of a multivariate polynomial f according to
%  the lexicographical order, and combine the like terms
%
%    Syntax:  >> G = mvPolynSort(F)
%             >> G = mvPolynSort(F, tord)
%             >> [G,idg] = mvPolynSort(F)
%             >> [G,idg] = mvPolynSort(F, tord)
%
%    Input:   F -- (matrix) multivariate polynomial in coeff. matrix
%          tord -- (string, optional) 'lex' or 'grlex', term order type
%                   The default is 'lex' if not provided
%
%   Output:   G --- (matrix) sorted coeff. matrix of the input polynomial
%           idg --- (vector) the indices of G terms
%
%   Examples:
%
%   >> F
%
%   F =
%
%     0     0     4     3     3     0
%     0     0     1     0     0     1
%     0     0     1     0     0     2
%     8     7    -7     2     4    -5
%
%   >> [g,idg] = mvPolynSort(F)
%
%   G =
%
%     0     3     4     0
%     0     0     1     1
%     0     0     1     2
%    15     6    -7    -5
%
%   idg =
%
%     1     4    20    26
%
%   >> [G,idg] = mvPolynSort(F,'grlex')
%
%   G =
%
%     0     0     3     4
%     0     1     0     1
%     0     2     0     1
%    15    -5     6    -7
%
%
%   idg =
%
%     1    12    20    80
%


function D = prtDistanceEuclidean(dataSet1,dataSet2)
%prtDistanceEuclidean   Euclidean distance
%
%   DIST = prtDistanceCityBlock(DS1,DS2) calculates the Euclidean distance
%   from all the observations in datasets DS1 to DS2, and ouputs a distance
%   matrix of size DS1.nObservations x DS2.nObservations. DS1 and DS2
%   should have the same number of features. DS1 and DS2 should be
%   prtDataSet objects.
%
%   For more information, see:
%
%   http://en.wikipedia.org/wiki/Euclidean_distance
%
% Example:
%
%   % Create 2 data sets
%   dsx = prtDataSetStandard('Observations', [0 0; 1 1]);
%   dsy = prtDataSetStandard('Observations', [1 0;2 2; 3 3]);
%   % Compute distance
%   distance = prtDistanceEuclidean(dsx,dsy)
%
% See also: prtDistanceCityBlock, prtDistanceChebychev
% prtDistanceMahalanobis, prtDistanceSquare, prtDistanceLnorm

[data1,data2] = prtUtilDistanceParseInputs(dataSet1,dataSet2);
D = prtDistanceLNorm(data1,data2,2);


function [ mH ] = GenerateToeplitzConvMatrix( vH, numElementsData, convShape )
% ----------------------------------------------------------------------------------------------- %
%[ mH ] = GenerateToeplitzConvMatrix( vH, numElementsData, convShape )
% Generates matrix 'mH' such that mH * vX = conv(vX, vH, 'convShape').
% Input:
%   - vH                -   Input Vector.
%                           The coeeficients of the filter.
%                           Structure: Vector (n X 1).
%                           Type: 'Single' / 'Double'.
%                           Range: (-inf, inf).
%   - numElementsData   -   Number of Elements of the Data.
%                           Number of elements in the vector to convolve.
%                           In the equation above it is 'length(vX)'.
%                           Structure: Scalar.
%                           Type: 'Single' / 'Double'.
%                           Range: {1, 2, 3, ...}.
%   - convShape         -   Convolution Shape.
%                           Sets the convolution type. Using same
%                           definitions as in MATLAB 'conv()' function.
%                           Structure: Scalar.
%                           Type: 'Single' / 'Double'.
%                           Range: {1, 2, 3}.
% Output:
%   - mH                -   Toeplitz Convolution Matrix.
%                           Structure: Matrix.
%                           Type: 'Single' / 'Double'.
%                           Range: (-inf, inf).
% References
%   1.  A
% Remarks:
%   1.  B
% Known Issues:
%   1.  C
% TODO:
%   1.  D
% Release Notes:
%   -   1.0.001     17/01/2020  Royi Avital
%       *   Direct use of 'toeplitz()' to create the
%           'CONVOLUTION_SHAPE_SAME' case.
%   -   1.0.000     11/01/2020  Royi Avital
%       *   First realease version.
% ----------------------------------------------------------------------------------------------- %

CONVOLUTION_SHAPE_FULL         = 1;
CONVOLUTION_SHAPE_SAME         = 2;
CONVOLUTION_SHAPE_VALID        = 3;

numTaps = length(vH);

switch(convShape)
    case(CONVOLUTION_SHAPE_FULL)
        vR = [vH(1); zeros(numElementsData - 1, 1)];
        vC = [vH(:); zeros(numElementsData - 1, 1)];
    case(CONVOLUTION_SHAPE_SAME)
        sepIdx = ceil((numTaps + 1) / 2);
        vC = zeros(numElementsData, 1);
        vR = zeros(numElementsData, 1);
        vC(1:numTaps - sepIdx + 1) = vH(sepIdx:numTaps);
        vR(1:sepIdx) = vH(sepIdx:-1:1);
    case(CONVOLUTION_SHAPE_VALID)
        vR = [flip(vH(:), 1); zeros(numElementsData - numTaps, 1)];
        vC = [vH(end); zeros(numElementsData - numTaps, 1)];
end

mH = toeplitz(vC, vR);

end


function KG = kappa(I)
% get curvature information of input image
% input: 2D image I
% output: curvature matrix KG

% Copyright (c) 2009,
% Yue Wu @ ECE Department, Tufts University
% All Rights Reserved

I = double(I);
[m,n] = size(I);
P = padarray(I,[1,1],1,'pre');
P = padarray(P,[1,1],1,'post');

% central difference
fy = P(3:end,2:n+1)-P(1:m,2:n+1);
fx = P(2:m+1,3:end)-P(2:m+1,1:n);
fyy = P(3:end,2:n+1)+P(1:m,2:n+1)-2*I;
fxx = P(2:m+1,3:end)+P(2:m+1,1:n)-2*I;
fxy = 0.25.*(P(3:end,3:end)-P(1:m,3:end)+P(3:end,1:n)-P(1:m,1:n));
G = (fx.^2+fy.^2).^(0.5);
K = (fxx.*fy.^2-2*fxy.*fx.*fy+fyy.*fx.^2)./((fx.^2+fy.^2+eps).^(1.5));
KG = K.*G;
KG(1,:) = eps;
KG(end,:) = eps;
KG(:,1) = eps;
KG(:,end) = eps;
KG = KG./max(max(abs(KG)));


function par_est
% parameter estimation with derivatives              Holzbecher September 2005
% for exponential fit of exponent lambda for c(0)=c0
global tfit cfit c0

% specify fitting data
tfit =  [0.25 1 2 4 8];
cfit = [0.7716 0.5791 0.4002 0.1860 0.1019];
c0 = .8;

lambda = fzero(@myfun,0.11);
normc = norm(cfit - c0*exp(-lambda*tfit));
display (['Best fit for lambda = ' num2str(lambda)]);
display (['Norm of residuals =' num2str(normc)]);
tmax = tfit(size(tfit,2));
t = [0:0.01*tmax:tmax];
figure; plot (tfit,cfit,'or',t,c0*exp(-lambda*t),'-');
legend ('given','modelled');
text(0.5*tmax,c0*0.7,['\lambda: ' num2str(lambda)]);
text(0.5*tmax,c0*0.6,['norm of residuals: ' num2str(normc)]);
xlabel ('time'); ylabel ('concentration')

function f = myfun(lambda);
global tfit cfit c0

t = tfit;
c = c0*exp(-lambda*t);    % solve linear decay equation for c with c(0)=c0
clambda = -c.*t;          % equation for dc/dlambda
f = (cfit-c)*clambda';    % specify function f to vanish


function t = iseuclidean(D)
%ISEUCLIDEAN Is a distance matrix Euclidean?
%   T = ISEUCLIDEAN(D) returns a logical indicating whether or not the
%   dissimilarity matrix D is a Euclidean distance matrix, i.e., whether
%   there exist n points in p-dimensional space (for some p < n) such that
%   their Euclidean distances are given by D.  D may be specified as either
%   a full (square, symmetric) dissimilarity matrix, or as the lower
%   triangle (e.g., output by PDIST).
%
%   This algorithm is essentially classical multidimensional scaling.
%
%   See also CMDSCALE, PDIST, LINKAGE.
%
%   References:
%     [1] Seber, G.A.F., Multivariate Observations, Wiley, 1984

%   Copyright 1993-2002 The MathWorks, Inc.
%   $Revision: 1.4 $ $Date: 2002/02/04 19:25:44 $

[n m] = size(D);
del = 10*eps;

% lower triangle form for D
if n == 1
    % make sure it's a valid dissimilarity matrix
    n = (1+sqrt(1+8*m))/2;
    if n == fix(n) & all(D >= 0)
        D = squareform(D);
    else
        warning('Not a valid dissimilarity or distance matrix.')
        t = logical(0);
        return
    end

% full matrix form, make sure it's valid dissimilarity matrix
elseif n ~= m | any(any(D < 0 | abs(D - D') > del*max(max(D)))) | any(diag(D) > del)
    warning('Not a valid dissimilarity or distance matrix.')
    t = logical(0);
    return
end

P = eye(n) - repmat(1/n,n,n);
B = P * (-.5 * D .* D) * P;
g = eig((B+B')./2); % guard against spurious complex e-vals from roundoff
t = all(-eps^(3/4)*max(abs(g)) <= g); % all non-negative eigenvals (within roundoff)?


function c = phaseunlockreal(c,a,M,varargin)
%PHASEUNLOCKREAL  Undo phase lock of Gabor coefficients
%   Usage:  c=phaseunlockreal(c,a,M);
%
%   `phaseunlockreal(c,a,M)` removes phase locking from the Gabor coefficients *c*.
%   The coefficient must have been obtained from a |dgtreal| with parameter *a*
%   and using the 'timeinv' flag.
%
%   Phase locking the coefficients modifies them so as if they were obtained
%   from a frequency-invariant Gabor system. A filter bank produces phase locked
%   coefficients.
%
%   See also: dgt, phaselockreal
%
%   References: puc95

%   AUTHOR:    Peter Balazs, Peter L. Søndergaard, Zdenek Prusa
%   TESTING:   OK
%   REFERENCE: OK

if nargin<3
  error('%s: Too few input parameters.',upper(mfilename));
end;

if  ~isscalar(a) || ~isnumeric(a) || rem(a,1)~=0
  error('a must be integer');
end;

if  ~isscalar(M) || ~isnumeric(M) || rem(M,1)~=0
  error('M must be integer');
end;

definput.flags.accuracy={'normal', 'precise'};
flags=ltfatarghelper({},definput,varargin);

M2=size(c,1);
M2user = floor(M/2) + 1;

if M2~=M2user
    error('%s: Size of s does not comply with M.',upper(mfilename));
end

N=size(c,2);

if flags.do_normal
    TimeInd = (0:(N-1))*a;
    FreqInd = (0:(M2-1));

    phase = FreqInd'*TimeInd;
    phase = mod(phase,M);
    phase = exp(-2*1i*pi*phase/M);

    % Handle multisignals
    c=bsxfun(@times,c,phase);
elseif flags.do_precise

    frames = ifftreal(c,M);
    for n=0:N-1
        frames(:,n+1,:) = circshift(frames(:,n+1,:),n*a);
    end
    c = fftreal(frames);

end


function z=hyperg(a,b,c,x,n)
% HYPERGEOMETRIC2F1 Computes the hypergeometric function
% using a series expansion:
%
%    f(a,b;c;x)=
%
%    1 + [ab/1!c]x + [a(a+1)b(b+1)/2!c(c+1)]x^2 +
%    [a(a+1)(a+2)b(b+1)(b+2)/3!c(c+1)(c+2)]x^3 + ...
%
% The series is expanded to n terms
%
% This function solves the Gaussian Hypergeometric Differential Equation:
%
%     x(1-x)y'' + {c-(a+b+1)x}y' - aby = 0
%
% The Hypergeometric function converges only for:
% |x| < 1
% c != 0, -1, -2, -3, ...
%
%
% Comments to:
% Diego Garcia   - d.garcia@ieee.org
% Chuck Mongiovi - mongiovi@fast.net
% June 14, 2002

if nargin ~= 5
    error('Usage: hypergeometric2f1(a,b,c,x,n) --> Wrong number of arguments')
end

if (n <= 0 | n ~= floor(n))
    error('Usage: hypergeometric2f1(a,b,c,x,n) --> n has to be a positive integer')
end

% if (abs(x) > 1)
%    z=min(0.99,x);
%    return;
%    error('Usage: hypergeometric2f1(a,b,c,x,n) --> |x| has to be less than 1')
% end

if (c <= 0 & c == floor(c))
    error('Usage: hypergeometric2f1(a,b,c,x,n) --> c != 0, -1, -2, -3, ...')
end

z = 0;
m = 0;
while (m<n)
    if (m == 0)
        delta = 1;
    else
        delta = delta .* x .* (a + (m - 1)) .* (b + (m-1)) ./ m ./ (c + (m-1));
   end
   z = z + delta;
   m = m + 1;
end


function [all_theta] = oneVsAll(X, y, num_labels, lambda)
%ONEVSALL trains multiple logistic regression classifiers and returns all
%the classifiers in a matrix all_theta, where the i-th row of all_theta
%corresponds to the classifier for label i
%   [all_theta] = ONEVSALL(X, y, num_labels, lambda) trains num_labels
%   logisitc regression classifiers and returns each of these classifiers
%   in a matrix all_theta, where the i-th row of all_theta corresponds
%   to the classifier for label i

% Some useful variables
m = size(X, 1);
n = size(X, 2);

% You need to return the following variables correctly
all_theta = zeros(num_labels, n + 1);

% Add ones to the X data matrix
X = [ones(m, 1) X];

% ====================== YOUR CODE HERE ======================
% Instructions: You should complete the following code to train num_labels
%               logistic regression classifiers with regularization
%               parameter lambda.
%
% Hint: theta(:) will return a column vector.
%
% Hint: You can use y == c to obtain a vector of 1's and 0's that tell use
%       whether the ground truth is true/false for this class.
%
% Note: For this assignment, we recommend using fmincg to optimize the cost
%       function. It is okay to use a for-loop (for c = 1:num_labels) to
%       loop over the different classes.
%
%       fmincg works similarly to fminunc, but is more efficient when we
%       are dealing with large number of parameters.
%
% Example Code for fmincg:
%
%     % Set Initial theta
%     initial_theta = zeros(n + 1, 1);
%
%     % Set options for fminunc
%     options = optimset('GradObj', 'on', 'MaxIter', 50);
%
%     % Run fmincg to obtain the optimal theta
%     % This function will return theta and the cost
%     [theta] = ...
%         fmincg (@(t)(lrCostFunction(t, X, (y == c), lambda)), ...
%                 initial_theta, options);
%

for c = 1:num_labels

    initial_theta = zeros(n + 1, 1);

    options = optimset('GradObj', 'on', 'MaxIter', 50);

    [theta] = ...
         fmincg (@(t)(lrCostFunction(t, X, (y == c), lambda)), ...
                 initial_theta, options);

    all_theta(c,:) = theta';

end

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

end


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

% discrete time convolution of
% x[n]=[1,2],n=0,1 and h[n]=[2,1,1,1],n=0,1,2,3

%the signals
 kx=[0 1];
 x=[1 2];
 stem(kx,x);
 legend('x[k]')
 axis([-.1 3.1 -.1 2.1])

 figure
 kh=0:3;
 h=[2,1,1,1];
 stem(kh,h);
 axis([-.1 3.1 -.1 2.1])
 legend('h[k]')

 %reflection
 stem(-kh,h)
 axis([-3.1 .1 -.1 2.1])
 legend('h[-k]')

 %shifting
 %zero overlap
 figure
  stem(kx,x)
 axis([-5.1 3.1 -.1 2.1])
 legend('x[k]')
 figure
 n=-2;
 stem(-kh+n,h);
 axis([-5.1 3.1 -.1 2.1])
 legend('h[-2-k]')

  %overlap
 figure
 stem(kx,x)
 axis([-5.1 3.1 -.1 2.1])
 legend('x(k)')
 figure
 n=0;
 stem(-kh+n,h);
 axis([-5.1 3.1 -.1 2.1])
 legend('h(n-k)=h(0-k)')

 figure;
 n=1;
 stem(-kh+n,h);
 axis([-5.1 3.1 -.1 2.1])
 legend('h[n-k]=h[1-k]')

 figure;
 n=2;
 stem(-kh+n,h);
 axis([-5.1 3.1 -.1 2.1])
 legend('h[n-k]=h[2-k]')

 figure
 n=3;
 stem(-kh+n,h);
 axis([-2.1 6.1 -.1 2.1])
 legend('h[n-k]=h[3-k]')

 figure
 n=4;
 stem(-kh+n,h);
 axis([-2.1 6.1 -.1 2.1])
 legend('h[n-k]=h[4-k]')

%zero overlap
 n=5;
 stem(-kh+n,h);
 axis([-2.1 6.1 -.1 2.1])
 legend('h(n-k)=h(5-k)')

 %result
  n=0:4;
  y=[2,5,3,3,2];
  stem(n,y);
  axis([-.1 4.1 -.1 5.1])
  legend('y[n]')


function a = moler3 ( m, n )

%*****************************************************************************80
%
%% MOLER3 returns the MOLER3 matrix.
%
%  Formula:
%
%    if ( I == J )
%      A(I,J) = I
%    else
%      A(I,J) = min(I,J) - 2
%
%  Example:
%
%    N = 5
%
%     1 -1 -1 -1 -1
%    -1  2  0  0  0
%    -1  0  3  1  1
%    -1  0  1  4  2
%    -1  0  1  2  5
%
%  Properties:
%
%    A is integral, therefore det ( A ) is integral, and
%    det ( A ) * inverse ( A ) is integral.
%
%    A is positive definite.
%
%    A is symmetric: A' = A.
%
%    Because A is symmetric, it is normal.
%
%    Because A is normal, it is diagonalizable.
%
%    A has a simple Cholesky factorization.
%
%    A has one small eigenvalue.
%
%    The family of matrices is nested as a function of N.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 October 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer M, N, the number of rows and columns of A.
%
%    Output, real A(M,N), the matrix.
%
  for i = 1 : m
    for j = 1 : n
      if ( i == j )
        a(i,j) = i;
      else
        a(i,j) = min ( i, j ) - 2;
      end
    end
  end

  return
end


%infsup   computes inf-sup eigenvalue distribution
%   IFISS scriptfile: DJS; 7 March 2005.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage
fprintf('inf-sup eigenvalue estimation \n')
leig=default('eig/eigs? 0/1 (default is eig)',0);
stab=default('stable/stabilised? 0/1 (default is stable)',0);
[np,nu]=size(Bst);
S=Bst*(Ast\Bst');
if stab==1, S=S+beta*C; end
%
% compute discrete eigenvalues
S=0.5*(S+S');Q=0.5*(Q+Q');
if leig==1
   [V,D,flag] = eigs(S,Q,4,'sm');
   e=diag(D); e=sort(real(e));
   fprintf('inf-sup constant is %g \n',e(2))
else
   [V,D]=eig(full(S),full(Q));
e=diag(D); [e,k]=sort(real(e)); V=V(:,k); pp=length(e);
fprintf('inf-sup constant is %g \n',e(2))
fprintf('     upper bound is %g \n',e(pp))
end


function [y,c]=hp(z,lambda);
% PURPOSE: Hodrick-Prescott filtering
% ------------------------------------------------------------
% SYNTAX: [y,c]=hp(z,lambda);
% ------------------------------------------------------------
% OUTPUT: y: nx1 --> long-term trend
%         c: nx1 --> cycle as deviation from long-term trend (as %)
% ------------------------------------------------------------
% INPUT: z: nx1      --> short-term trend or s.a. time series
%        lambda: 1x1 --> balance between adjustment and smoothness
% ------------------------------------------------------------
% LIBRARY: dif
% ------------------------------------------------------------

% written by:
%  Enrique M. Quilis
%  Macroeconomic Research Department
%  Ministry of Economy and Competitiveness
%  <enrique.quilis@mineco.es>

% Version 2.0 [May 2009]

% Size of the input data
[n,m] = size(z);

% Second difference matrix
D = dif(2,n);
D(1:2,:) = [];

% Matrix form of the filter (non inverted)
H = eye(n) + lambda*(D'*D);

% Computing long-term trend
y = H \ z;

% Computing cycle as deviation from long term trend
c = 100 * (z - y) ./ y;


function dq = av2dq(AV)

% AV2DQ   transforms an angular vector into a rotation dual quaternion
%
%       DQ = AV2DQ(AV) returns the rotation dual quaternion DQ from its
%       angular vector representation AV [deg].
%       - AV is the angular vector representation of a rotation of angle
%          theta and unitary vecotr n. AV = theta*n = theta*[nx ny nz]. It
%          is expressed in [deg]. AV is a 3-vector or an 3*N array (where
%          column i is the angular vector representation of rotation i).
%       - DQ is a rotation dual quaternion. It is an 8*N array (each column
%         is a rotation dual quaternion).
%
% See also DQ2AV

sAV = size(AV);
if sAV == [1 3]
    AV = AV.';
    sAV = size(AV);
end

% wrong format
if sAV(1) ~= 3
    error('DualQuaternion:AV2dquat:wrongsize',...
        '%d rows in the AV array. It should be 3.',sAV(1));
end

n = sAV(2);
theta = sym(sqrt(sum(AV.^2))); %default is column sum
axis = sym([ones(1,n); zeros(2,n)]);
axis(:,n) = AV(:,n)./repmat(theta(n),3,1);

dq = rot2dq(theta,axis);


function output = perceptronTrain(input)
%perceptronTrain Training of two-class perceptron.
%   OUTPUT = perceptronTrain(INPUT) training of two-class perceptron. The
%   input and output parameters of are structures defined as follows.
%
%   Parameter input is a structure with the following fields:
%
%   input.X             A matrix of size n-by-np whose columns are
%                       n-dimensional input pattern vectors, and np is
%                       the number of such vectors. For example, for a
%                       set of 100, 3-element patterns, matrix inputs.X
%                       would be of size 3-by-100. The function augments
%                       the patterns by appending a 1 at the end of all
%                       pattern vectors.
%
%   input.r             Class membership vector of size 1-by-np whose
%                       kth value is 1 if the pattern vector in the kth
%                       column of X belongs to class c1; otherwise the
%                       kth value of input.r is -1.
%
%   input.Alpha         Learning rate positive scalar that defaults to
%                       0.5.
%
%   input.W0            Initial augmented weight vector of size
%                       (n + 1)-by-1. Its components default to uniform
%                       random numbers in the range [0,1].
%
%   input.NumEpochs     The number of training epochs. Defaults to 100.
%
%
%   Parameter output is a structure with the following fields.
%
%   output.W            (n + 1)-by-1 weight vector at completion of
%                       training. This may or not be a solution that
%                       separates the two classes, depending on the
%                       number of epochs specified and whether the
%                       classes are linearly separable.
%
%   output.Convergence  True (1) if training converged and false (0)
%                       otherwise.
%
%   output.ActualEpochs The actual number of epochs of training
%                       executed.
%
%   Copyright 2002-2020 Gatesmark
%
%   This function, and other functions in the DIPUM Toolbox, are based
%   on the theoretical and practical foundations established in the
%   book Digital Image Processing Using MATLAB, 3rd ed., Gatesmark
%   Press, 2020.
%
%   Book website: http://www.imageprocessingplace.com
%   License: https://github.com/dipum/dipum-toolbox/blob/master/LICENSE.txt

% AUGMENT THE PATTERN VECTORS.
% Number of patterns.
np = size(input.X,2);
% Augment the pattern vectors.
X = cat(1,input.X,ones(1,np));

% SET DEFAULTS.
if ~isfield(input,'Alpha')
   input.Alpha = 0.5;
end
if ~isfield(input,'NumEpochs')
   input.NumEpochs = 100;
end
if ~isfield(input,'W0')
   rng('shuffle');
   input.W0 = rand(size(X,1),1);
end

% INITIALIZATION.
% Make sure that input.W0 is a column vector.
input.W0 = input.W0(:);
% Initial values for loop.
w_last = input.W0;
w = input.W0;
output.ActualEpochs = 0;

% ITERATE.
for I = 1:input.NumEpochs
   output.ActualEpochs = output.ActualEpochs + 1;
   output.Convergence = true;
   for J = 1:np
      % An error has been committed for the Jth pattern if the sign of
      % w'*input.X(:,J) does not match the sign of input.r
      if sign(w'*X(:,J)) ~= input.r(J)
         w = w_last + input.r(J)*input.Alpha*X(:,J);
         output.Convergence = false;
         w_last = w;
      end
   end
   % Exit if convergence was not set to false for an entire epoch.
    if output.Convergence
      output.W = w_last;
      output.ActualEpochs = I;
      break
    end
end
output.ActualEpochs = I;
output.W = w_last;


function [ A, rhs ] = boundary ( nx, ny, x, y, A, rhs )

%*****************************************************************************80
%
%% BOUNDARY sets up the matrix and right hand side at boundary nodes.
%
%  Discussion:
%
%    For this simple problem, the boundary conditions specify that the solution
%    is 10 on the left size, 100 on the right side, and 0 on the top and bottom.
%
%    Nodes are assigned a single index K, which increases as:
%
%    (NY-1)*NX+1  (NY-1)*NX+2  ...  NY * NX
%           ....         ....  ...    .....
%           NX+1         NX+2  ...   2 * NX
%              1            2  ...       NX
%
%    The index K of a node on the lower boundary satisfies:
%      1 <= K <= NX
%    The index K of a node on the upper boundary satisfies:
%      (NY-1)*NX+1 <= K <= NY * NX
%    The index K of a node on the left boundary satisfies:
%      mod ( K, NX ) = 1
%    The index K of a node on the right boundary satisfies:
%      mod ( K, NX ) = 0
%
%    If we number rows from bottom I = 1 to top I = NY
%    and columns from left J = 1 to right J = NX, then the relationship
%    between the single index K and the row and column indices I and J is:
%      K = ( I - 1 ) * NX + J
%    and
%      J = 1 + mod ( K - 1, NX )
%      I = 1 + ( K - J ) / NX
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 July 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer NX, NY, the number of grid points in X and Y.
%
%    Input, real X(NX), Y(NY), the coordinates of grid lines.
%
%    Input, real sparse A(N,N), the system matrix, with the entries for the
%    interior nodes filled in.
%
%    Input, real RHS(N), the system right hand side, with the entries for the
%    interior nodes filled in.
%
%    Output, real sparse A(N,N), the system matrix, with the entries for all
%    nodes filled in.
%
%    Output, real RHS(N), the system right hand side, with the entries for
%    all nodes filled in.
%

%
%  Left boundary.
%
  j = 1;
  for i = 1 : ny
    kc = ( i - 1 ) * nx + j;
    xc = x(j);
    yc = y(i);
    A(kc,kc) = 1.0;
    rhs(kc,1) = 10.0;
  end
%
%  Right boundary.
%
  j = nx;
  for i = 1 : ny
    kc = ( i - 1 ) * nx + j;
    xc = x(j);
    yc = y(i);
    A(kc,kc) = 1.0;
    rhs(kc,1) = 100.0;
  end
%
%  Lower boundary.
%
  i = 1;
  for j = 1 : nx
    kc = ( i - 1 ) * nx + j;
    xc = x(j);
    yc = y(i);
    A(kc,kc) = 1.0;
    rhs(kc,1) = 0.0;
  end
%
%  Upper boundary.
%
  i = ny;
  for j = 1 : nx
    kc = ( i - 1 ) * nx + j;
    xc = x(j);
    yc = y(i);
    A(kc,kc) = 1.0;
    rhs(kc,1) = 0.0;
  end

  return
end


function s=phaseran(x,c)
%Syntax: s=phaseran(x,c)
%_______________________
%
% Makes c phase randomized surrogates of a time series x.
%
% s is the phase randomized time series.
% x is the original time series.
% c is the number of surrogates.
%
%
% References:
%
% Theiler J, Galdrikian B, Longtin A, Eubank S, Farmer D J (1992): Using
% Surrogate Data to Detect Nonlinearity in Time Series. In Nonlinear Modeling
% and Forecasting, eds. Casdagli M & Eubank S. 163-188. Addison-Wesley
%
% Theiler J, Eubank S,Galdrikian B, Longtin A,  Farmer D J (1992): Testing
% for nonlinearity in time series: the method of surrogate data. Physica D
% 58: 77-94
%
%
% Alexandros Leontitsis
% Department of Education
% University of Ioannina
% 45110 - Dourouti
% Ioannina
% Greece
%
% University e-mail: me00743@cc.uoi.gr
% Lifetime e-mail: leoaleq@yahoo.com
% Homepage: http://www.geocities.com/CapeCanaveral/Lab/1421
%
% 12 Apr 2002

if nargin<1 | isempty(x)==1
   error('You should provide a time series.');
else
   % x must be a vector
   if min(size(x))>1
      error('Invalid time series.');
   end
   x=x(:);
   % N is the time series length
   N=length(x);
end

if nargin<2 | isempty(c)==1
   c=1;
else
   % c must be scalar
   if sum(size(c))>2
      error('c must be scalar.');
   end
   % c must be greater or equal than 1
   if c<1
      error('c must be greater or equal than 1.');
   end
end

% FFT on x
y=fft(x);
% Magnitudes
m=abs(y);
% Angles
p=angle(y);
% The imaginary unit
i=sqrt(-1);
% Half of the data points
h=floor(N/2);

for j=1:c
   % Randomized phases
   if rem(N,2)==0
      p1=rand(h-1,1)*2*pi;
      p(2:N)=[p1' p(h+1) -flipud(p1)'];
      % Adjust the magnitudes
      m=[m(1:h+1);flipud(m(2:h))];
   else
      p1=rand(h,1)*2*pi;
      p(2:N)=[p1 -flipud(p1)];
   end
   % Back to the complex numbers
   s(:,j)=m.*exp(i*p);
   % Back to the time series (phase randomized surrogates)
   s(:,j)=real(ifft(s(:,j)));
end


function [xx, yy] = chebpts2(nx, ny, D, kind)
%CHEBPTS2   Chebyshev tensor product grid.
%   [XX YY] = CHEBPTS2(N) constructs an N by N grid of Chebyshev tensor points
%   on [-1,1]^2.
%
%   [XX YY] = CHEBPTS2(NX,NY) constructs an NX by NY grid of Chebyshev tensor
%   points on [-1,1]^2.
%
%   [XX YY] = CHEBPTS2(NX,NY,D) constructs an NX by NY grid of Chebyshev tensor
%   points on the rectangle [a,b] x [c,d], where D = [a b c d].
%
%   [XX YY] = CHEBPTS2(NX,NY,D,KIND) constructs a Chebyshev tensor grid of
%   the kind KIND. KIND = 2 is the default.
%
% See also CHEBPTS.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

if ( nargin > 2 )
   % Third argument should be a domain.
   D = D(:).';  % make a row vector.
   if ( ~all( size( D ) == [1 4] ) )
        error('CHEBFUN:CHEBFUN2:chebpts2:domain', 'Unrecognised domain.');
   end
else  % Default to the canoncial domain.
    D = [-1, 1, -1, 1];
end

if ( nargin == 1 )
    % Make it a square Chebyshev grid if only one input.
    ny = nx;
end
if ( nargin < 4 )
    % default to Chebyshev point of the 2nd kind.
    kind = 2;
end

% Get points:
x = chebpts(nx, D(1:2), kind);
y = chebpts(ny, D(3:4), kind);

% Tensor product.
[xx, yy] = meshgrid(x, y);

end


function avgNEES = ANEES(trans_err, rot_err, err_sigma)

    stateErr = [rot_err;trans_err];
    stateVar = err_sigma.^2;
    avgNEES = 0;
    stepNum = size(stateErr, 2);
    for i = 1:stepNum
        avgNEES = avgNEES + (1/stepNum)*stateErr(:,i)'*inv(diag(stateVar(:,i)))*stateErr(:,i);
    end
end


vectors_file_name = add_data_dir_base('GoogleNews_vectors_norm.mat');

if word2vec_sqrt
	vectors_file_name = fname_concat(vectors_file_name, '_sqrt');
end

is_sampled = true;
%is_sampled = false;

% without normalizing we had numeric problems in the LMM
normalize  = true;

if is_sampled
    vectors_file_name = fname_concat(vectors_file_name, '_sampled');
end

output(1, 'reading vectors file %s\n', vectors_file_name);
load(vectors_file_name);
output(1, 'done\n');

%TargetDim = 256;
TargetDim = 300;
%TargetDim = 100;

output(1, 'Use PCA to reduce to dimension %d\n', TargetDim);

[pc,~,latent] = princomp(vectors_');
sumlatent = cumsum(latent) ./ sum(latent);

pc = pc(:,1:TargetDim);
trans_matrix = pc';
vectors_ = trans_matrix * vectors_;

[dim, num_vectors] = size(vectors_)

if normalize
    % normalize
    output(1, 'normalizing...\n');
    for i = 1:num_vectors
      vectors_(:,i) = norma(vectors_(:,i));
    end
end

output(1, 'saving to file...\n');

post_fix = sprintf('_pca_%d', TargetDim);
pca_vectors_file_name = fname_concat(vectors_file_name, post_fix);
trans_matrix_file_name = add_data_dir_base(strcat('trans_matrix', post_fix));

save(pca_vectors_file_name, 'vectors_', '-v7.3');
output(1, 'saved to file: %s\n', pca_vectors_file_name);

save(trans_matrix_file_name, 'trans_matrix', '-v7.3');
output(1, 'saved to file: %s\n', trans_matrix_file_name);

clear vectors_;
clear trans_matrix;


function [newL2] = bestMap(L1,L2)
%bestmap: permute labels of L2 match L1 as good as possible
%   [newL2] = bestMap(L1,L2);

%===========
L1 = L1(:);
L2 = L2(:);
if size(L1) ~= size(L2)
    error('size(L1) must == size(L2)');
end

Label1 = unique(L1);
nClass1 = length(Label1);
Label2 = unique(L2);
nClass2 = length(Label2);

nClass = max(nClass1,nClass2);
G = zeros(nClass);
for i=1:nClass1
    for j=1:nClass2
        G(i,j) = length(find(L1 == Label1(i) & L2 == Label2(j)));
    end
end
[c,t] = hungarian(-G);
newL2 = zeros(size(L2));
for i=1:nClass2
    newL2(L2 == Label2(i)) = Label1(c(i));
end

return;

%=======backup old===========

L1 = L1 - min(L1) + 1;      %   min (L1) <- 1;
L2 = L2 - min(L2) + 1;      %   min (L2) <- 1;
%===========    make bipartition graph  ============
nClass = max(max(L1), max(L2));
G = zeros(nClass);
for i=1:nClass
    for j=1:nClass
        G(i,j) = length(find(L1 == i & L2 == j));
    end
end
%===========    assign with hungarian method    ======
[c,t] = hungarian(-G);
newL2 = zeros(nClass,1);
for i=1:nClass
    newL2(L2 == i) = c(i);
end


function h = matrix_decomp

%% Problem instance settings

m = 20;
n = 50;
use_cvx = 1; % set to 0 for larger instances

%% Problem data

s = RandStream.create('mt19937ar','seed',5489);
RandStream.setDefaultStream(s);

N = 3;
r = 4;

L = randn(m,r) * randn(r,n);    % low rank
S = sprandn(m,n,0.05);          % sparse
S(S ~= 0) = 20*binornd(1,0.5,nnz(S),1)-10;
V = 0.01*randn(m,n);            % noise

A = S + L + V;

g2_max = norm(A(:),inf);
g3_max = norm(A);
g2 = 0.15*g2_max;
g3 = 0.15*g3_max;

%% CVX

if use_cvx
    tic;

    cvx_begin
        cvx_precision low
        variables X_1(m,n) X_2(m,n) X_3(m,n)
        minimize(0.5*square_pos(norm(X_1,'fro')) + g2*norm(X_2(:),1) + g3*norm_nuc(X_3))
        subject to
            X_1 + X_2 + X_3 == A;
    cvx_end

    h.cvx_toc = toc;
    h.p_cvx = cvx_optval;
    h.X1_cvx = X_1;
    h.X2_cvx = X_2;
    h.X3_cvx = X_3;

    X_2(abs(X_2) < 1e-4) = 0;
    rhat = sum(svd(X_3) > 1e-4);
    fprintf('CVX (vs true):\n');
    fprintf('|V| = %.2f;  |X_1| = %.2f\n', norm(V, 'fro'), norm(X_1,'fro'));
    fprintf('nnz(S) = %d; nnz(X_2) = %d\n', nnz(S), nnz(X_2));
    fprintf('rank(L) = %d; rank(X_3) = %d\n', rank(L), rhat);
end

%% ADMM

MAX_ITER = 100;
ABSTOL   = 1e-4;
RELTOL   = 1e-2;

tic;

lambda = 1;
rho = 1/lambda;

X_1 = zeros(m,n);
X_2 = zeros(m,n);
X_3 = zeros(m,n);
z   = zeros(m,N*n);
U   = zeros(m,n);

fprintf('\n%3s\t%10s\t%10s\t%10s\t%10s\t%10s\n', 'iter', ...
    'r norm', 'eps pri', 's norm', 'eps dual', 'objective');

for k = 1:MAX_ITER

    B = avg(X_1, X_2, X_3) - A./N + U;

    % x-update
    X_1 = (1/(1+lambda))*(X_1 - B);
    X_2 = prox_l1(X_2 - B, lambda*g2);
    X_3 = prox_matrix(X_3 - B, lambda*g3, @prox_l1);

    % (for termination checks only)
    x = [X_1 X_2 X_3];
    zold = z;
    z = x + repmat(-avg(X_1, X_2, X_3) + A./N, 1, N);

    % u-update
    U = B;

    % diagnostics, reporting, termination checks
    h.objval(k)   = objective(X_1, g2, X_2, g3, X_3);
    h.r_norm(k)   = norm(x - z,'fro');
    h.s_norm(k)   = norm(-rho*(z - zold),'fro');
    h.eps_pri(k)  = sqrt(m*n*N)*ABSTOL + RELTOL*max(norm(x,'fro'), norm(-z,'fro'));
    h.eps_dual(k) = sqrt(m*n*N)*ABSTOL + RELTOL*sqrt(N)*norm(rho*U,'fro');

    if k == 1 || mod(k,10) == 0
        fprintf('%4d\t%10.4f\t%10.4f\t%10.4f\t%10.4f\t%10.2f\n', k, ...
            h.r_norm(k), h.eps_pri(k), h.s_norm(k), h.eps_dual(k), h.objval(k));
    end

    if h.r_norm(k) < h.eps_pri(k) && h.s_norm(k) < h.eps_dual(k)
         break;
    end

end

h.admm_toc = toc;
h.admm_iter = k;
h.X1_admm = X_1;
h.X2_admm = X_2;
h.X3_admm = X_3;

fprintf('\nADMM (vs true):\n');
fprintf('|V| = %.2f;  |X_1| = %.2f\n', norm(V, 'fro'), norm(X_1,'fro'));
fprintf('nnz(S) = %d; nnz(X_2) = %d\n', nnz(S), nnz(X_2));
fprintf('rank(L) = %d; rank(X_3) = %d\n', rank(L), rank(X_3));

if use_cvx
    fprintf('\nADMM vs CVX solutions (in Frobenius norm):\n');
    fprintf('X_1: %.2e; X_2: %.2e; X_3: %.2e\n', ...
        norm(h.X1_cvx - X_1,'fro'), norm(h.X2_cvx - X_2,'fro'), norm(h.X3_cvx - X_3,'fro'));
end

end

function x = avg(varargin)
    N = length(varargin);
    x = 0;
    for k = 1:N
        x = x + varargin{k};
    end
    x = x/N;
end

function p = objective(X_1, g_2, X_2, g_3, X_3)
    p = norm(X_1,'fro').^2 + g_2*norm(X_2(:),1) + g_3*norm(svd(X_3),1);
end


function [Z,W,P,T] = dosc(X,Y,nocomp,tol)
%  DOSC Direct Orthogonal Signal Correction
%
%  [Z,W,P,T] = dosc(X,Y,nocomp,tol);
%
%  Input
%     X       Matrix of predictor variables (usually spectra)  (I x J)
%     Y       Predicted variables (e.g. concentration)         (I x K)
%     nocomp  number of DOSC components to calculate
%     tol     tolerance used to calculate pseudinverse of X
%             a tolerance of 1E-3 worked well in two cases presented in paper [1]
%
%
%  Output
%     Z       DOSC corrected matrix X                          (I x J)
%     W       Weights used to determine DOSC components        (J x nocomp)
%     P       Loadings used to remove DOSC component from X    (J x nocomp)
%     T       DOSC components                                  (I x nocomp)
%
%
%  Once the calibration is done, new (scaled) x-data can be corrected by
%  newx = x - x*W*P'; Or use mfile dosc_pred
%
% See Reference
% Westerhuis JA, de Jong S and Smilde AK, Direct orthogonal signal correction,
% Chemometrics and Intelligent Laboratory Systems, 56, (2001), 13-25.

% Sijmen de Jong, Oct 99
% Adjusted by Johan Westerhuis
%   ==========================================================================
%   Copyright 2005 Biosystems Data Analysis Group ; Universiteit van Amsterdam
%   ==========================================================================

% project Y onto X      (step 1)
Yhat = X*(pinv(X')'*Y);

% deflate X wrt Yhat    (step 2)
AyX = X-Yhat*(pinv(Yhat)*X);

% find major PCs of AyX
[Ta,D] = eigs(AyX*AyX',nocomp);

% Calculate pseudoinverse of X using tolerance (step 5a)
pinvX = pinv(X',tol)';

% The tolerance can be changed to the number of PCR components (nc) used
% to estimate the pseudo inverse.
% [U,S,V] = svd(X,0);
% Xcorr = U(:,1:nc)*S(1:nc,1:nc)*V(:,1:nc)';
% pinvX = pinv(Xcorr);

W = pinvX*Ta;
T = X*W;

% Calculate loadings to remove DOSC component (step 7a)
P = X'*T*inv(T'*T);

% deflate X wrt to DOSC components (step 6a)
Z = X - T*P';


function [y,labels] = generateGMM(n,lambda,mu,gamma,verbose)
%
% function y = generateGMM(n,lambda,mu)
% This function generates n observations following a MoG distribution
% given by the class frequencies lambda, their mean mu and their variance gamma.

try, verbose = ~~verbose; catch, verbose = 1; end

p = size(mu,1);
k = 1;
sumLambdak = lambda(1);

if verbose && (p == 2 || p == 3)
    col = repmat('bgrcmyk',1,ceil(1+length(gamma)./7));
    pl = figure;
    hold on
end

labels = zeros(n,length(gamma));

for i = 1:n

    ratio = i./n;

    if ratio>=sumLambdak && ~isequal(i,n)
        k = k+1;
        sumLambdak = sumLambdak+lambda(k);
    end

    labels(i,k) = 1;
    y(:,i) = mu(:,k) + sqrt(gamma(k)).*randn(p,1);

    if verbose && p == 2
        figure(pl),plot(y(1,i),y(2,i),[col(k),'.']);
    elseif verbose && p == 3
        figure(pl),plot3(y(1,i),y(2,i),y(3,i),[col(k),'.']);
    end
%     drawnow;
end

if verbose &&(p==2 || p==3)
    axis square
end


function [score,in,out]=clusterquality(f,S,partition)
%function [score,in,out]=clusterquality(f,S,partition)
%
%PURPOSE
%
%To compute a simple quality (compactness) index for the given
%clusters. The more dense and isolated a cluster is the bigger
%value the index gets; however, if there is only one item in a
%cluster the index is not computed (a NaN is returned for that
%cluster)
%
%INPUT
%
% f          (string)     cluster score function: 'mean' or 'minmax'
% S          (NxN matrix) similarity matrix
% partition  (Nx1 vector) partition vector (see explanation for
%              'partition vector' in function hcluster)
%
%OUTPUT
%
%score       (Kx1 vector) score(k) contains the index value for
%             cluster k: score(k)=in(k)-out(k)
%in          (Kx1 vector)  see above
%out         (Kx1 vector)  see above
%
%DETAILS
%
%For f='mean' the average extra-cluster similarity is subtracted
%from the mean intra-cluster similarity.
%
%   Iq=avg(intra-cluster similarity) - avg(extra-cluster similarity)
%
%The index is described in publication Himberg et al. (2004),
%"Validating the independent components of neuroimaging time-series
%via clustering and visualization". NeuroImage, 22:3(1214-1222). It
%is used by default in Icasso functions.
%
%(The intra-cluster similarities for cluster C mean the mutual
%similarities between the estimates in C, and the extra-cluster
%similarities for C are the similarities between the estimates in C
%and the estimates not in C.)
%
%Note: if there is only one item in a cluster, index
%value NaN is returned for that cluster.
%
%You can also specify a more conservative but less robust criteria
%('minmax') where the maximum extra-cluster similarity is
%subtracted from the minimum intra-cluster similarity: if
%f='minmax' the maximum extra-cluster similarity is subtracted from
%the minimum intra-cluster similarity.
%
%SEE ALSO
% clusterstat
% icassoStability

%COPYRIGHT NOTICE
%This function is a part of Icasso software library
%Copyright (C) 2003-2005 Johan Himberg
%
%This program is free software; you can redistribute it and/or
%modify it under the terms of the GNU General Public License
%as published by the Free Software Foundation; either version 2
%of the License, or any later version.
%
%This program is distributed in the hope that it will be useful,
%but WITHOUT ANY WARRANTY; without even the implied warranty of
%MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%GNU General Public License for more details.
%
%You should have received a copy of the GNU General Public License
%along with this program; if not, write to the Free Software
%Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

% ver 1.2 100105

Ncluster=max(partition);
s=clusterstat(S,partition);

% Compute score
switch lower(f)
 case 'mean'
  in=s.internal.avg;
  out=s.external.avg;
 case 'minmax'
  in=s.internal.min;
  out=s.external.max;
 otherwise
  error('Unrecognized score function.');
end

score=in-out;


classdef Kernel < handle
    %{
        Kernel function

            INPUT
        X         data (n*d)
        Y         data (m*d)

        OUTPUT
        K         kernel matrix (n*m)

    ----------------------------------------------------------------------

        type   -

        linear      :  k(x,y) = x'*y
        polynomial  :  k(x,y) = (γ*x'*y+c)^d
        gaussian    :  k(x,y) = exp(-γ*||x-y||^2)
        sigmoid     :  k(x,y) = tanh(γ*x'*y+c)
        laplacian   :  k(x,y) = exp(-γ*||x-y||)

        degree -  d
        offset -  c
        gamma  -  γ

    ----------------------------------------------------------------------

        Version 1.1, 11-MAY-2021
        Email: iqiukp@outlook.com
    ----------------------------------------------------------------------
    %}

    properties
        type = 'gaussian'
        offset = 0
        gamma = 0.1
        degree = 2
    end

    methods
        function obj = Kernel(varargin)
            inputValue = varargin;
            nParameter = size(inputValue, 2)/2;
            supportedKernelFunc = {'linear', 'gaussian', 'polynomial', 'sigmoid', 'laplacian'};
            for n = 1:nParameter
                parameter = inputValue{(n-1)*2+1};
                value = inputValue{(n-1)*2+2};
                if strcmp(parameter, 'type')
                    if ~any(strcmp(value, supportedKernelFunc))
                    errorText = sprintf([
                        'Unsupported kernel function.\n',...
                        'Use one of these kernel functions:\n', ...
                        'linear, gaussian, polynomial, sigmoid, laplacian.']);
                    error(errorText)
                    end
                end
                obj.(parameter) = value;
            end
        end

        function K = computeMatrix(obj, x, y)
            K = zeros(size(x, 1), size(y, 1));
            % compute the kernel matrix
            switch obj.type
                case 'linear' % linear kernel function
                    K = x*y';

                case 'gaussian' % gaussian kernel function
                    try
                        K = exp(-obj.gamma*pdist2(x, y, 'squaredeuclidean'));
                    catch
                        sx = sum(x.^2, 2);
                        sy = sum(y.^2, 2);
                        xy = 2*x*y';
                        K = exp((bsxfun(@minus, bsxfun(@minus, xy, sx), sy'))*obj.gamma);
                    end

                case 'polynomial' % polynomial kernel function
                    K = (obj.gamma*x*y'+obj.offset).^double(obj.degree);

                case 'sigmoid' % sigmoid kernel function
                    K = tanh(obj.gamma*x*y'+obj.offset);

                case 'laplacian' % laplacian kernel function
                    K = exp(-obj.gamma*pdist2(x, y, 'cityblock'));
            end
        end
    end
end


function test_eigen_test01 ( )

%*****************************************************************************80
%
%% TEST_EIGEN_TEST01 tests R8SYMM_TEST.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    20 February 2012
%
%  Author:
%
%    John Burkardt
%
  n = 100;
  bin_num = 10;
  lambda_dev = 1.0;
  lambda_mean = 1.0;
  seed = 123456789;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST_EIGEN_TEST01\n' );
  fprintf ( 1, '  R8SYMM_TEST makes an arbitrary size symmetric matrix\n' );
  fprintf ( 1, '  with known eigenvalues and eigenvectors.\n' );

  [ a, q, lambda, seed ] = r8symm_test ( n, lambda_mean, lambda_dev, seed );
%
%  Get the eigenvalue range.
%
  lambda_min = min ( lambda(1:n) );
  lambda_max = max ( lambda(1:n) );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  LAMBDA_MIN = %g\n', lambda_min );
  fprintf ( 1, '  LAMBDA_MAX = %g\n', lambda_max );
%
%  Bin the eigenvalues.
%
  [ bin, bin_limit ] = r8vec_bin ( n, lambda, bin_num, lambda_min, lambda_max );

  r8bin_print ( bin_num, bin, bin_limit, '  Lambda bins:' );

  if ( 0 )
    r8mat_print ( n, n, a, '  The matrix A:' );
  end

  if ( 0 )
    r8mat_print ( n, n, q, '  The eigenvector matrix Q:' );
  end

  aq = a * q;

  for j = 1 : n
    lambda2(j) = norm ( aq(1:n,j) );
  end

  r8vec2_print ( n, lambda, lambda2, '  LAMBDA versus column norms of A*Q:' );

  return
end