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 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 [ 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 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 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


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 [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 geometry_test174 ( )

%*****************************************************************************80
%
%% TEST174 tests RADEC_TO_XYZ, XYZ_TO_RADEC.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 December 2010
%
%  Author:
%
%    John Burkardt
%
  ntest = 6;

  ptest = [ ...
     1.0,  0.0,  0.0; ...
     0.0,  1.0,  0.0; ...
     0.0,  0.0,  1.0; ...
     1.0,  1.0,  1.0; ...
     5.0, -2.0, -1.0; ...
    -2.0, -2.0, -2.0 ]';

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST174\n' );
  fprintf ( 1, '  RADEC_TO_XYZ converts XYZ to RADEC coordinates.\n' );
  fprintf ( 1, '  XYZ_TO_RADEC converts RADEC to XYZ coordinates.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '          P1          RA     DEC           P2\n' );
  fprintf ( 1, '\n' );

  for i = 1 : ntest

    p1(1:3,1) = ptest(1:3,i);

    [ ra, dec ] = xyz_to_radec ( p1 );
    p2 = radec_to_xyz ( ra, dec );

    fprintf ( 1, '  %10f  %10f  %10f  %10f  %10f  %10f  %10f  %10f\n', ...
      p1(1:3,1), ra, dec, p2(1:3,1) );

  end

  return
end


function [p,w] = nrbeval(nurbs,tt)
%
% Function Name:
%
%   nrbeval - Evaluate a NURBS at parameteric points
%
% Calling Sequence:
%
%   [p,w] = nrbeval(crv,ut)
%   [p,w] = nrbeval(srf,{ut,vt})
%
% Parameters:
%
%   crv		: NURBS curve, see nrbmak.
%
%   srf		: NURBS surface, see nrbmak.
%
%   ut		: Parametric evaluation points along U direction.
%
%   vt		: Parametric evaluation points along V direction.
%
%   p		: Evaluated points on the NURBS curve or surface as cartesian
% 		coordinates (x,y,z). If w is included on the lhs argument list
% 		the points are returned as homogeneous coordinates (wx,wy,wz).
%
%   w		: Weights of the homogeneous coordinates of the evaluated
% 		points. Note inclusion of this argument changes the type
% 		of coordinates returned in p (see above).
%
% Description:
%
%   Evaluation of NURBS curves or surfaces at parametric points along the
%   U and V directions. Either homogeneous coordinates are returned if the
%   weights are requested in the lhs arguments, or as cartesian coordinates.
%   This function utilises the 'C' interface bspeval.
%
% Examples:
%
%   Evaluate the NURBS circle at twenty points from 0.0 to 1.0
%
%   nrb = nrbcirc;
%   ut = linspace(0.0,1.0,20);
%   p = nrbeval(nrb,ut);
%
% See:
%
%     bspeval
%

%  D.M. Spink
%  Copyright (c) 2000.

if nargin < 2
  error('Not enough input arguments');
end

foption = 1;    % output format 3D cartesian coordinates
if nargout == 2
  foption = 0;  % output format 4D homogenous coordinates
end

if ~isstruct(nurbs)
  error('NURBS representation is not structure!');
end

if ~strcmp(nurbs.form,'B-NURBS')
  error('Not a recognised NURBS representation');
end

if iscell(nurbs.knots)
  % NURBS structure represents a surface

  num1 = nurbs.number(1);
  num2 = nurbs.number(2);
  degree = nurbs.order-1;

  if iscell(tt)
    % Evaluate over a [u,v] grid
    % tt{1} represents the u direction
    % tt{2} represents the v direction

    nt1 = length(tt{1});
    nt2 = length(tt{2});

    % Evaluate along the v direction
    val = reshape(nurbs.coefs,4*num1,num2);
    val = bspeval(degree(2),val,nurbs.knots{2},tt{2});
    val = reshape(val,[4 num1 nt2]);

    % Evaluate along the u direction
    val = permute(val,[1 3 2]);
    val = reshape(val,4*nt2,num1);
    val = bspeval(degree(1),val,nurbs.knots{1},tt{1});
    val = reshape(val,[4 nt2 nt1]);
    val = permute(val,[1 3 2]);

    w = val(4,:,:);
    p = val(1:3,:,:);
    if foption
      p = p./repmat(w,[3 1 1]);
    end

  else

    % Evaluate at scattered points
    % tt(1,:) represents the u direction
    % tt(2,:) represents the v direction

    nt = size(tt,2);

    val = reshape(nurbs.coefs,4*num1,num2);
    val = bspeval(degree(2),val,nurbs.knots{2},tt(2,:));
    val = reshape(val,[4 num1 nt]);

    % evaluate along the u direction
    pnts = zeros(4,nt);
    for v = 1:nt
      coefs = squeeze(val(:,:,v));
      pnts(:,v) = bspeval(degree(1),coefs,nurbs.knots{1},tt(1,v));
    end

    w = pnts(4,:);
    p = pnts(1:3,:);
    if foption
       p = p./w;
    end

  end

else

  % NURBS structure represents a curve
  %  tt represent a vector of parametric points in the u direction

  val = bspeval(nurbs.order-1,nurbs.coefs,nurbs.knots,tt);

  w = val(4,:);
  p = val(1:3,:);
  if foption
    p = p./repmat(w,3,1);
  end

end


function [maskOut]=kGaussian_color_EM(imageFile,k)
%% this function uses EM algorithm and gaussian distribution function to do
% image segmentation on the color space
% try:
%   img=imread('onion.png');
%   [maskOut]=kGaussian_color_EM(img,9); figure;  imshow(maskOut)
% written by Rongwen Lu on 12/11/2011; email: rongwen@uab.edu
img=double(imageFile);

[M,N,P]=size(img);
n=M*N;
imgR=img(:,:,1);
imgG=img(:,:,2);
imgB=img(:,:,3);
[cy,cx]=ind2sub([M,N],1:n);

%normalize each vector; delete it if normalization is not needed; weights
%are also assigned here;
% imgR=mat2gray(imgR);
% imgG=mat2gray(imgG);
% imgB=mat2gray(imgB);
% cy=mat2gray(cy);
% cx=mat2gray(cx);
imgR=imgR/255;
imgG=imgG/255;
imgB=imgB/255;
cy=cy/M;
cx=cx/N;

% %% Gaussian filter
% w=fspecial('gaussian',[5,5],4);
% imgR=imfilter(imgR,w);
% imgG=imfilter(imgG,w);
% imgB=imfilter(imgB,w);

%% assign vectors into the matrix raw
raw=zeros(n,3);
raw(:,1)=imgR(:);
raw(:,2)=imgG(:);
raw(:,3)=imgB(:);

% raw=zeros(n,5);
% raw(:,1)=cy.';
% raw(:,2)=cx.';
% raw(:,3)=imgR(:);
% raw(:,4)=imgG(:);
% raw(:,5)=imgB(:);

%% get assignment matrix p, which is also memebership probability here; u
%% is vector of the estimated means of Gaussian function, v is the vector ot the estimated SD
[p,u,v]=em(raw,k);

imgRe=zeros(n,3);
kColor=jet(k);
kColor=u(:,1:3);
imgRe=p*kColor;

maskOut=zeros(M,N,3);
for ii=1:3
    maskOut(:,:,ii)=reshape(imgRe(:,ii),[M,N]);
end

% figure; imshow((maskOut))
% title('based on k Gaussian by EM algorithm on color space')

 function [p,u,v]=em(raw,k)
 % this function uses Expectation Maximization method to estimate k
 % Gaussian distribution functions. There are 2 input arguments. Raw's size
 % is [n,dim], where n is the NO of data and dim is the dimention of data.
 % k means using k Gaussin functions to do image segmentation.The output is
 % p, which is assignment matrix.its [ii,jj]th element means the
 % probability that Xii is generated by jjth Gaussian function.

%% the input of following codes are raw,and K

%% initialize centroid matrix u; u has k raws. NO of column is the same as
%% raw
[n,dim]=size(raw);
u=raw(randint(k,1,[1,n]),:);
%u=[0,0;40,40;-40,-40];

%% initialize standard diviation v, v has k raws, one column.
v=zeros(k,1);
for ii=1:k
    raw_tmp=raw(ii:k:end,1);
    v(ii,:)=std(raw_tmp);
end
%v=.5*[4,4,4]';
%% initialize weight w
w=ones(k,1)/k;

%% initialize membership probability matrix (assignment matrix) p, which is p(k|x)
p=zeros(n,k);

%% do interation to get best r
u0=u*0;
v0=0*v;
w0=w*0;
energy=sum(sum((u-u0).^2))+sum(sum((v-v0).^2))+(sum((w-w0).^2));
iteration=1;
x_u=zeros(size(raw));
while energy>10^(-6)

    %% calculate membership probability, which is also assignment matrix
    for jj=1:k
        for ss=1:dim
            x_u(:,ss)=raw(:,ss)-u(jj,ss)*ones(n,1);
        end
        x_u=x_u.*x_u;
        p(:,jj)=power(sqrt(2*pi)*v(jj),-1*dim)*exp((-1/2)*sum(x_u,2)./(v(jj).^2));
        p(:,jj)=p(:,jj)*w(jj);

    end
    %% normalize p on the x dimention
    pSum=sum(p,2);
    for jj=1:k
        p(:,jj)=p(:,jj)./pSum;
    end

    %% normlaize p on the y dimention, yielding pNorm
    pSum2=sum(p,1);
    pNorm=p*0;
    for jj=1:k
        pNorm(:,jj)=p(:,jj)/pSum2(jj);
    end

    %% save current u, v, and w as u0, v0 and w0
    u0=u;v0=v;w0=w;

    %%update u
    u=(pNorm.')*raw;

    %% update v
    for jj=1:k
        for ss=1:dim
            x_u(:,ss)=raw(:,ss)-u(jj,ss)*ones(n,1);
        end
        x_u=x_u.*x_u;
        x_uSum=sum(x_u,2);
        v(jj)=sqrt(1/dim*(pNorm(:,jj).')*x_uSum);
    end

    %% update w
    w=(sum(p)/n).';

    %% update and display iteration and energy

    %disp(sprintf(['iteration=',num2str(iteration),'; energy=',num2str(energy,'%g')]))
    iteration=iteration+1;
    energy=sum(sum((u-u0).^2))+sum(sum((v-v0).^2))+(sum((w-w0).^2));

end


function [ xtab, weight ] = laguerre_compute ( norder, alpha )

%*****************************************************************************80
%
%% LAGUERRE_COMPUTE computes a Gauss-Laguerre quadrature rule.
%
%  Discussion:
%
%    In the simplest case, ALPHA is 0, and we are approximating the
%    integral from 0 to +oo of EXP(-X) * F(X).  When this is so,
%    it is easy to modify the rule to approximate the integral from
%    A to +oo as well.
%
%    If ALPHA is nonzero, then there is no simple way to extend the
%    rule to approximate the integral from A to +oo.  The simplest
%    procedures would be to approximate the integral from 0 to A.
%
%    The integration interval is [ A, +oo ) or [ 0, +oo ).
%
%    The weight function w(x) = EXP ( - X ) or EXP ( - X ) * X^ALPHA.
%
%
%    If the integral to approximate is:
%
%        Integral ( A <= X < +oo ) EXP ( - X ) * F(X) dX
%      or
%        Integral ( 0 <= X < +oo ) EXP ( - X ) * X^ALPHA * F(X) dX
%
%    then the quadrature rule is:
%
%      EXP ( - A ) * Sum ( 1 <= I <= ORDER ) WEIGHT(I) * F ( A+XTAB(I) )
%    or
%      sum ( 1 <= I <= ORDER ) WEIGHT(I) * F ( XTAB(I) )
%
%
%    If the integral to approximate is:
%
%        Integral ( A <= X < +oo ) F(X) dX
%      or
%        Integral ( 0 <= X < +oo ) X^ALPHA * F(X) dX
%
%    then the quadrature rule is:
%
%      EXP ( - A ) * sum ( 1 <= I <= ORDER )
%        WEIGHT(I) * EXP(A+XTAB(I)) * F ( A+XTAB(I) )
%    or
%      sum ( 1 <= I <= ORDER ) WEIGHT(I) * EXP(XTAB(I)) * F ( XTAB(I) )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 October 2005
%
%  Author:
%
%    Original FORTRAN77 version by Arthur Stroud, Don Secrest.
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Arthur Stroud, Don Secrest,
%    Gaussian Quadrature Formulas,
%    Prentice Hall, 1966,
%    LC: QA299.4G3S7.
%
%  Parameters:
%
%    Input, integer NORDER, the order of the quadrature rule to be computed.
%    NORDER must be at least 1.
%
%    Input, real ALPHA, the exponent of the X factor.
%    Set ALPHA = 0.0 for the simplest rule.
%    ALPHA must be nonnegative.
%
%    Output, real XTAB(NORDER), the Gauss-Laguerre abscissas.
%
%    Output, real WEIGHT(NORDER), the Gauss-Laguerre weights.
%

%
%  Set the recursion coefficients.
%
  for i = 1 : norder
    b(i) = ( alpha + 2 * i - 1 );
  end

  for i = 1 : norder
    c(i) = ( i - 1 ) * ( alpha + i - 1 );
  end

  cc = gamma ( alpha + 1.0 ) * prod ( c(2:norder) );

  for i = 1 : norder
%
%  Compute an estimate for the root.
%
    if ( i == 1 )

      x = ( 1.0 + alpha ) * ( 3.0 + 0.92 * alpha ) ...
        / ( 1.0 + 2.4 * norder + 1.8 * alpha );

    elseif ( i == 2 )

      x = x + ( 15.0 + 6.25 * alpha ) ...
        / ( 1.0 + 0.9 * alpha + 2.5 * norder );

    else

      r1 = ( 1.0 + 2.55 * ( i - 2 ) ) / ( 1.9 * ( i - 2 ) );

      r2 = 1.26 * ( i - 2 ) * alpha / ( 1.0 + 3.5 * ( i - 2 ) );

      ratio = ( r1 + r2 ) / ( 1.0 + 0.3 * alpha );

      x = x + ratio * ( x - xtab(i-2) );

    end
%
%  Use iteration to find the root.
%
    [ x, dp2, p1 ] = laguerre_root ( x, norder, alpha, b, c );
%
%  Set the abscissa and weight.
%
    xtab(i) = x;
    weight(i) = ( cc / dp2 ) / p1;

  end

  return
end


function [N]=gold_n(wl)

% the function calculates the index of refraction of gold (complex value), in the range of wavelength
% between 188nm and 1942nm.
% the input may be a scalar or vector, but it have to be an integer and in the right range.
% the values were taken from the paper:
%       P. B. Johnson, and R. W. Christy, "Optical Constants of the Noble Metals," Physical Review B 6, 4370 (1972).
% (the paper is available here: http://prb.aps.org/abstract/PRB/v6/i12/p4370_1 )
% the values for wavelength calculated with linear interpolation.
%
% Moshe Lindner, August 2010 (C).

if any((max(wl)>1942) || (min(wl)<188))
    error('Wavelength is out of range! (should be in the range of 188nm - 1942nm)')
    return
elseif any(wl~=ceil(wl))
    error('Wavelength must be an integer!')
    return
end

% n = real part
n=[0.92 0.56 0.43 0.35 0.27 0.22 0.17 0.16 0.14 0.13 0.14 0.21 0.29 0.43 0.62 1.04 1.31 1.39 1.45 1.46 1.47 1.46 1.48 1.5 1.48 1.48 1.54 1.53 1.53 1.49 1.47 1.43 1.38 1.35 1.33 1.33 1.32 1.32 1.3 1.31 1.3 1.3 1.3 1.3 1.33 1.33 1.34 1.32 1.28]';
n=n(end:-1:1);
% k = imaginary part
k=[13.78 11.21 9.519 8.145 7.15 6.35 5.663 5.083 4.542 4.103 3.697 3.272 2.863 2.455 2.081 1.833 1.849 1.914 1.948 1.958 1.952 1.933 1.895 1.866 1.871 1.883 1.898 1.893 1.889 1.878 1.869 1.847 1.803 1.749 1.688 1.631 1.577 1.536 1.497 1.46 1.427 1.387 1.35 1.304 1.277 1.251 1.226 1.203 1.188]';
k=k(end:-1:1);
% ev = photon energy in electronvolts
ev=[0.64 0.77 0.89 1.02 1.14 1.26 1.39 1.51 1.64 1.76 1.88 2.01 2.13 2.26 2.38 2.50 2.63 2.75 2.88 3 3.12 3.25 3.37 3.5 3.62 3.74 3.87 3.99 4.12 4.24 4.36 4.49 4.61 4.74 4.86 4.98 5.11 5.23 5.36 5.48 5.6 5.73 5.85 5.98 6.1 6.22 6.35 6.47 6.6]';
ev=ev(end:-1:1);
h=6.62606896e-34; % [J*sec] (Plank const.)
c=3e8; %[m/sec]  (speed of light)
q=1.6e-19; % [C] (electron charge)
lambda=1e9*h*c./(ev.*q);% wavelength in nanometer

lam=188:1942;
n1=interp1(lambda,n,lam,'linear');
k1=interp1(lambda,k,lam,'linear');

for q=1:length(wl)
    N(q)=n1(lam==wl(q)) + i*k1(lam==wl(q));
end


function B = bernstein_eval(i,n,u)
  % BERNSTERIN_EVAL evaluate a Bernstein polynomial. B_i,n(u)
  %
  % B = bernstein_eval(i,n,u)
  %
  % Inputs:
  %  i  #i scalar index of polynomial
  %  n  scalar order of polynomial
  %  u  #u evaluation points
  % Outputs:
  %  B  #u by #i values
  %
  u = reshape(u,numel(u),1);
  i = reshape(i,1,numel(i));
  nck = factorial(n)./(factorial(i).*factorial(n-(i)));
  B = nck .*  u.^i .* (1-u).^(n-i);
end


% book : Signals and Systems Laboratory with MATLAB
% authors : Alex Palamides & Anastasia Veloni
%
%
% Problem 7- Frequency Response and Impulse Response of an ideal bandpass
% filter

td=.05;
B1=10 ;
B2=20;
w1=-30:-B2;
H1=zeros(size(w1));
w2=-B2:-B1;
H2=exp(-j*w2*td);
w3=-B1:B1;
H3=zeros(size(w3));
w4=B1:B2;
H4= exp(-j*w4*td);
w5=B2:30;
H5=zeros(size(w5));
w=[w1 w2 w3 w4 w5];
H=[H1 H2 H3 H4 H5];
plot(w,abs(H))
ylim([-.2 1.2]);
legend(' |H(\Omega) | ')

figure
plot(w,angle(H));
ylim([-1.1 1.1]);
legend('\angle H(\Omega)')

figure
syms t w
H1=exp(-j*w*td)*(heaviside(w+B2)-heaviside(w+B1));
H2=exp(-j*w*td)*(heaviside(w-B1)-heaviside(w-B2));
h1=ifourier(H1,t);
h2=ifourier(H2,t);
h=h1+h2;
ezplot(h, [-3 3]);
ylim([-4 4]);
legend('Impulse response h(t) ')


function [Vc,R]=circlefit(V)

% function [Vc,R]=circlefit(V)
% ------------------------------------------------------------------------
% This function fits a circle to 2 or more points. The input is an array
% containing the points (vertices) V in 2D or 3D. Although 3D data is
% supported the Z-coordinates should all be equal such that the fitting
% problem remains 2D.
% The output consists of the circle centre Vc and radius R.
%
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
% 2019/11/21 Added to GIBBON
% ------------------------------------------------------------------------

%% Parse input

%Check if empty or not numeric
if isempty(V)
    error('Empty input')
elseif ~isnumeric(V)
    error('Input is not numeric');
end

%Force real
if ~isreal(V)
    V=real(V);
    warning('Complex data encountered. Complex parts ignored');
end

%Force double
if ~isa(V,'double')
    V=double(V); %Attempt conversion to double
end

%Check size
sizV=size(V);
if sizV(1)==1
    error('Only 1 point provided')
end

%Force 3D
if sizV(2)==2
    V(:,3)=0;
end

%% Fit cirlce
Vm=mean(V,1); %Get mean of point set
VD=V-Vm(ones(sizV(1),1),:); % shift points on mean
D=sqrt(sum(VD.^2,2)); %Compute distance to centre

if sizV(1)==2 %If only two points provided
    Vc=Vm; %Cirlc centre set to mean
    R=mean(D); %Radius set to mean distance
else %Fit circle to more than 2 points
    % Scale data
    scaleFactor=max(max(D,eps));
    VD=VD./scaleFactor; D=D./scaleFactor;

    % Solve sytem
    VF=[2*VD(:,1) 2*VD(:,2) ones(sizV(1),1)]\D.^2;

    % Unscale, collect output
    Q=[Vm(1) Vm(2) 0]+[VF(1) VF(2) sqrt(VF(3)+hypot(VF(1),VF(2)).^2)]*scaleFactor;

    Vc=[Q(1) Q(2) Vm(3)]; %Cirle centre
    R=Q(3); %Radius
end

if sizV(2)==2
    Vc=Vc(:,[1 2]);
end

end

%%
% _*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 value = p31_f ( dim_num, point_num, x )

%*****************************************************************************80
%
%% P31_F evaluates the integrand for problem 31.
%
%  Dimension:
%
%    DIM_NUM arbitrary.
%
%  Region:
%
%    0 <= X(1:DIM_NUM) <= 1
%
%  Integral Parameters:
%
%    There is a basis point Z associated with the integrand.
%    Z(1:DIM_NUM) defaults to ( 0.5, 0.5, ..., 0.5 ).
%    The user can set, get, or randomize this value by calling
%    P31_R8VEC.
%
%    The coefficient vector C (whose entries are usually positive)
%    controls the steepness and circularity of the pseudo-Gaussian.
%    C(1:DIM_NUM) defaults to 2.0.
%    The user can set, get, or randomize this value by calling
%    P31_R8VEC.
%
%  Integrand:
%
%    exp ( - sum ( c(1:dim_num) * abs ( x(1:dim_num) - z(1:dim_num) ) ) )
%
%  Exact Integral:
%
%    The integral is separable into
%
%      Int ( A(1) <= X(1) <= B(1) ) exp ( - C(1) * abs ( X(1) - Z(1) ) )
%        * Int ( A(2) <= X(2) <= B(2) ) exp ( - C(2) * abs ( X(2) - Z(2) ) )
%          * ...
%
%    Hence, the exact integral is computed as the product of
%    one dimensional integrals.  Each of these is easily computed
%    once the location of Z(I) with respect to A(I) and B(I) is
%    determined.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 June 2007
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Alan Genz,
%    [Integral #5]
%    A Package for Testing Multiple Integration Subroutines,
%    in Numerical Integration: Recent Developments, Software
%    and Applications,
%    edited by Patrick Keast and Graeme Fairweather,
%    D. Reidel, 1987, pages 337-340,
%    LC: QA299.3.N38.
%
%    Kenneth Hanson,
%    Quasi-Monte Carlo: halftoning in high dimensions?
%    in Computatinal Imaging,
%    Edited by CA Bouman and RL Stevenson,
%    Proceedings SPIE,
%    Volume 5016, 2003, pages 161-172.
%
%  Parameters:
%
%    Input, integer DIM_NUM, the dimension of the argument.
%
%    Input, integer POINT_NUM, the number of points.
%
%    Input, real X(DIM_NUM,POINT_NUM), the evaluation points.
%
%    Output, real VALUE(POINT_NUM), the integrand values.
%
  c = [];
  c = p31_r8vec ( 'G', 'C', dim_num, c );

  z = [];
  z = p31_r8vec ( 'G', 'Z', dim_num, z );

  value(1:point_num) = 0.0;

  for point = 1 : point_num

    value(point) = exp ( - sum ( c(1:dim_num)' .* ...
      abs ( x(1:dim_num,point) - z(1:dim_num)' ) ) );

  end

  p31_i4 ( 'I', '#', point_num );

  return
end


function res = SymPoly2Sym(F,Dexp,MaxCtr)
%SYMPOLY2SYM   Similar to poly2sym but can handle symbolic coefficients and
%indeterminate variables specified as equations
%
%   SymPoly2Sym('a*z^2 + b*z + c','z') = [a b c]
%   SymPoly2Sym('a*sin(x)^2 + b*sin(x) + c','sin(x)') = [a b c]

%%This function iteratively takes the derivative then evaluates at 0 to
%%determine the coefficients

if nargin<2,
    Dexp = 't'; %Default dependent variable
end
F = sym(subs(F,Dexp,'XX')); %Substitute independent variable 'XX' for dependent expression Dexp

if nargin<3,
    MaxCtr = 20; %Default maximum order
end

res = sym([]); %Initialize res as empty sym
ctr = 0; %Initialize counter
while F~=0,
    res(end+1) = subs(F,'XX',0); %Evaluate at XX=0
    F = diff(F,'XX',1); %Take derivative

    %%%%Check ctr as a defense against recursive loops
    ctr = ctr+1;
    if ctr>=MaxCtr,
        disp(['Error: Exceeded maximum number of terms (' num2str(MaxCtr) ')'])
        disp(['Inputs may be in invalid form (not a polynomial)'])
        disp('To increase maximum number, use SymPoly2Sym(F,DV,Max#)')
        res = [];
        return
    end
    %%%%%%%%

end
Fact = [1 cumprod(1:length(res)-1)]; %Create factorial vector
res = res./Fact; %Divide coefficients by the amount contributed by derivative operations
res = res(end:-1:1); %Reverse order to match poly2sym convention