function [x, funVal, ValueL, res]=overlapping_LeastR(A, y, z, opts)
%
%%
% Function overlapping_LeastR
%      Least Squares Loss with the
%           overlapping group Lasso
%
%% Problem
%
%  min  1/2 || A x - y||^2 + z_1 \|x\|_1 + z_2 * sum_i w_i ||x_{G_i}||
%
%  G_i's are nodes
%
%    we have L1 for each element
%    and the L2 for the overlapping group
%
%  The overlapping group information is contained in
%
%   opts.G- a row vector containing the indices of all the overlapping
%           groups G_1, G_2, ..., G_groupNum
%
%   opts.ind- a 3 x groupNum matrix
%           opts.ind(1,i): the starting index of G_i in opts.G
%           opts.ind(2,i): the ending index of G_i in opts.G
%           opts.ind(3,i): the weight for the i-th group
%
% For better illustration, we consider the following example of four groups:
%   G_1={1,2,3}, G_2={2,4}, G_3={3,5}, G_4={1,5}.
% Let us assume the weight for each group is 123.
%
%   opts.G=[1,2,3,2,4,3,5,1,5];
%   opts.ind=[ [1, 3, 123]', [4,5,123]',[6,7,123]',[8,9,123]' ];
%
%
%% Input parameters:
%
%  A-         Matrix of size m x n
%                A can be a dense matrix
%                         a sparse matrix
%                         or a DCT matrix
%  y -        Response vector (of size mx1)
%  z -        The regularization parameter (z=[z_1,z_2] >=0)
%  opts-      Optimal inputs (default value: opts=[])
%
%% Output parameters:
%
%  x-         Solution
%  funVal-    Function value during iterations
%
%% Copyright (C) 2010-2011 Jun Liu, and Jieping Ye
%
% You are suggested to first read the Manual.
%
% For any problem, please contact with Jun Liu via j.liu@asu.edu
%
% Last modified on April 21, 2010.
%
%% Related papers
%
% [1]  Jun Liu and Jieping Ye, Fast Overlapping Group Lasso,
%      arXiv:1009.0306v1, 2010
%
%% Related functions:
%
%  sll_opts, initFactor, pathSolutionLeast
%
%%

%% Verify and initialize the parameters
%%
if (nargin <4)
    error('\n Inputs: A, y, z, and opts (.ind) should be specified!\n');
end

[m,n]=size(A);

if (length(y) ~=m)
    error('\n Check the length of y!\n');
end

if (z(1)<0 || z(2)<0)
    error('\n z should be nonnegative!\n');
end

lambda1=z(1);
lambda2=z(2);

opts=sll_opts(opts); % run sll_opts to set default values (flags)

% restart the program for better efficiency
%  this is a newly added function
if (~isfield(opts,'rStartNum'))
    opts.rStartNum=opts.maxIter;
else
    if (opts.rStartNum<=0)
        opts.rStartNum=opts.maxIter;
    end
end

%% Detailed initialization
%% Normalization

% Please refer to sll_opts for the definitions of mu, nu and nFlag
%
% If .nFlag =1, the input matrix A is normalized to
%                     A= ( A- repmat(mu, m,1) ) * diag(nu)^{-1}
%
% If .nFlag =2, the input matrix A is normalized to
%                     A= diag(nu)^{-1} * ( A- repmat(mu, m,1) )
%
% Such normalization is done implicitly
%     This implicit normalization is suggested for the sparse matrix
%                                    but not for the dense matrix
%

if (opts.nFlag~=0)
    if (isfield(opts,'mu'))
        mu=opts.mu;
        if(size(mu,2)~=n)
            error('\n Check the input .mu');
        end
    else
        mu=mean(A,1);
    end

    if (opts.nFlag==1)
        if (isfield(opts,'nu'))
            nu=opts.nu;
            if(size(nu,1)~=n)
                error('\n Check the input .nu!');
            end
        else
            nu=(sum(A.^2,1)/m).^(0.5); nu=nu';
        end
    else % .nFlag=2
        if (isfield(opts,'nu'))
            nu=opts.nu;
            if(size(nu,1)~=m)
                error('\n Check the input .nu!');
            end
        else
            nu=(sum(A.^2,2)/n).^(0.5);
        end
    end

    ind_zero=find(abs(nu)<= 1e-10);    nu(ind_zero)=1;
    % If some values in nu is typically small, it might be that,
    % the entries in a given row or column in A are all close to zero.
    % For numerical stability, we set the corresponding value to 1.
end

if (~issparse(A)) && (opts.nFlag~=0)
    fprintf('\n -----------------------------------------------------');
    fprintf('\n The data is not sparse or not stored in sparse format');
    fprintf('\n The code still works.');
    fprintf('\n But we suggest you to normalize the data directly,');
    fprintf('\n for achieving better efficiency.');
    fprintf('\n -----------------------------------------------------');
end

%% Group & Others

% Initialize maxIter2
if (~isfield(opts,'maxIter2'))
    maxIter2=1000;
else
    maxIter2=opts.maxIter2;
end
% the maximal number of iteration for the projection

% Initialize tol2
if (~isfield(opts,'tol2'))
    tol2=1e-8;
else
    tol2=opts.tol2;
end
% the duality gap of the projection

% Initialize flag2
if (~isfield(opts,'flag2'))
    flag2=2;
else
    flag2=opts.flag2;
end

% Initialize G
if (~isfield(opts,'G'))
    error('\n In overlapping_LeastR, the field .G should be specified');
else
    G=opts.G-1;
    % we substract 1, as in C, the index begins with 0
end

% Initialize w
if (~isfield(opts,'ind'))
    error('\n In overlapping_LeastR, the field .ind should be specified');
else
    w=opts.ind;

    if (size(w,1)~=3)
        error('\n w is a 3 x groupNum matrix');
    end

    w(1:2,:)=w(1:2,:)-1;
    % we substract 1, as in C, the index begins with 0
end

groupNum=size(w,2);
% the number of groups

Y=zeros(length(G),1);
% the starting point for the projection

%% Starting point initialization

% compute AT y
if (opts.nFlag==0)
    ATy =A'*y;
elseif (opts.nFlag==1)
    ATy= A'*y - sum(y) * mu';  ATy=ATy./nu;
else
    invNu=y./nu;              ATy=A'*invNu-sum(invNu)*mu';
end

% process the regularization parameter
if (opts.rFlag~=0)
    % z here is the scaling factor lying in [0,1]
%     if (lambda1<0 || lambda1>1 || lambda2<0 || lambda2>1)
%         error('\n opts.rFlag=1, and z should be in [0,1]');
%     end

    % compute lambda1_max
    temp=abs(ATy);
    lambda1_max=max(temp);

    lambda1=lambda1*lambda1_max;

    % compute lambda2_max(lambda_1)

    % lambda_2_max to be added later

    lambda2_max=1;

    lambda2=lambda2*lambda2_max;
end

% initialize a starting point
if opts.init==2
    x=zeros(n,1);
else
    if isfield(opts,'x0')
        x=opts.x0;
        if (length(x)~=n)
            error('\n Check the input .x0');
        end
    else
        x=ATy;  % if .x0 is not specified, we use ratio*ATy,
        % where ratio is a positive value
    end
end

% compute A x
if (opts.nFlag==0)
    Ax=A* x;
elseif (opts.nFlag==1)
    invNu=x./nu; mu_invNu=mu * invNu;
    Ax=A*invNu -repmat(mu_invNu, m, 1);
else
    Ax=A*x-repmat(mu*x, m, 1);     Ax=Ax./nu;
end

if (opts.init==0)
    % ------  This function is not available
    %
    % If .init=0, we set x=ratio*x by "initFactor"
    % Please refer to the function initFactor for detail
    %

    % Here, we only support starting from zero, due to the complex
    % structure

    %x=zeros(n,1);
end

%% The main program
% The Armijo Goldstein line search schemes + accelearted gradient descent

bFlag=0; % this flag tests whether the gradient step only changes a little

if (opts.mFlag==0 && opts.lFlag==0)
    L=1;
    % We assume that the maximum eigenvalue of A'A is over 1

    % assign xp with x, and Axp with Ax
    xp=x; Axp=Ax; xxp=zeros(n,1);

    alphap=0; alpha=1;

    for iterStep=1:opts.maxIter
        % --------------------------- step 1 ---------------------------
        % compute search point s based on xp and x (with beta)
        beta=(alphap-1)/alpha;    s=x + beta* xxp;

        % --------------------------- step 2 ---------------------------
        % line search for L and compute the new approximate solution x

        % compute the gradient (g) at s
        As=Ax + beta* (Ax-Axp);

        % compute AT As
        if (opts.nFlag==0)
            ATAs=A'*As;
        elseif (opts.nFlag==1)
            ATAs=A'*As - sum(As) * mu';  ATAs=ATAs./nu;
        else
            invNu=As./nu;                ATAs=A'*invNu-sum(invNu)*mu';
        end

        % obtain the gradient g
        g=ATAs-ATy;

        % copy x and Ax to xp and Axp
        xp=x;    Axp=Ax;

        firstFlag=1;
        while (1)
            % let s walk in a step in the antigradient of s to get v
            % and then do the L1/Lq-norm regularized projection
            v=s-g/L;

            % projection
            [x,gap,penalty2]=overlapping(v,  n, groupNum, lambda1/L, lambda2/L,...
                w, G, Y, maxIter2, flag2, tol2);

            if (nargout ==4)
                % record the number of iterations

                if (firstFlag)
                    res.projStep(iterStep)=penalty2(4);
                else
                    res.projStep(iterStep)=...
                        max(res.projStep(iterStep),penalty2(4) );
                end
            end
            firstFlag=0;

            v=x-s;  % the difference between the new approximate solution x
            % and the search point s

            % compute A x
            if (opts.nFlag==0)
                Ax=A* x;
            elseif (opts.nFlag==1)
                invNu=x./nu; mu_invNu=mu * invNu;
                Ax=A*invNu -repmat(mu_invNu, m, 1);
            else
                Ax=A*x-repmat(mu*x, m, 1);     Ax=Ax./nu;
            end

            Av=Ax -As;
            r_sum=v'*v; l_sum=Av'*Av;

            if (r_sum <=1e-20)
                bFlag=1; % this shows that, the gradient step makes little improvement
                break;
            end

            % the condition is ||Av||_2^2 <= L * ||v||_2^2
            if(l_sum <= r_sum * L)
                break;
            else
                L=max(2*L, l_sum/r_sum);
                %fprintf('\n L=%5.6f',L);
            end
        end

        % --------------------------- step 3 ---------------------------
        % update alpha and alphap, and check whether converge
        alphap=alpha; alpha= (1+ sqrt(4*alpha*alpha +1))/2;

        xxp=x-xp;   Axy=Ax-y;

        ValueL(iterStep)=L;

        % function value = loss + regularizatioin
        funVal(iterStep)=Axy'* Axy/2 + lambda1 * sum(abs(x)) + lambda2 *penalty2 (1);

        if (nargout ==4)
            % record pp and gg;
            res.pp(iterStep)=penalty2 (2);
            res.qq(iterStep)=penalty2 (3);

            % record gap
            res.gap(iterStep)=gap;

            % record the number of zero group in the solution
            res.zg(iterStep)=penalty2(5);
        end

        if (bFlag)
            % fprintf('\n The program terminates as the gradient step changes the solution very small.');
            break;
        end

        switch(opts.tFlag)
            case 0
                if iterStep>=2
                    if (abs( funVal(iterStep) - funVal(iterStep-1) ) <= opts.tol)
                        break;
                    end
                end
            case 1
                if iterStep>=2
                    if (abs( funVal(iterStep) - funVal(iterStep-1) ) <=...
                            opts.tol* funVal(iterStep-1))
                        break;
                    end
                end
            case 2
                if ( funVal(iterStep)<= opts.tol)
                    break;
                end
            case 3
                norm_xxp=sqrt(xxp'*xxp);
                if ( norm_xxp <=opts.tol)
                    break;
                end
            case 4
                norm_xp=sqrt(xp'*xp);    norm_xxp=sqrt(xxp'*xxp);
                if ( norm_xxp <=opts.tol * max(norm_xp,1))
                    break;
                end
            case 5
                if iterStep>=opts.maxIter
                    break;
                end
        end

        % restart the program every opts.rStartNum
        if (~mod(iterStep, opts.rStartNum))
            alphap=0; alpha=1;
            xp=x; Axp=Ax; xxp=zeros(n,1); L =L/2;
        end
    end
else
    error('\n The function does not support opts.mFlag neq 0 & opts.lFlag neq 0!');
end


function  F = FGG_3d(f,knots,N,accuracy,GridListx, GridListy, GridListz)
%Description:
%This code implements the 3D version of the "accelerated"
%Gaussian-gridding-based NUFFT described in Greengard and Lee [1]. The
%gridding approach is very similar to previous work by Nguyen and Liu [2];
%the only difference is the use of a different convolution kernel ([1]
%claims that the Gaussian kernel has computational advantages). Both
%algorithms allow the user to specify the numerical precision of the
%routine, but [1] provides a nice summary that would allow one to tabulate
%the appropriate variable values for each desired numerical precision. Code
%for [2] is also available upon request.
%
%This code performs NUFFTs that form rectangular cubes of size N=[Nx,Ny,Nz]
%(not counting frequency padding for image interpolation). The approximate
%DFT attains errors on the order of 1e-6 (for more or less accuracy, vary
%the optional "accuracy" parameter).
%
%Inputs:
%       f: frequency-domain data (a complex Mx1 vector) unwrapped from a
%           matrix knots: k-space locations at which the data were measured
%           (an Mx3 vector). This data must be in double format.
%       knots: the frequency locations of the data points. These locations
%           should be normalized to correspond to the grid boundaries
%           [-N/2, N/2 -1/N], N even. If the knots are not scaled
%           properly, they will be shifted and scaled into this normalized
%           form.
%       N = [Nx,Ny,Nz]: the 1x3 vector denoting the size of the spatial
%           grid in the image domain. This parameter will determine the
%           spatial extent of the image.
%       accuracy: (optional input parameter) a positive integer indicating
%           the desired number of digits of accuracy
%Optional Inputs (highly recommended):
%       GridListx:(column vector) The x-locations of the
%           frequency grid (not yet scaled by c or 2*pi) onto which the
%           data should be interpolated
%       GridListy:(column vector) The y-locations of the
%           frequency grid (not yet scaled by c or 2*pi) onto which the
%           data should be interpolated
%       GridListz:(column vector) The z-locations of the
%           frequency grid (not yet scaled by c or 2*pi) onto which the
%           data should be interpolated
%Outputs:
%       F: the 3D NUFFT (approximate DFT) of f, with dimension [Nx,Ny,Nz].
%
%
%Usage Notes:
%In order for this function to work, the C
%file "FGG_Convolution3D.c" must be compiled into a Matlab executable
%(cmex) with the following command in the command prompt:
%
%mex FGG_Convolution3D.c
%
%A note on the effect of M_sp on the algorithm's accuracy:
%[R,M_sp]=[2,3]  ==> 1e-3 accuracy
%[R,M_sp]=[2,6]  ==> single precision
%[R,M_sp]=[2,9]  ==> 1e-9 accuracy
%[R,M_sp]=[2,12] ==> double precision
%
%References:
%[1] L. Greengard and J. Lee, "Accelerating the Nonuniform Fast Fourier
%Transform," SIAM Review, Vol. 46, No. 3, pp. 443-454.
%[2] N. Nguyen and Q. H. Liu, "Nonuniform fast fourier transforms," SIAM J.
%Sci. Comput., 1999.
%
%Please note:
%This code is free to use, but we ask that you please reference the source,
%as this will encourage future funding for more free AFRL products. This
%code was developed through the AFOSR Lab Task "Moving-Target Radar Feature
%Extraction."
%Project Manager: Arje Nachman
%Principal Investigator: Matthew Ferrara
%Date: November 2008
%
%Code by (send correspondence to):
%Matthew Ferrara, Research Mathematician
%AFRL Sensors Directorate Innovative Algorithms Branch (AFRL/RYAT)
%Matthew.Ferrara@wpafb.af.mil

%Explanation of variables used
%bw             The bandwidth of the input data (fmax-fmin)
%D              A [Nx,Ny,Nz] deconvolution matrix formed from the 3D
%               kronecker product of E4_x, E4_y, and E4_z
%dgx,dgy,dgz    The separation (in the frequency domain) of the
%               user-defined k-space grid onto which the data should be
%               interpolated
%E1, E2, E3     factors of the Gaussian filter in the frequency domain
%               (the Gaussian is factored to eliminate redundant
%               exponential calculations)
%E4             The Gaussian deconvolution filter
%f              The Mx1 vector of nonuniformly-spaced frequency data given
%               as input to the NUFFT routine
%f_tau          The [R*Nx,R*Ny] matrix of uniformly-spaced fequency-domain
%               data values after "gridding"
%F_tau          The FFT of f_tau
%F              The approximate DFT of f (the deconvolved FFT of f_tau)
%fmean          The average knot values of the input data (1x3 vector)
%j              Index variable that indexes the convolution loop through
%               the data points (1 <= j <= M)
%kmin           The minimum knot values of the input data (1x3 vector)
%kmax           The maximum knot values of the input data (1x3 vector)
%knots          The Mx3 vector of frequency locations given as input to
%               the NUFFT.
%M              The number of (k-space) data points (the length of the
%               input data vector f)
%M_sp           Width of the frequency-domain box used in the approximate
%               interpolation of each data point onto the frequency grid
%               (M_sp=6 for single precision and M_sp=12 for double
%               precision)
%N              The image size of the NUFFT output (N=[Nx, Ny, Nz])
%Nx             The length of the image in the x dimension
%Ny             The length of the image in the y dimension
%Nz             The length of the image in the z dimension
%R              Oversampling ratio for gridding in the frequency (data)
%               domain
%S              The [Nz,Nx*Ny]-sized kronecker product of E4z, E4_x, and
%               E4_y
%scale          1x3 vector used to scale the input data locations into the
%               normalized form
%shift          1x3 vector used to shift the input data locations into the
%               normalized form
%tau            The 3x1 Gaussian kernel spreading factor
%End Explanation of variables

%% Step 1: Initialize constant variables:
M=length(f);%number of frequency-domain data points
if nargin<4, accuracy=6; end
if nargin<3, N=M; accuracy=6; end
if length(N)<2, N=N(1)*[1,1,1];accuracy=6; end
%The size parameters [Nx,Ny] determine the spatial extent of the image
Nx=N(1); Ny=N(2); Nz=N(3);
%R is the oversampling ratio(>1) for gridding in the frequency (data)
%domain. There are diminishing returns in accuracy after R=2 (M_sp has a
%more direct effect on accuracy).
R=2;
%M_sp is the length of the convolution kernel
M_sp=accuracy;%This gives roughly 6 digits of accuracy
%The variance, tau, of the Gaussian filter may be different in each
%dimension
%tau = M_sp./(N.^2);%I was initially using this value
tau = (pi*M_sp./(N.*N*R*(R-.5)));%Suggested value of tau by Greengard [1]
%The length of the oversampled grid
M_r = R*N;
%Scale knots (data locations) to [-N/2,N/2-1] (I don't initially use
%Greengard's [0,2*pi] convention, but instead assume users will most likely
%be thinking in terms of fs<=f<=fe)
kmin=min(knots);
kmax=max(knots);

if nargin <=4,%Simply choose the most convenient frequency-domain grid
    bw=kmax-kmin;
    scale=(N-1)./bw;
    shift=-N/2-kmin.*scale;
    knots=repmat(scale,[M,1]).*knots + repmat(shift,[M,1]);
else%we specify knot locations in terms of the user-defined grid (this
    %consequently specifies the image pixel locations)
    fmean=(kmin+kmax)/2;
    dgx=GridListx(2)-GridListx(1);
    dgy=GridListy(2)-GridListy(1);
    dgz=GridListz(2)-GridListz(1);
    %We choose to ensure that the data are perfectly centered on the grid:
    kminx=fmean(1)-(Nx/2)*dgx;
    kmaxx=kminx+(Nx-1)*dgx;
    kminy=fmean(2)-(Ny/2)*dgy;
    kmaxy=kminy+(Ny-1)*dgy;
    kminz=fmean(3)-(Nz/2)*dgz;
    kmaxz=kminz+(Nz-1)*dgz;
    kmin=[kminx,  kminy, kminz];
    kmax=[kmaxx,  kmaxy, kmaxz];
    %The BW that covers the whole k-space region when confined to the
    %specified grid spacing
    bw=[kmaxx-kminx,  kmaxy-kminy,  kmaxz-kminz];
    scale=(N-1)./bw;
    shift=-.5*[Nx,Ny,Nz]-[kminx,kminy,kminz].*scale;
    knots=repmat(scale,[M,1]).*knots + repmat(shift,[M,1]);
end
%Switch knot locations to [0,2*pi] convention (used by Greengard):
knots=mod(2*pi*knots./repmat(N,[M,1]),2*pi);%Makes NUFFT implementation
%more straightforward when notation is the same!

%Precompute E_3, the constant component of the (truncated) Gaussian:
E_3x(1,1:M_sp) = exp(-((pi*(1:M_sp)/M_r(1)).^2)/tau(1));
%don't waste (slow) exponential calculations
E_3x=[fliplr(E_3x(1:(M_sp-1))),1,E_3x];
E_3y(1,1:M_sp) = exp(-((pi*(1:M_sp)/M_r(2)).^2)/tau(2));
%don't waste (slow) exponential calculations
E_3y=[fliplr(E_3y(1:(M_sp-1))),1,E_3y];
E_3z(1,1:M_sp) = exp(-((pi*(1:M_sp)/M_r(3)).^2)/tau(3));
%don't waste (slow) exponential calculations
E_3z=[fliplr(E_3z(1:(M_sp-1))),1,E_3z];

%Precompute E_4 (for devonvolution after the FFT)
kx_vec = (-Nx/2):(Nx/2-1);
%The Hadamard Inverse of the Fourier Transform of the truncated Gaussian
E_4x(1:Nx,1)=sqrt(pi/tau(1))*exp(tau(1)*(kx_vec.^2));
ky_vec = (-Ny/2):(Ny/2-1);
%The Hadamard Inverse of the Fourier Transform of the truncated Gaussian
E_4y(1,1:Ny)=sqrt(pi/tau(2))*exp(tau(2)*(ky_vec.^2));%
kz_vec = (-Nz/2):(Nz/2-1);
%The Hadamard Inverse of the Fourier Transform of the truncated Gaussian
E_4z(1:Nz,1)=sqrt(pi/tau(3))*exp(tau(3)*(kz_vec.^2));%
%End initialization of constant variables

%% Step 2: Approximate convolution for each datum location, (x_j,y_j). This
% step is implemented in C and compiled into a Matlab-executable (cmex)
% file.
%Initialize convolved data matrix
f_tau=zeros(M_r(1),M_r(2),M_r(3));
f_taui=zeros(M_r(1)*M_r(2)*M_r(3),1);%Imaginary components of f_tau
f_taur=zeros(M_r(1)*M_r(2)*M_r(3),1);%Real components of f_tau
%Perform convolution onto finely-spaced grid

[f_taur,f_taui]=...
    FGG_Convolution3D(double(real(f(:))),double(imag(f(:))),...
    double(knots(:)),double(E_3x), double(E_3y), double(E_3z), ...
    [double(M_sp), double(tau(1)), double(tau(2)), double(tau(3)),...
 double(M_r(1)), double(M_r(2)), double(M_r(3))]);

f_tau = reshape(f_taur+sqrt(-1)*f_taui,[M_r(1), M_r(2), M_r(3)]);

%% Step 3: Perform FFT and deconvolve the result
%Perform FFT
F_tau=fftshift(fftn(ifftshift(f_tau)));
%Chop off excess pixels(the fine spacing in the frequency domain expanded
%the image in the transform domain)
F_tau(1:round(.5*(R-1)*Nx),:,:)=[];
F_tau(Nx+1:end,:,:)=[];
F_tau(:,1:round(.5*(R-1)*Ny),:)=[];
F_tau(:,Ny+1:end,:)=[];
F_tau(:,:,1:round(.5*(R-1)*Nz))=[];
F_tau(:,:,Nz+1:end)=[];

%Deconvolve the FFT by Hadamard multiplication with the Gaussian
%To form the deconvolution matrix S, we could do this with a loop:
%for i=1:Nx
%    for j=1:Ny
%        for k=1:Nz
%        S(i,j,k)=E_4x(i)*E_4y(j)*E_4z(k);
%        end
%    end
%end
%HOWEVER, Matlab is extremely slow with loops so we instead use the kron()
%function and reshape the result (alternatively, we could have written
%another mex function):
S=kron(E_4z,E_4x*E_4y);%Scalars for 3D kronecker product (matrix must be
                       %reshaped)
D=permute(reshape(S,[Nx,Nz,Ny]),[1,3,2]);
F=F_tau.*D/(M*R*R*R); %Note that the scaling factor is 1/M, which is
%apparently not 1/M_r as shown in eqn (9) in [1]. This makes sense because
%the scaling factor for the DFT we are attempting to approximate (in eqn
%(1) of [1]) is 1/M.

%% If desired, compare to DFT
% F_true=zeros(Nx,Ny,Nz);
% for m=(-Nx/2):(Nx/2 -1)
%     for n=(-Ny/2):(Ny/2 -1)
%           for o=(-Nz/2):(Nz/2 -1)
%         for k=1:M
%             F_true(m+Nx/2+1,n+Ny/2+1,o+Nz/2+1)=...
%               F_true(m+Nx/2+1,n+Ny/2+1,o+Nz/2+1)+...
%               f(k)*exp(sqrt(-1)*(m*knots(k,1) + n*knots(k,2) + ...
%               o*knots(k,3)));
%         end
%     end
% end
% F_true=F_true/M;
%
% figure
% isosurface(abs(F))
% title('F via NUFFT')
%
% figure
% isosurface(abs(F_true))
% title('F via DFT')
%
%error('done!')


%This function calculates BETA probabilities at each stage for all states,
%using GAMMA probabilities obtained previously. Uses recursion formula for
%BETA to calculate it for the previous stage. Each column is for states 00,10,01
%and 11 respectively. As we move backward in the block BETA will become very
%small, as the 1st term corresponding to gamma can be very less(of the order
%of 10^(-15)). Hence BETA will keep on decreasing and  will become very small.
%After some stages it will become exactly 0. So to avoid that we can
%multiply each BETA by 10^(-20) at a stage where they all become less than
%10^(-20). As we need BETA in calculation of LAPPR. So scaling wont affect the ratio

function [BETA]=beta_1(GAMMA,N)

    BETA=zeros(4,N);
    %Initialization assuming the final stage to be 00
    BETA(1,N)=1;BETA(2,N)=0;BETA(3,N)=0;BETA(4,N)=0;

    j=2*N-1;
    for i=N-1:-1:1
       BETA(1,i)=(GAMMA(1,j)*BETA(1,i+1))+(GAMMA(1,j+1)*BETA(2,i+1));
       BETA(2,i)=(GAMMA(2,j)*BETA(3,i+1))+(GAMMA(2,j+1)*BETA(4,i+1));
       BETA(3,i)=(GAMMA(3,j)*BETA(2,i+1))+(GAMMA(3,j+1)*BETA(1,i+1));
       BETA(4,i)=(GAMMA(4,j)*BETA(4,i+1))+(GAMMA(4,j+1)*BETA(3,i+1));
       j=j-2;

       if (BETA(1,i)<10^(-20) && BETA(2,i)<10^(-20) &&...
               BETA(3,i)<10^(-20) && BETA(4,i)<10^(-20) )
           BETA(:,i)=10^(20)*BETA(:,i);         %Scaling beta if became very less
       end
    end

end


function R=Rxyz(t,flag)

if flag==1
    R=[1       0         0;
       0     cos(t)   -sin(t);
       0     sin(t)    cos(t)]';
elseif flag==2
     R=[cos(t)       0         sin(t);
           0         1           0;
       -sin(t)       0         cos(t)]';
elseif flag==3
    R=[   cos(t)      -sin(t)       0;
          sin(t)       cos(t)       0;
           0            0           1]';
end

return;


function checkdiff(problem, x, d, force_gradient)
% Checks the consistency of the cost function and directional derivatives.
%
% function checkdiff(problem)
% function checkdiff(problem, x)
% function checkdiff(problem, x, d)
%
% checkdiff performs a numerical test to check that the directional
% derivatives defined in the problem structure agree up to first order with
% the cost function at some point x, along some direction d. The test is
% based on a truncated Taylor series (see online Manopt documentation).
%
% Both x and d are optional and will be sampled at random if omitted.
%
% See also: checkgradient checkhessian

% If force_gradient = true (hidden parameter), then the function will call
% getGradient and infer the directional derivative, rather than call
% getDirectionalDerivative directly. This is used by checkgradient.

% This file is part of Manopt: www.manopt.org.
% Original author: Nicolas Boumal, Dec. 30, 2012.
% Contributors:
% Change log:
%
%   March 26, 2017 (JB):
%       Detects if the approximated linear model is exact
%       and provides the user with the corresponding feedback.
%
%   April 3, 2015 (NB):
%       Works with the new StoreDB class system.
%
%   Aug. 2, 2018 (NB):
%       Using storedb.remove() to avoid unnecessary cache build-up.
%
%   Sep. 6, 2018 (NB):
%       Now checks whether M.exp() is available; uses retraction otherwise.
%
%   June 18, 2019 (NB):
%       Now issues a warning if the cost function returns complex values.

    if ~exist('force_gradient', 'var')
        force_gradient = false;
    end

    % Verify that the problem description is sufficient.
    if ~canGetCost(problem)
        error('It seems no cost was provided.');
    end
    if ~force_gradient && ~canGetDirectionalDerivative(problem)
        error('It seems no directional derivatives were provided.');
    end
    if force_gradient && ~canGetGradient(problem)
        % Would normally issue a warning, but this function should only be
        % called with force_gradient on by checkgradient, which will
        % already have issued a warning.
    end

    x_isprovided = exist('x', 'var') && ~isempty(x);
    d_isprovided = exist('d', 'var') && ~isempty(d);

    if ~x_isprovided && d_isprovided
        error('If d is provided, x must be too, since d is tangent at x.');
    end

    % If x and / or d are not specified, pick them at random.
    if ~x_isprovided
        x = problem.M.rand();
    end
    if ~d_isprovided
        d = problem.M.randvec(x);
    end

    % Compute the value f0 at f and directional derivative at x along d.
    storedb = StoreDB();
    xkey = storedb.getNewKey();
    f0 = getCost(problem, x, storedb, xkey);

    if ~force_gradient
        df0 = getDirectionalDerivative(problem, x, d, storedb, xkey);
    else
        grad = getGradient(problem, x, storedb, xkey);
        df0 = problem.M.inner(x, grad, d);
    end

    % Pick a stepping function: exponential or retraction?
    if isfield(problem.M, 'exp')
        stepper = problem.M.exp;
    else
        stepper = problem.M.retr;
        % No need to issue a warning: to check the gradient, any retraction
        % (which is first-order by definition) is appropriate.
    end

    % Compute the value of f at points on the geodesic (or approximation
    % of it) originating from x, along direction d, for stepsizes in a
    % large range given by h.
    h = logspace(-8, 0, 51);
    value = zeros(size(h));
    for k = 1 : length(h)
        y = stepper(x, d, h(k));
        ykey = storedb.getNewKey();
        value(k) = getCost(problem, y, storedb, ykey);
        storedb.remove(ykey); % no need to keep it in memory
    end

    % Compute the linear approximation of the cost function using f0 and
    % df0 at the same points.
    model = polyval([df0 f0], h);

    % Compute the approximation error
    err = abs(model - value);

    % And plot it.
    loglog(h, err);
    title(sprintf(['Directional derivative check.\nThe slope of the '...
                   'continuous line should match that of the dashed\n'...
                   '(reference) line over at least a few orders of '...
                   'magnitude for h.']));
    xlabel('h');
    ylabel('Approximation error');

    line('xdata', [1e-8 1e0], 'ydata', [1e-8 1e8], ...
         'color', 'k', 'LineStyle', '--', ...
         'YLimInclude', 'off', 'XLimInclude', 'off');

    if ~all( err < 1e-12 )
        % In a numerically reasonable neighborhood, the error should
        % decrease as the square of the stepsize, i.e., in loglog scale,
        % the error should have a slope of 2.
        isModelExact = false;
        window_len = 10;
        [range, poly] = identify_linear_piece(log10(h), log10(err), window_len);
    else
        % The 1st order model is exact: all errors are (numerically) zero
        % Fit line from all points, use log scale only in h.
        isModelExact = true;
        range = 1:numel(h);
        poly = polyfit(log10(h), err, 1);
        % Set mean error in log scale for plot.
        poly(end) = log10(poly(end));
        % Change title to something more descriptive for this special case.
        title(sprintf(...
              ['Directional derivative check.\n'...
               'It seems the linear model is exact:\n'...
               'Model error is numerically zero for all h.']));
    end
    hold all;
    loglog(h(range), 10.^polyval(poly, log10(h(range))), 'LineWidth', 3);
    hold off;

    if ~isModelExact
        fprintf('The slope should be 2. It appears to be: %g.\n', poly(1));
        fprintf(['If it is far from 2, then directional derivatives ' ...
                 'might be erroneous.\n']);
    else
        fprintf(['The linear model appears to be exact ' ...
                 '(within numerical precision),\n'...
                 'hence the slope computation is irrelevant.\n']);
    end

    if ~(isreal(value) && isreal(f0))
        fprintf(['# The cost function appears to return complex values' ...
              '.\n# Please ensure real outputs.\n']);
    end

end


function [out] = saturation_2(S,Smax,p1,In)
%saturation_2

% Copyright (C) 2019, 2021 Wouter J.M. Knoben, Luca Trotter
% This file is part of the Modular Assessment of Rainfall-Runoff Models
% Toolbox (MARRMoT).
% MARRMoT is a free software (GNU GPL v3) and distributed WITHOUT ANY
% WARRANTY. See <https://www.gnu.org/licenses/> for details.

% Flux function
% ------------------
% Description:  Saturation excess from a store with different degrees of saturation
% Constraints:  1-S/Smax >= 0       prevents numerical issues with complex
%                                   numbers
% @(Inputs):    S    - current storage [mm]
%               Smax - maximum contributing storage [mm]
%               p1   - non-linear scaling parameter [-]
%               In   - incoming flux [mm/d]

% NOTE: When stores are very slightly below or over their maximum, the
% exponent can push this function into regions where no feasible solutions
% exist. The min(max()) combination prevents this from happening.

out = (1- min(1,max(0,(1-S./Smax))).^p1) .*In;

end


function M = multinomialfactory(n, m)
% Manifold of n-by-m column-stochastic matrices with positive entries.
%
% function M = multinomialfactory(n, m)
%
% The returned structure M is a Manopt manifold structure to optimize over
% the set of n-by-m matrices with (strictly) positive entries and such that
% the entries of each column sum to one.
%
% The metric imposed on the manifold is the Fisher metric such that
% the set of n-by-m column-stochastic matrices (aka the multinomial manifold)
% is a Riemannian submanifold of the space of n-by-m matrices. Also it
% should be noted that the retraction operation that we define
% is first order and as such the checkhessian tool cannot verify
% the slope correctly.
%
% The file is based on developments in the research paper
% Y. Sun, J. Gao, X. Hong, B. Mishra, and B. Yin,
% "Heterogeneous tensor decomposition for clustering via manifold
% optimization", arXiv:1504.01777, 2015.
%
% Link to the paper: http://arxiv.org/abs/1504.01777.
%
% Please cite the Manopt paper as well as the research paper:
%     @Techreport{sun2014multinomial,
%       Title   = {Heterogeneous tensor decomposition for clustering via manifold optimization},
%       Author  = {Sun, Y. and Gao, J. and Hong, X. and Mishra, B. and Yin, B.},
%       Journal = {Arxiv preprint arXiv:1504.01777},
%       Year    = {2014}
%     }

% This file is part of Manopt: www.manopt.org.
% Original author: Bamdev Mishra, April 06, 2015.
% Contributors:
% Change log:

    M.name = @() sprintf('%dx%d column-stochastic matrices with positive entries', n, m);

    M.dim = @() (n-1)*m;

    % We impose the Fisher metric.
    M.inner = @iproduct;
    function ip = iproduct(X, eta, zeta)
        ip = sum((eta(:).*zeta(:))./X(:));
    end

    M.norm = @(X, eta) sqrt(M.inner(X, eta, eta));

    M.dist = @(X, Y) error('multinomialfactory.dist not implemented yet.');

    M.typicaldist = @() m*pi/2; % This is an approximation.

    % Column vector of ones of length n.
    e = ones(n, 1);

    M.egrad2rgrad = @egrad2rgrad;
    function rgrad = egrad2rgrad(X, egrad)
        lambda = -sum(X.*egrad, 1); % Row vector of length m.
        rgrad = X.*egrad + (e*lambda).*X; % This is in the tangent space.
    end

    M.ehess2rhess = @ehess2rhess;
    function rhess = ehess2rhess(X, egrad, ehess, eta)

        % Riemannian gradient computation.
        % lambda is a row vector of length m.
        lambda = - sum(X.*egrad, 1);
        rgrad =  X.*egrad + (e*lambda).*X;

        % Directional derivative of the Riemannian gradient.
        % lambdadot is a row vector of length m.
        lambdadot = -sum(eta.*egrad, 1) - sum(X.*ehess, 1);
        rgraddot = eta.*egrad + X.*ehess + (e*lambdadot).*X + (e*lambda).*eta;

        % Correction term because of the non-constant metric that we
        % impose. The computation of the correction term follows the use of
        % Koszul formula.
        correction_term = - 0.5*(eta.*rgrad)./X;
        rhess = rgraddot + correction_term;

        % Finally, projection onto the tangent space.
        rhess = M.proj(X, rhess);
    end

    % Projection of the vector eta in the ambeint space onto the tangent
    % space.
    M.proj = @projection;
    function etaproj = projection(X, eta)
        alpha = sum(eta, 1); % Row vector of length m.
        etaproj = eta - (e*alpha).*X;
    end

    M.tangent = M.proj;
    M.tangent2ambient = @(X, eta) eta;

    M.retr = @retraction;
    function Y = retraction(X, eta, t)
        if nargin < 3
            t = 1.0;
        end
        % A first-order retraction.
        Y = X.*exp(t*(eta./X)); % Based on mapping for positive scalars.
        Y = Y./(e*(sum(Y, 1))); % Projection onto the constraint set.
        % For numerical reasons, so that we avoid entries going to zero:
        Y = max(Y, eps);
    end

    M.exp = @exponential;
    function Y = exponential(X, eta, t)
        if nargin < 3
            t = 1.0;
        end
        Y = retraction(X, eta, t);
        warning('manopt:multinomialfactory:exp', ...
            ['Exponential for the Multinomial manifold' ...
            'manifold not implemented yet. Used retraction instead.']);
    end

    M.hash = @(X) ['z' hashmd5(X(:))];

    M.rand = @random;
    function X = random()
        % A random point in the ambient space.
        X = rand(n, m); %
        X = X./(e*(sum(X, 1)));
    end

    M.randvec = @randomvec;
    function eta = randomvec(X)
        % A random vector in the tangent space
        eta = randn(n, m);
        eta = M.proj(X, eta); % Projection onto the tangent space.
        nrm = M.norm(X, eta);
        eta = eta / nrm;
    end

    M.lincomb = @matrixlincomb;

    M.zerovec = @(X) zeros(n, m);

    M.transp = @(X1, X2, d) projection(X2, d);

    % vec and mat are not isometries, because of the scaled metric.
    M.vec = @(X, U) U(:);
    M.mat = @(X, u) reshape(u, n, m);
    M.vecmatareisometries = @() false;
end


function [output_signal,output_time] = mvstat(Inputdata_signal,Inputdata_time,windowrange,reductionrange,fn)
%------------ Introduction ----------------------
%This file is created to calculate the mathematical operation like 'max'
%on a pre-defined window range and with a pre-defined reduction range of an vector data.
%This function will need the following inputs in order to calculate the
%wished results:
%   1- Inputdata_signal: A vector containg your Y-Values that need to be
%   filtered.
%   2- Inputdata_time: A vector containg your x-Values that need to be
%   filtered (Normally is a time signal where the sampling rate can be
%   extracted).
%   3- windowrange: in unit of time (s) is the range to calculate the needed
%   mathematical function (The moving range ex. mvmean(y,x,0.02,0.02) or mvrms(y,x,0.02,0.02))
%   4- reductionrange: in unit of time (s) is the scalling reference for
%   the new data
%   5- fn : is used to define the wished mathmatical operation (ex. @max, @min, @mean, @rms, @int)
%The relation between the windowrange input and the reductionrange input
%must be an integer value of 1:1.2:1..10:1. If not the reductionrange would
%be corrected to get one of those relation. this specification give us the
%possibility to calculate the 'mvstat_final' without using a for-Loop which will save a whole amount of time
% for example:
% fn = @mean
% [output_signal,out_put_time] = mvstat_final (y,x,10,10)
% the moving average will be calculated as a result of this function. every
% 10 s the mean value for the last 10 s will be calculated.
% fn = @max
% [output_signal,out_put_time] = mvstat_final (y,x,20,10)
% the moving max will be calculated as a result of this function. every
% 10 s the maximum value for the last 20 s will be calculated.
% fn = @min
% [output_signal,out_put_time] = mvstat_final (y,x,5,10)
% the moving min will be calculated as a result of this function. every
% 10 s the minmum value for the last 5 s will be calculated.
%Notice: when the input values of windowrange and reductionrange are not
%the same then at the beginning of the calculation the fn value of the a
%available data will be calculated.
% Is m.file will also allows you to calculate the intgration of your input
% data in a spesific windowrange. in this case the reductionrange input
% should be defined as in the example:
%fn = @int;
%[Ua_sin,Ua_sin_time] = mvstat(Ua_sin,U1_time,(1/f_grid),delta_t,fn); Ua_sin = Ua_sin*2*f_grid;
% in this example the integration of your input data (in this case U1_sin)
% will be calculated ever one period (normally this mean 0.02 s or 1/50 or
% 1/f_grid in our case). and then the reductionrange is in this case equal
% to the sampling time of the inputdata (delta = U1_time(2)-U1_time(1)).
% this work was done in order to bring FAMOS (IMC) software function into
% matlab.
%Auther: Msc.Eng. Aubai Alkhatib
%Datum: 10.09.2013
%-------- End of introduction ------------------
delta = Inputdata_time(2)-Inputdata_time(1);
length_window = windowrange/delta;
length_reduction = reductionrange/delta;
time = Inputdata_time(end);
if windowrange > reductionrange
    number = windowrange/reductionrange;
    integer = floor(number);
    fract = number-integer;
    if fract >= 0.5
        A = windowrange/(integer+1);
    else
        A = windowrange/(integer);
    end
    reductionrange_new = A;
    integer_A = floor(A);
    fract_A = A-integer_A;
    [~,b] = rat(A);
    if b > 1
        length_reduction_new = round(reductionrange_new/delta);
    else
        length_reduction_new = reductionrange_new/delta;
    end
    i = length_reduction_new;
    ii = 1;
    output = zeros();
    while i < length(Inputdata_signal)
        if i >= length_window
            if fract_A == 0
                switch func2str(fn)
                    case 'mean'
                        output(ii) = mean(Inputdata_signal((i-length_window)+1:i));
                    case 'max'
                        output(ii) = max(Inputdata_signal((i-length_window)+1:i));
                    case 'sum'
                        output(ii) = sum(Inputdata_signal((i-length_window)+1:i));
                    case 'min'
                        output(ii) = min(Inputdata_signal((i-length_window)+1:i));
                    case 'int'
                        output(ii) = sum(Inputdata_signal((i-length_window)+1:i))*reductionrange_new;
                    otherwise
                        output(ii) = rms(Inputdata_signal((i-length_window)+1:i));
                end
            else
                switch func2str(fn)
                    case 'mean'
                        output(ii) = mean(Inputdata_signal((i-length_window):i));
                    case 'max'
                        output(ii) = max(Inputdata_signal((i-length_window):i));
                    case 'sum'
                        output(ii) = sum(Inputdata_signal((i-length_window):i));
                    case 'min'
                        output(ii) = min(Inputdata_signal((i-length_window):i));
                    case 'int'
                        output(ii) = sum(Inputdata_signal((i-length_window)+1:i))*reductionrange_new;
                    otherwise
                        output(ii) = rms(Inputdata_signal((i-length_window):i));
                end
            end
        else
            switch func2str(fn)
                case 'mean'
                    output(ii) = mean(Inputdata_signal(1:i));
                case 'max'
                    output(ii) = max(Inputdata_signal(1:i));
                case 'sum'
                    output(ii) = sum(Inputdata_signal(1:i));
                case 'int'
                    output(ii) = sum(Inputdata_signal(1:i))*reductionrange_new;
                case 'min'
                    output(ii) = min(Inputdata_signal(1:i));
                otherwise
                    output(ii) = rms(Inputdata_signal(1:i));
            end
        end
        i = i + length_reduction_new;
        ii = ii + 1;
    end

    if strcmp(func2str(fn),'int')
        output_signal = output(length_window:length(output));
        output_time = windowrange:reductionrange_new:(length(output)*reductionrange_new);
    elseif isinteger(reductionrange_new)
        output_signal = output;
        output_time = 0:reductionrange_new:(length(output)*reductionrange_new)-reductionrange_new;
    else
        output_signal = output;
        output_time = 0:(length_reduction_new*delta):(length(output)*(length_reduction_new*delta))-(length_reduction_new*delta);
    end
elseif reductionrange > windowrange
    Length_Output = fix(time/windowrange);
    Length_Input_New = Length_Output*windowrange/delta;
    delta_new = length_window;
    delta_time = windowrange;
    Input_reshaped = reshape(Inputdata_signal(1:Length_Input_New),delta_new,Length_Input_New/delta_new);
    switch func2str(fn)
        case 'mean'
            output_signal = mean(Input_reshaped);
        case 'max'
            output_signal = max(Input_reshaped);
        case 'sum'
            output_signal = sum(Input_reshaped);
        case 'int'
            output = sum(Input_reshaped)*delta_time;
        case 'min'
            output_signal = min(Input_reshaped);
        otherwise
            output_signal = rms(Input_reshaped);
    end
    if strcmp(func2str(fn),'int')
        output_signal = output(length_window:length(output));
        output_time = windowrange:delta_time:(Length_Output*delta_time)-delta_time;
    else
        output_time = 0:delta_time:(Length_Output*delta_time)-delta_time;
    end
elseif windowrange == reductionrange
    Length_Output = fix(time/windowrange);
    Length_Input_New = Length_Output*reductionrange/delta;
    delta_new = length_reduction;
    delta_time = windowrange;
    Input_reshaped = reshape(Inputdata_signal(1:Length_Input_New),delta_new,Length_Input_New/delta_new);
    switch func2str(fn)
        case 'mean'
            output_signal = mean(Input_reshaped);
        case 'max'
            output_signal = max(Input_reshaped);
        case 'sum'
            output_signal = sum(Input_reshaped);
        case 'int'
            output = sum(Input_reshaped)*delta_time;
        case 'min'
            output_signal = min(Input_reshaped);
        otherwise
            output_signal = rms(Input_reshaped);
    end
    if strcmp(func2str(fn),'int')
        output_signal = output(length_window:length(output));
        output_time = windowrange:delta_time:(Length_Output*delta_time)-delta_time;
    else
        output_time = 0:delta_time:(Length_Output*delta_time)-delta_time;
    end
end
end


function [tfr,t,f] = tfrmhs(x,t,N,g,h,trace);
%TFRMHS	Margenau-Hill-Spectrogram time-frequency distribution.
%	[TFR,T,F]=TFRMHS(X,T,N,G,H,TRACE) computes the Margenau-Hill-Spectrogram
%	distribution of a discrete-time signal X, or the cross
%	Margenau-Hill-Spectrogram representation between two signals.
%
%	X     : Signal if auto-MHS, or [X1,X2] if cross-MHS.
%	T     : time instant(s)          (default : 1:length(X)).
%	N     : number of frequency bins (default : length(X)).
%	G,H   : analysis windows, normalized so that the representation
%               preserves the signal energy.
%	                (default : Hamming(N/10) and Hamming(N/4)).
%	TRACE : if nonzero, the progression of the algorithm is shown
%                                        (default : 0).
%	TFR   : time-frequency representation. When called without
%               output arguments, TFRMHS runs TFRQVIEW.
%	F     : vector of normalized frequencies.
%
%	Example:
%	 sig=fmlin(128,0.1,0.4); g=tftb_window(21,'Kaiser');
%	 h=tftb_window(63,'Kaiser'); tfrmhs(sig,1:128,64,g,h,1);
%
%	See also all the time-frequency representations listed in
%	 the file CONTENTS (TFR*)

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

if (nargin == 0),
 error('At least 1 parameter required');
end;
[xrow,xcol] = size(x);
if (xcol==0)|(xcol>2),
 error('X must have one or two columns');
end

if (nargin <= 2),
 N=xrow;
elseif (N<0),
 error('N must be greater than zero');
elseif (2^nextpow2(N)~=N),
 fprintf('For a faster computation, N should be a power of two\n');
end;

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

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

[trow,tcol] = size(t);
if (trow~=1),
 error('T must only have one row');
end;

[grow,gcol]=size(g); Lg=(grow-1)/2;
if (gcol~=1)|(rem(grow,2)==0),
 error('G must be a smoothing window with odd length');
end;

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

Lgh=min(Lg,Lh); points=-Lgh:Lgh;
Kgh=sum(h(Lh+1+points).*conj(g(Lg+1+points))); h=h/Kgh;

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

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


function vu = burgers_solution ( nu, vxn, vx, vtn, vt )

%*****************************************************************************80
%
%% BURGERS_SOLUTION evaluates a solution to the Burgers equation.
%
%  Discussion:
%
%    The form of the Burgers equation considered here is
%
%      du       du        d^2 u
%      -- + u * -- = nu * -----
%      dt       dx        dx^2
%
%    for -1.0 < x < +1.0, and 0 < t.
%
%    Initial conditions are u(x,0) = - sin(pi*x).  Boundary conditions
%    are u(-1,t) = u(+1,t) = 0.  The viscosity parameter nu is taken
%    to be 0.01 / pi, although this is not essential.
%
%    The authors note an integral representation for the solution u(x,t),
%    and present a better version of the formula that is amenable to
%    approximation using Hermite quadrature.
%
%    This program library does little more than evaluate the exact solution
%    at a user-specified set of points, using the quadrature rule.
%    Internally, the order of this quadrature rule is set to 8, but the
%    user can easily modify this value if greater accuracy is desired.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 November 2011
%
%  Author:
%
%    John Burkardt.
%
%  Reference:
%
%    Claude Basdevant, Michel Deville, Pierre Haldenwang, J Lacroix,
%    J Ouazzani, Roger Peyret, Paolo Orlandi, Anthony Patera,
%    Spectral and finite difference solutions of the Burgers equation,
%    Computers and Fluids,
%    Volume 14, Number 1, 1986, pages 23-41.
%
%  Parameters:
%
%    Input, real NU, the viscoscity.
%
%    Input, integer VXN, the number of spatial grid points.
%
%    Input, real VX(VXN), the spatial grid points.
%
%    Input, integer VTN, the number of time grid points.
%
%    Input, real VT(VTN), the time grid points.
%
%    Output, real VU(VXN,VTN), the solution of the Burgers
%    equation at each space and time grid point.
%
  qn = 8;
%
%  Compute the rule.
%
  [ qx, qw ] = hermite_ek_compute ( qn );
%
%  Evaluate U(X,T) for later times.
%
  vu = zeros ( vxn, vtn );

  for vti = 1 : vtn

    if ( vt(vti) == 0.0 )

      vu(1:vxn,vti) = - sin ( pi * vx(1:vxn) );

    else

      for vxi = 1 : vxn

        top = 0.0;
        bot = 0.0;

        for qi = 1 : qn

          c = 2.0 * sqrt ( nu * vt(vti) );

          top = top - qw(qi) * c * sin ( pi * ( vx(vxi) - c * qx(qi) ) ) ...
            * exp ( - cos ( pi * ( vx(vxi) - c * qx(qi)  ) ) ...
            / ( 2.0 * pi * nu ) );

          bot = bot + qw(qi) * c ...
            * exp ( - cos ( pi * ( vx(vxi) - c * qx(qi)  ) ) ...
            / ( 2.0 * pi * nu ) );

          vu(vxi,vti) = top / bot;

        end

      end

    end

  end

  return
end


function [out] = smoothThreshold_temperature_logistic(T,Tt,r)
%smoothThreshold_temperature_logistic Logisitic smoother for temperature threshold functions.

% Copyright (C) 2018 Wouter J.M. Knoben
% This file is part of the Modular Assessment of Rainfall-Runoff Models
% Toolbox (MARRMoT).
% MARRMoT is a free software (GNU GPL v3) and distributed WITHOUT ANY
% WARRANTY. See <https://www.gnu.org/licenses/> for details.

%   Smooths the transition of threshold functions of the form:
%
%   Snowfall = { P, if T <  Tt
%              { 0, if T >= Tt
%
%   By transforming the equation above to Sf = f(P,T,Tt,r):
%   Sf = P * 1/ (1+exp((T-Tt)/r))
%
%   Inputs:
%   P       : current precipitation
%   T       : current temperature
%   Tt      : threshold temperature below which snowfall occurs
%   r       : [optional] smoothing parameter rho, default = 0.01
%
%   NOTE: this function only outputs the multiplier. This needs to be
%   applied to the proper flux utside of this function.

% Check for inputs and use defaults if not provided
% NOTE: this is not very elegant, but it is more than a factor 10 faster then:
% if ~exist('r','var'); r = 0.01; end
if nargin == 2
    r = 0.01;
end

% Calculate multiplier
out = 1 ./ (1+exp((T-Tt)/(r)));

end


function beta = linearCompressibility(S,x)
% computes the linear compressibility of an elasticity tensor
%
% Description
%
% $$\beta(x) = S_{ijkk} x_i x_j$$
%
% Input
%  S - elastic @complianceTensor
%  x - list of @vector3d
%
% Output
%  beta - linear compressibility in directions v
%

% return a function if required
if nargin == 1 || isempty(x)
  beta = S2FunHarmonicSym.quadrature(@(x) linearCompressibility(S,x),'bandwidth',2,S.CS);
  return
end

% compute tensor product
beta = EinsteinSum(S,[-1 -2 -3 -3],x,-1,x,-2);


function x = from_array(A,opt)
    %FROM_ARRAY Approximate full array by TTeMPS tensor of prescribed rank
    %   or within a prescribed tolerance.
    %
    %   X = TTeMPS.from_array( A, tol ) approximates the given array A by a
    %       TTeMPS tensor such that the the error is in the order of tol.
    %
    %   X = TTeMPS.from_array( A, r ), with r a vector of length (ndims(A))+1),
    %       approximates the given array A by a rank-r TTeMPS tensor, such that
    %       X.rank = r.
    %

    %   TTeMPS Toolbox.
    %   Michael Steinlechner, 2013-2016
    %   Questions and contact: michael.steinlechner@epfl.ch
    %   BSD 2-clause license, see LICENSE.txt

    n = size(A);
    d = length(n);

    if length(opt) == 1
        useTol = true;
        tol = opt;
        r = ones(1,d+1);
    else
        useTol = false;
        r = opt;
        if r(1) ~= 1 || r(d+1) ~= 1
            error('Invalid rank specified')
        end
    end

    U = cell(1,d);

    % process from left to right
    % first core
    A = reshape( A, n(1), prod(n(2:end)));
    [u,s,v] = svd(A,'econ');
    if useTol
        r(2) = trunc_singular( diag(s), tol );
    end
    U{1} = reshape( u(:,1:r(2)), [1, n(1), r(2)] );
    A = s(1:r(2),1:r(2))*v(:,1:r(2))';

    % middle cores
    for i = 2:d-1
        A = reshape( A, n(i)*r(i), prod(n(i+1:end)));
        [u,s,v] = svd(A,'econ');
        if useTol
            r(i+1) = trunc_singular( diag(s), tol );
        end
        U{i} = reshape( u(:,1:r(i+1)), [r(i), n(i), r(i+1)] );
        A = s(1:r(i+1),1:r(i+1)) * v(:,1:r(i+1))';
    end

    %last core
    U{d} = reshape(A, [r(d), n(d), 1]);

    x = TTeMPS( U );
end


function circle_segment_test05 ( )

%*****************************************************************************80
%
%% CIRCLE_SEGMENT_TEST05 tests the AREA and HEIGHT_FROM_AREA functions.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 May 2013
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'CIRCLE_SEGMENT_TEST05\n' );
  fprintf ( 1, '  For circle segment with a given radius R,\n' );
  fprintf ( 1, '  CIRCLE_SEGMENT_AREA_FROM_HEIGHT computes the area A, given the height.\n' );
  fprintf ( 1, '  CIRCLE_SEGMENT_HEIGHT_FROM_AREA computes height H, given the area.\n' );
  fprintf ( 1, '  Check that these functions are inverses of each other\n' );
  fprintf ( 1, '  using random values of R, A, and H.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '        R             H      =>     A    =>       H2\n' );
  fprintf ( 1, '\n' );

  seed = 123456789;

  for test = 1 : 5
    [ r, seed ] = r8_uniform_01 ( seed );
    r = 5.0 * r;
    [ h, seed ] = r8_uniform_01 ( seed );
    h = 2.0 * r * h;
    a = circle_segment_area_from_height ( r, h );
    h2 = circle_segment_height_from_area ( r, a );
    fprintf ( 1, '  %12f  %12f  %12f  %12f\n', r, h, a, h2 );
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, '        R             A      =>     H    =>       A2\n' );
  fprintf ( 1, '\n' );
  for test = 1 : 5
    [ r, seed ] = r8_uniform_01 ( seed );
    r = 5.0 * r;
    [ a, seed ] = r8_uniform_01 ( seed );
    a = pi * r * r * a;
    h = circle_segment_height_from_area ( r, a );
    a2 = circle_segment_area_from_height ( r, h );
    fprintf ( 1, '  %12f  %12f  %12f  %12f\n', r, a, h, a2 );
  end

  return
end


function [peakVals,isMax,peakIdx]=findMaxMinPoints(data)
%%FINDMAXMINPOINTS Given a grid of points in one or more dimensions, this
%                  function finds all maxima and minima. A maximum/minimum
%                  is declared if the point in question is higher/lower
%                  than all neighboring points (including those diagonally
%                  offset). Points at the edge of the matrix are not
%                  considered to be maxima or minima.
%
%INPUTS: data An n1Xn2X...Xnk dimensional matrix.  Singleton dimensions
%             (ni=1) are ignored. Non-singleton dimensions must be > 2. to
%             consider points that are not on the edge. data must be a real
%             matrix.
%
%OUTPUTS: peakVals A numValsX1 vector of the maximum and minimum values
%                  found. If no values are found, this is an empty matrix.
%            isMax A numValsX1 vector indicating whether each value in
%                  peakVals is a maximum or a minimum. 1 indicates maximum,
%                  0 indicated minimum.
%          peakIdx A numValsX1 vector of indices of the peaks such that
%                  data(peakIdx(i)) provides the ith peak value.
%
%EXAMPLE:
%This function is useful for finding maxima and minima of cost functions.
%Here, we find all maxima and minima of a surface.
% numPoints=100;
% pts=linspace(0,2*pi,numPoints);
% [X,Y]=meshgrid(pts,pts);
% Z=sin(2*X+3*Y)+cos(X-2*Y);
% %Display the surface whose peaks are desired.
% figure(1)
% clf
% surface(X,Y,Z,'EdgeColor','None')
% [peakVals,isMax,peakIdx]=findMaxMinPoints(Z)
%One sees that all 13 of the maxma and minima (-1 and 1)  that are found.
%Values on the edge are not counted for maxma or minima.
%
%October 2016 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

dims=size(data);

%Get rid of singleton dimensions.
dims=dims(dims~=1);
if(isempty(dims)||isscalar(dims)&&dims==1||any(dims==2))
   peakVals=[];
   peakIdx=[];
   isMax=[];
   return;
end

numDims=length(dims);
switch(numDims)
    case 1%Find peaks for linear values.
        peakVals=[];
        peakIdx=[];
        isMax=[];
        for idx1=2:(dims(1)-1)
            curVal=data(idx1);

            vals=[curVal-data(idx1-1);
                  curVal-data(idx1+1)];
            if(all(vals>0))
                peakVals=[peakVals;curVal];
                peakIdx=[peakIdx;idx1];
                isMax=[isMax;1];
            elseif(all(vals<0))
                peakVals=[peakVals;curVal];
                peakIdx=[peakIdx;idx1];
                isMax=[isMax;0];
            end
        end
    case 2
        data=reshape(data,dims(1),dims(2));

        peakVals=[];
        peakIdx=[];
        isMax=[];

        for idx1=2:(dims(1)-1)
            for idx2=2:(dims(2)-1)
                curVal=data(idx1,idx2);

                vals=[curVal-data(idx1,idx2-1);
                      curVal-data(idx1-1,idx2-1);
                      curVal-data(idx1+1,idx2-1);
                      curVal-data(idx1,idx2+1);
                      curVal-data(idx1-1,idx2+1);
                      curVal-data(idx1+1,idx2+1);
                      curVal-data(idx1-1,idx2);
                      curVal-data(idx1+1,idx2)];

                %If we have found a maximum or a minimum
                if(all(vals>0))
                    peakVals=[peakVals;curVal];
                    idx=sub2ind(dims,idx1,idx2);
                    peakIdx=[peakIdx;idx];
                    isMax=[isMax;1];
                elseif(all(vals<0))
                    peakVals=[peakVals;curVal];
                    idx=sub2ind(dims,idx1,idx2);
                    peakIdx=[peakIdx;idx];
                    isMax=[isMax;0];
                end
            end
        end
    otherwise%3 or more dimensions
        maxTupleVals=dims-3;

        peakVals=[];
        peakIdx=[];
        isMax=[];

        idxList=getNextTuple(numDims);
        while(~isempty(idxList))
            %Points that will be compared to their neighbors are never the
            %edge points. Thus, the minimum value possible for an element
            %is 2 and the maximum value is one less than the number of
            %things in that dimension.
            shiftIdxList=idxList+2;

            curIdx=nDim2Index(dims,shiftIdxList);
            curVal=data(curIdx);

            %Now, we look at all neighbors of the current point. This means
            %that all points go through all combinations of +1,-1, and 0,
            %except for the all zero case. We can get the values using
            %tuples.
            maxSignVals=2*ones(numDims,1);

            signList=getNextTuple(zeros(numDims,1),maxSignVals);

            isMax=true;
            isMin=true;
            while(~isempty(signList)&&(isMax==true||isMin==true))
                temp=signList;
                temp(temp==2)=-1;

                shiftedIdx=nDim2Index(dims,shiftIdxList+temp);
                compVal=data(shiftedIdx);

                if(compVal>=curVal)
                   isMax=false;
                end

                if(compVal<=curVal)
                   isMin=false;
                end

                signList=getNextTuple(signList,maxSignVals);
            end

            if(~(isMax&&isMin))
                if(isMax)
                    peakVals=[peakVals;curVal];
                    peakIdx=[peakIdx;curIdx];
                    isMax=[isMax;1];
                elseif(isMin)
                    peakVals=[peakVals;curVal];
                    peakIdx=[peakIdx;curIdx];
                    isMax=[isMax;0];
                end
            end

            idxList=getNextTuple(idxList,maxTupleVals);
        end
end
end

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


function adj = triangulation_order3_adj_set ( node_num, ...
  tri_num, triangle_node, triangle_neighbor, adj_num, adj_col )

%*****************************************************************************80
%
%% TRIANGULATION_ORDER3_ADJ_SET sets adjacencies in a triangulation.
%
%  Discussion:
%
%    This routine is called to count the adjacencies, so that the
%    appropriate amount of memory can be set aside for storage when
%    the adjacency structure is created.
%
%    The triangulation is assumed to involve 3-node triangles.
%
%    Two nodes are "adjacent" if they are both nodes in some triangle.
%    Also, a node is considered to be adjacent to itself.
%
%    This routine can be used to create the compressed column storage
%    for a linear triangle finite element discretization of
%    Poisson's equation in two dimensions.
%
%  Diagram:
%
%       3
%    s  |\
%    i  | \
%    d  |  \
%    e  |   \  side 2
%       |    \
%    3  |     \
%       |      \
%       1-------2
%
%         side 1
%
%    The local node numbering
%
%
%   21-22-23-24-25
%    |\ |\ |\ |\ |
%    | \| \| \| \|
%   16-17-18-19-20
%    |\ |\ |\ |\ |
%    | \| \| \| \|
%   11-12-13-14-15
%    |\ |\ |\ |\ |
%    | \| \| \| \|
%    6--7--8--9-10
%    |\ |\ |\ |\ |
%    | \| \| \| \|
%    1--2--3--4--5
%
%    A sample grid
%
%
%    Below, we have a chart that summarizes the adjacency relationships
%    in the sample grid.  On the left, we list the node, and its neighbors,
%    with an asterisk to indicate the adjacency of the node to itself
%    (in some cases, you want to count this self adjacency and in some
%    you don't).  On the right, we list the number of adjancencies to
%    lower-indexed nodes, to the node itself, to higher-indexed nodes,
%    the total number of adjacencies for this node, and the location
%    of the first and last entries required to list this set of adjacencies
%    in a single list of all the adjacencies.
%
%    N   Adjacencies                Below  Self    Above  Total First  Last
%
%   --  -- -- -- -- -- -- --           --    --      --      --   ---     0
%    1:  *  2  6                        0     1       2       3     1     3
%    2:  1  *  3  6  7                  1     1       3       5     4     8
%    3:  2  *  4  7  8                  1     1       3       5     9    13
%    4:  3  *  5  8  9                  1     1       3       5    14    18
%    5:  4  *  9 10                     1     1       2       4    19    22
%    6:  1  2  *  7 11                  2     1       2       5    23    27
%    7:  2  3  6  *  8 11 12            3     1       3       7    28    34
%    8:  3  4  7  *  9 12 13            3     1       3       7    35    41
%    9:  4  5  8  * 10 13 14            3     1       3       7    42    48
%   10:  5  9  * 14 15                  2     1       2       5    49    53
%   11:  6  7  * 12 16                  2     1       2       5    54    58
%   12:  7  8 11  * 13 16 17            3     1       3       7    59    65
%   13:  8  9 12  * 14 17 18            3     1       3       7    66    72
%   14:  9 10 13  * 15 18 19            3     1       3       7    73    79
%   15: 10 14  * 19 20                  2     1       2       5    80    84
%   16: 11 12  * 17 21                  2     1       2       5    85    89
%   17: 12 13 16  * 18 21 22            3     1       3       7    90    96
%   18: 13 14 17  * 19 22 23            3     1       3       7    97   103
%   19: 14 15 18  * 20 23 24            3     1       3       7   104   110
%   20: 15 19  * 24 25                  2     1       2       5   111   115
%   21: 16 17  * 22                     2     1       1       4   116   119
%   22: 17 18 21  * 23                  3     1       1       5   120   124
%   23: 18 19 22  * 24                  3     1       1       5   125   129
%   24: 19 20 23  * 25                  3     1       1       5   130   134
%   25: 20 24  *                        2     1       0       3   135   137
%   --  -- -- -- -- -- -- --           --    --      --      --   138   ---
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 September 2006
%
%  Author:
%
%    John Burkardt
%
%  Parameters
%
%    Input, integer NODE_NUM, the number of nodes.
%
%    Input, integer TRI_NUM, the number of triangles.
%
%    Input, integer TRIANGLE_NODE(3,TRI_NUM), lists the nodes that
%    make up each triangle in counterclockwise order.
%
%    Input, integer TRIANGLE_NEIGHBOR(3,TRI_NUM), for each side of
%    a triangle, lists the neighboring triangle, or -1 if there is
%    no neighbor.
%
%    Input, integer ADJ_NUM, the number of adjacencies.
%
%    Input, integer ADJ_COL(NODE_NUM+1).  Information about column J is stored
%    in entries ADJ_COL(J) through ADJ_COL(J+1)-1 of ADJ.
%
%    Output, integer ADJ(ADJ_NUM), the adjacency information.
%
  triangle_order = 3;
  adj(1:adj_num) = -1;
  adj_copy(1:node_num) = adj_col(1:node_num);
%
%  Set every node to be adjacent to itself.
%
  for node = 1 : node_num
    adj(adj_copy(node)) = node;
    adj_copy(node) = adj_copy(node) + 1;
  end
%
%  Examine each triangle.
%
  for triangle = 1 : tri_num

    n1 = triangle_node(1,triangle);
    n2 = triangle_node(2,triangle);
    n3 = triangle_node(3,triangle);
%
%  Add edge (1,2) if this is the first occurrence,
%  that is, if the edge (1,2) is on a boundary (TRIANGLE2 <= 0)
%  or if this triangle is the first of the pair in which the edge
%  occurs (TRIANGLE < TRIANGLE2).
%
    triangle2 = triangle_neighbor(1,triangle);

    if ( triangle2 < 0 | triangle < triangle2 )
      adj(adj_copy(n1)) = n2;
      adj_copy(n1) = adj_copy(n1) + 1;
      adj(adj_copy(n2)) = n1;
      adj_copy(n2) = adj_copy(n2) + 1;
    end
%
%  Add edge (2,3).
%
    triangle2 = triangle_neighbor(2,triangle);

    if ( triangle2 < 0 | triangle < triangle2 )
      adj(adj_copy(n2)) = n3;
      adj_copy(n2) = adj_copy(n2) + 1;
      adj(adj_copy(n3)) = n2;
      adj_copy(n3) = adj_copy(n3) + 1;
    end
%
%  Add edge (3,1).
%
    triangle2 = triangle_neighbor(3,triangle);

    if ( triangle2 < 0 | triangle < triangle2 )
      adj(adj_copy(n1)) = n3;
      adj_copy(n1) = adj_copy(n1) + 1;
      adj(adj_copy(n3)) = n1;
      adj_copy(n3) = adj_copy(n3) + 1;
    end

  end
%
%  Ascending sort the entries for each node.
%
  for node = 1 : node_num
    k1 = adj_col(node);
    k2 = adj_col(node+1)-1;
    adj(k1:k2) = i4vec_sort_heap_a ( k2+1-k1, adj(k1:k2) );
  end

  return
end


function v2 = r8vec_any_normal ( dim_num, v1 )

%*****************************************************************************80
%
%% R8VEC_ANY_NORMAL returns some normal vector to V1.
%
%  Discussion:
%
%    If DIM_NUM < 2, then no normal vector can be returned.
%
%    If V1 is the zero vector, then any unit vector will do.
%
%    No doubt, there are better, more robust algorithms.  But I will take
%    just about ANY reasonable unit vector that is normal to V1.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 August 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the spatial dimension.
%
%    Input, real V1(DIM_NUM), the vector.
%
%    Output, real V2(DIM_NUM), a vector that is
%    normal to V2, and has unit Euclidean length.
%
  if ( dim_num < 2 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'R8VEC_ANY_NORMAL - Fatal error!\n' );
    fprintf ( 1, '  Called with DIM_NUM < 2.\n' );
    error ( 'R8VEC_ANY_NORMAL - Fatal error!' );
  end

  if ( r8vec_norm ( dim_num, v1 ) == 0.0 )
    v2(1) = 1.0;
    v2(2:dim_num) = 0.0;
    return
  end
%
%  Seek the largest entry in V1, VJ = V1(J), and the
%  second largest, VK = V1(K).
%
%  Since V1 does not have zero norm, we are guaranteed that
%  VJ, at least, is not zero.
%
  j = -1;
  vj = 0.0;

  k = -1;
  vk = 0.0;

  for i = 1 : dim_num

    if ( abs ( vk ) < abs ( v1(i) ) || k < 1 )

      if ( abs ( vj ) < abs ( v1(i) ) || j < 1 )
        k = j;
        vk = vj;
        j = i;
        vj = v1(i);
      else
        k = i;
        vk = v1(i);
      end

    end

  end
%
%  Setting V2 to zero, except that V2(J) = -VK, and V2(K) = VJ,
%  will just about do the trick.
%
  v2(1:dim_num) = 0.0;

  v2(j) = -vk / sqrt ( vk * vk + vj * vj );
  v2(k) =  vj / sqrt ( vk * vk + vj * vj );

  return
end


function [pmiss,pfa] = rocch(tar_scores,nontar_scores)
% ROCCH: ROC Convex Hull.
% Usage: [pmiss,pfa] = rocch(tar_scores,nontar_scores)
% (This function has the same interface as compute_roc.)
%
% Note: pmiss and pfa contain the coordinates of the vertices of the
%       ROC Convex Hull.
%
% For a demonstration that plots ROCCH against ROC for a few cases, just
% type 'rocch' at the MATLAB command line.
%
% Inputs:
%   tar_scores: scores for target trials
%   nontar_scores: scores for non-target trials

if nargin==0
    test_this();
    return
end

assert(nargin==2)
assert(isvector(tar_scores))
assert(isvector(nontar_scores))

Nt = length(tar_scores);
Nn = length(nontar_scores);
N = Nt+Nn;
scores = [tar_scores(:)',nontar_scores(:)'];
Pideal = [ones(1,Nt),zeros(1,Nn)];  %ideal, but non-monotonic posterior

%It is important here that scores that are the same (i.e. already in order) should NOT be swapped.
%MATLAB's sort algorithm has this property.
[scores,perturb] = sort(scores);

Pideal = Pideal(perturb);
[Popt,width] = pavx(Pideal);

nbins = length(width);
pmiss = zeros(1,nbins+1);
pfa = zeros(1,nbins+1);

%threshold leftmost: accept eveything, miss nothing
left = 0; %0 scores to left of threshold
fa = Nn;
miss = 0;

for i=1:nbins
    pmiss(i) = miss/Nt;
    pfa(i) = fa/Nn;
    left = left + width(i);
    miss = sum(Pideal(1:left));
    fa = N - left - sum(Pideal(left+1:end));
end
pmiss(nbins+1) = miss/Nt;
pfa(nbins+1) = fa/Nn;

end

function test_this()

figure();

subplot(2,3,1);
tar = [1]; non = [0];
[pmiss,pfa] = rocch(tar,non);
[pm,pf] = compute_roc(tar,non);
plot(pfa,pmiss,'r-^',pf,pm,'g--v');
axis('square');grid;legend('ROCCH','ROC');
title('2 scores: non < tar');

subplot(2,3,2);
tar = [0]; non = [1];
[pmiss,pfa] = rocch(tar,non);
[pm,pf] = compute_roc(tar,non);
plot(pfa,pmiss,'r-^',pf,pm,'g-v');
axis('square');grid;
title('2 scores: tar < non');

subplot(2,3,3);
tar = [0]; non = [-1,1];
[pmiss,pfa] = rocch(tar,non);
[pm,pf] = compute_roc(tar,non);
plot(pfa,pmiss,'r-^',pf,pm,'g--v');
axis('square');grid;
title('3 scores: non < tar < non');

subplot(2,3,4);
tar = [-1,1]; non = [0];
[pmiss,pfa] = rocch(tar,non);
[pm,pf] = compute_roc(tar,non);
plot(pfa,pmiss,'r-^',pf,pm,'g--v');
axis('square');grid;
title('3 scores: tar < non < tar');
xlabel('P_{fa}');
ylabel('P_{miss}');

subplot(2,3,5);
tar = randn(1,100)+1; non = randn(1,100);
[pmiss,pfa] = rocch(tar,non);
[pm,pf] = compute_roc(tar,non);
plot(pfa,pmiss,'r-^',pf,pm,'g');
axis('square');grid;
title('45^{\circ} DET');

subplot(2,3,6);
tar = randn(1,100)*2+1; non = randn(1,100);
[pmiss,pfa] = rocch(tar,non);
[pm,pf] = compute_roc(tar,non);
plot(pfa,pmiss,'r-^',pf,pm,'g');
axis('square');grid;
title('flatter DET');

end


function hu = imHuInvariants(img)
% Compute Hu's invariant for a 2D image.
%
%   HU = imHuInvariants(IMG)
%   HU is a row vector with 12 elements.
%
%   Example
%   imHuInvariants
%
%   See also
%
%   Current implementation is based on the paper:
%   "Noise tolerance of moment invariants in pattern recognition"
%   I. Baslev, Pattern Recognition Letters 19 (1998): 1183-1189
%

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

%% Compute image moments

% total mass of image
m00 = sum(img(:));

% center of mass (first order non-centered moment)
cx = imMoment(img, 1, 0)/m00;
cy = imMoment(img, 0, 1)/m00;

% second-order centered and scaled moments
m02 = imCSMoment(img, 0, 2, [cx cy], m00);
m11 = imCSMoment(img, 1, 1, [cx cy], m00);
m20 = imCSMoment(img, 2, 0, [cx cy], m00);

% third-order centered and scaled moments
m30 = imCSMoment(img, 3, 0, [cx cy], m00);
m21 = imCSMoment(img, 2, 1, [cx cy], m00);
m12 = imCSMoment(img, 1, 2, [cx cy], m00);
m03 = imCSMoment(img, 0, 3, [cx cy], m00);

% fourth-order centered and scaled moments
m40 = imCSMoment(img, 4, 0, [cx cy], m00);
m31 = imCSMoment(img, 3, 1, [cx cy], m00);
m22 = imCSMoment(img, 2, 2, [cx cy], m00);
m13 = imCSMoment(img, 1, 3, [cx cy], m00);
m04 = imCSMoment(img, 0, 4, [cx cy], m00);

%% computation shortcuts

% degree 2
a40 = m20 + m02;
a42 = m20 - m02;
b42 = 2*m11;

% degree 3
a51 = m30 + m12;
b51 = m21 + m03;
a53 = m30 - m12;
b53 = 3*m21 - m03;

% degree 4
a60 = m40 + 2*m22 + m04;
a62 = m40 - m04;
b62 = 2*(m31 + m13);
a64 = m40 - 6*m22 + m04;
b64 = 4*(m31 - m13);

%% Compute Hu's invariants

% init size
hu = zeros(1, 12);

% degree 2
hu(1)   = a40;
hu(2)   = a42^2 + b42^2;
hu(3)   = a42*(a51^2-b51^2) + 2*a51*b51*b42;

% degree 3
hu(4)   = a51^2 + b51^2;
hu(5)   = a53^2 + b53^2;
hu(6)   = a51*a53*(a51^2 - 3*b51^2) + b51*b53*(3*a51^2 - b51^2);
hu(7)   = a51*b53*(a51^2 - 3*b51^2) - b51*a53*(3*a51^2 - b51^2);

% degree 4
hu(8)   = a60;
hu(9)   = a62^2 + b62^2;
hu(10)  = a64^2 + b64^2;
hu(11)  = a64*(a62^2-b62^2) + 2*a62*b62*b64;
hu(12)  = b64*(a62^2-b62^2) - 2*a62*b62*b64;


%% (Internal) Mean/Median filtering
%
%   Output = MedianFilt(Input, WinSize, bRobust)
%
% Arguments:
%
%      + Input: the signal
%
%      + WinSize: The size of the window in samples
%
%      + bRobust: use mean (false) or median (true)
%
% Output:
%
%      + Output: filtered output
%
% Example:
%
%     WinSize = round(0.2*SamplingFreq);
%
%     %Baseline estimation.
%     BaselineEstimation = MedianFilt(noisyECG, WinSize );
%
%
% See also BaselineWanderRemovalMedian
%
% Author: Mariano Llamedo Soria llamedom@electron.frba.utn.edu.ar
% Version: 0.1 beta
% Last update: 14/5/2014
% Birthdate  : 21/4/2015
% Copyright 2008-2015
%
function Output = MedianFilt(Input, WinSize, bRobust)

if(nargin < 2 || isempty(WinSize) )
    WinSize = 31;
end

if(nargin < 3 || isempty(bRobust) )
    bRobust = true;
end

if(bRobust)
    mean_ptr_func = @nanmedian;
else
    mean_ptr_func = @nanmean;
end

MidPoint = ceil(WinSize/2);

aux_seq = 1:size(Input,1);
laux_seq = length(aux_seq);

each_sample_idx = arrayfun(@(a)(max(1,a):min(laux_seq,a + WinSize-1)), aux_seq - MidPoint+1, ...
                                                'UniformOutput', false);
Output = cellfun(@(a)(mean_ptr_func(Input(a,:),1)), colvec(each_sample_idx), 'UniformOutput', false);

Output = cell2mat(Output);

%old version
% startSample = MidPoint;
% endSample = size(Input,1) - fix(WinSize/2);
% Output = zeros(endSample-startSample+1, size(Input,2));
%
% iCount = 1;
%
% for iSampleIndex = startSample:endSample
%
%     startRange = iSampleIndex-MidPoint+1;
%     iRange = startRange:startRange+WinSize-1;
%
%     Output(iCount,:) = median( Input(iRange,:) );
%
%     iCount = iCount + 1;
%
% end


#!/usr/bin/env octave
%% Machine Learning Online Class
%  Exercise 7 | Principle Component Analysis and K-Means Clustering
%
%  Instructions
%  ------------
%
%  This file contains code that helps you get started on the
%  exercise. You will need to complete the following functions:
%
%     pca.m
%     projectData.m
%     recoverData.m
%     computeCentroids.m
%     findClosestCentroids.m
%     kMeansInitCentroids.m
%
%  For this exercise, you will not need to change any code in this file,
%  or any other files other than those mentioned above.
%

%% Initialization
clear ; close all; clc

%% ================== Part 1: Load Example Dataset  ===================
%  We start this exercise by using a small dataset that is easily to
%  visualize
%
fprintf('Visualizing example dataset for PCA.\n\n');

%  The following command loads the dataset. You should now have the
%  variable X in your environment
load ('ex7data1.mat');

%  Visualize the example dataset
plot(X(:, 1), X(:, 2), 'bo');
axis([0.5 6.5 2 8]); axis square;

fprintf('Program paused. Press enter to continue.\n');
pause;

%% =============== Part 2: Principal Component Analysis ===============
%  You should now implement PCA, a dimension reduction technique. You
%  should complete the code in pca.m
%
fprintf('\nRunning PCA on example dataset.\n\n');

%  Before running PCA, it is important to first normalize X
[X_norm, mu, sigma] = featureNormalize(X);

%  Run PCA
[U, S] = pca(X_norm);

%  Compute mu, the mean of the each feature

%  Draw the eigenvectors centered at mean of data. These lines show the
%  directions of maximum variations in the dataset.
hold on;
drawLine(mu, mu + 1.5 * S(1,1) * U(:,1)', '-k', 'LineWidth', 2);
drawLine(mu, mu + 1.5 * S(2,2) * U(:,2)', '-k', 'LineWidth', 2);
hold off;

fprintf('Top eigenvector: \n');
fprintf(' U(:,1) = %f %f \n', U(1,1), U(2,1));
fprintf('\n(you should expect to see -0.707107 -0.707107)\n');

fprintf('Program paused. Press enter to continue.\n');
pause;

%% =================== Part 3: Dimension Reduction ===================
%  You should now implement the projection step to map the data onto the
%  first k eigenvectors. The code will then plot the data in this reduced
%  dimensional space.  This will show you what the data looks like when
%  using only the corresponding eigenvectors to reconstruct it.
%
%  You should complete the code in projectData.m
%
fprintf('\nDimension reduction on example dataset.\n\n');

%  Plot the normalized dataset (returned from pca)
plot(X_norm(:, 1), X_norm(:, 2), 'bo');
axis([-4 3 -4 3]); axis square

%  Project the data onto K = 1 dimension
K = 1;
Z = projectData(X_norm, U, K);
fprintf('Projection of the first example: %f\n', Z(1));
fprintf('\n(this value should be about 1.481274)\n\n');

X_rec  = recoverData(Z, U, K);
fprintf('Approximation of the first example: %f %f\n', X_rec(1, 1), X_rec(1, 2));
fprintf('\n(this value should be about  -1.047419 -1.047419)\n\n');

%  Draw lines connecting the projected points to the original points
hold on;
plot(X_rec(:, 1), X_rec(:, 2), 'ro');
for i = 1:size(X_norm, 1)
    drawLine(X_norm(i,:), X_rec(i,:), '--k', 'LineWidth', 1);
end
hold off

fprintf('Program paused. Press enter to continue.\n');
pause;

%% =============== Part 4: Loading and Visualizing Face Data =============
%  We start the exercise by first loading and visualizing the dataset.
%  The following code will load the dataset into your environment
%
fprintf('\nLoading face dataset.\n\n');

%  Load Face dataset
load ('ex7faces.mat')

%  Display the first 100 faces in the dataset
displayData(X(1:100, :));

fprintf('Program paused. Press enter to continue.\n');
pause;

%% =========== Part 5: PCA on Face Data: Eigenfaces  ===================
%  Run PCA and visualize the eigenvectors which are in this case eigenfaces
%  We display the first 36 eigenfaces.
%
fprintf(['\nRunning PCA on face dataset.\n' ...
         '(this mght take a minute or two ...)\n\n']);

%  Before running PCA, it is important to first normalize X by subtracting
%  the mean value from each feature
[X_norm, mu, sigma] = featureNormalize(X);

%  Run PCA
[U, S] = pca(X_norm);

%  Visualize the top 36 eigenvectors found
displayData(U(:, 1:36)');

fprintf('Program paused. Press enter to continue.\n');
pause;

%% ============= Part 6: Dimension Reduction for Faces =================
%  Project images to the eigen space using the top k eigenvectors
%  If you are applying a machine learning algorithm
fprintf('\nDimension reduction for face dataset.\n\n');

K = 100;
Z = projectData(X_norm, U, K);

fprintf('The projected data Z has a size of: ')
fprintf('%d ', size(Z));

fprintf('\n\nProgram paused. Press enter to continue.\n');
pause;

%% ==== Part 7: Visualization of Faces after PCA Dimension Reduction ====
%  Project images to the eigen space using the top K eigen vectors and
%  visualize only using those K dimensions
%  Compare to the original input, which is also displayed

fprintf('\nVisualizing the projected (reduced dimension) faces.\n\n');

K = 100;
X_rec  = recoverData(Z, U, K);

% Display normalized data
subplot(1, 2, 1);
displayData(X_norm(1:100,:));
title('Original faces');
axis square;

% Display reconstructed data from only k eigenfaces
subplot(1, 2, 2);
displayData(X_rec(1:100,:));
title('Recovered faces');
axis square;

fprintf('Program paused. Press enter to continue.\n');
pause;

%% === Part 8(a): Optional (ungraded) Exercise: PCA for Visualization ===
%  One useful application of PCA is to use it to visualize high-dimensional
%  data. In the last K-Means exercise you ran K-Means on 3-dimensional
%  pixel colors of an image. We first visualize this output in 3D, and then
%  apply PCA to obtain a visualization in 2D.

close all; close all; clc

% Re-load the image from the previous exercise and run K-Means on it
% For this to work, you need to complete the K-Means assignment first
A = double(imread('bird_small.png'));

% If imread does not work for you, you can try instead
%   load ('bird_small.mat');

A = A / 255;
img_size = size(A);
X = reshape(A, img_size(1) * img_size(2), 3);
K = 16;
max_iters = 10;
initial_centroids = kMeansInitCentroids(X, K);
[centroids, idx] = runkMeans(X, initial_centroids, max_iters);

%  Sample 1000 random indexes (since working with all the data is
%  too expensive. If you have a fast computer, you may increase this.
sel = floor(rand(1000, 1) * size(X, 1)) + 1;

%  Setup Color Palette
palette = hsv(K);
colors = palette(idx(sel), :);

%  Visualize the data and centroid memberships in 3D
figure;
scatter3(X(sel, 1), X(sel, 2), X(sel, 3), 10, colors);
title('Pixel dataset plotted in 3D. Color shows centroid memberships');
fprintf('Program paused. Press enter to continue.\n');
pause;

%% === Part 8(b): Optional (ungraded) Exercise: PCA for Visualization ===
% Use PCA to project this cloud to 2D for visualization

% Subtract the mean to use PCA
[X_norm, mu, sigma] = featureNormalize(X);

% PCA and project the data to 2D
[U, S] = pca(X_norm);
Z = projectData(X_norm, U, 2);

% Plot in 2D
figure;
plotDataPoints(Z(sel, :), idx(sel), K);
title('Pixel dataset plotted in 2D, using PCA for dimensionality reduction');
fprintf('Program paused. Press enter to continue.\n');
pause;


function gamblers_ruin_simulation ( a_stakes, b_stakes, game_num )

%*****************************************************************************80
%
%% GAMBLERS_RUIN_SIMULATION simulates the game of gambler's ruin.
%
%  Discussion:
%
%    Two players, A and B, repeatedly toss a coin.
%    For heads, A wins one dollar from B;
%    For tails, B wins one dollar from A.
%    Play continues until one player is bankrupt.
%
%    This program "plays" the game GAME_NUM times, always starting from
%    the same initial configuration.
%
%    it keeps track of the number of coin tosses required, the number
%    of times the lead changes, and the number of times each player wins.
%
%    At the end, it prints some statistics, and plots histograms of the
%    length of the game, and the number of lead changes.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 April 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer A_STAKES, B_STAKES, the number of dollars that A and
%    B have initially.
%
%    Input, integer GAME_NUM, the number of games to simulate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'GAMBLERS_RUIN_SIMULATION\n' );
  fprintf ( 1, '  MATLAB version\n' );

  if ( nargin < 1 )
    a_stakes = input ( 'Enter A_STAKES: ' );
  else
    a_stakes = str2num ( a_stakes );
  end

  if ( nargin < 2 )
    b_stakes = input ( 'Enter B_STAKES: ' );
  else
    b_stakes = str2num ( b_stakes );
  end

  if ( nargin < 3 )
    game_num = input ( 'Enter GAME_NUM, the number of games to play: ' );
  else
    game_num = str2num ( game_num );
  end

  a_wins = 0;
  b_wins = 0;
%
%  Play GAME_NUM games.
%
  for game = 1 : game_num

    step_num = 0;
    leader = '0';
    flip_num = -1;
    a = a_stakes;
    b = b_stakes;

    while ( 0 < a & 0 < b )

      step_num = step_num + 1;

      r = rand ( );

      if ( r <= 0.5 )
        a = a + 1;
        b = b - 1;
      else
        a = a - 1;
        b = b + 1;
      end

      if ( a_stakes < a & leader ~= 'A' )
        leader = 'A';
        flip_num = flip_num + 1;
      elseif ( a < a_stakes & leader ~= 'B' )
        leader = 'B';
        flip_num = flip_num + 1;
      end

    end

    if ( b == 0 )
      a_wins = a_wins + 1;
    else
      b_wins = b_wins + 1;
    end

    flip(game) = flip_num;
    step(game) = step_num;

  end
%
%  Average over the number of games.
%
  step_ave = sum ( step(1:game_num) ) / game_num;
  prob_a_win = a_wins / game_num;
  prob_b_win = b_wins / game_num;
%
%  Print statistics.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of games in simulation = %d\n', game_num );
  fprintf ( 1, '  A starts game with %d\n', a_stakes );
  fprintf ( 1, '  B starts game with %d\n', b_stakes );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Average number of steps = %f\n', step_ave );
  fprintf ( 1, '  Expected number of steps = %d\n', a_stakes * b_stakes );
  fprintf ( 1, '  Maximum number of steps = %d\n', max ( step ) );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Average chance of A winning = %f\n', prob_a_win );
  fprintf ( 1, '  Expected chance of A winning = %f\n', a_stakes / ( a_stakes + b_stakes ) );
  fprintf ( 1, '  Average chance of B winning = %f\n', prob_b_win );
  fprintf ( 1, '  Expected chance of B winning = %f\n', b_stakes / ( a_stakes + b_stakes ) );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Average number of flips = %f\n', sum ( flip ) / game_num );
  fprintf ( 1, '  Maximum number of flips = %d\n', max ( flip ) );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Initial flip table:\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number Freq Prob\n' );
  fprintf ( 1, '\n' );
  for flip_num = 0 : 10
    i = find ( flip == flip_num );
    k = length ( i );
    fprintf ( 1, '  %4d  %6d  %f\n', flip_num, k, k / game_num );
  end
%
%  Plot steps.
%
  figure ( 1 )

  hist ( step, 40 )

  title ( 'Gambler''s ruin, number of steps' )
  xlabel ( 'Steps' )
  ylabel ( 'Frequency' )

  figure ( 2 )

  hist ( flip, 40 )
  title ( 'Gambler''s ruin, number of changes in the lead (flips)' )
  xlabel ( 'Flips' )
  ylabel ( 'Frequency' )

  return
end


function im = IdealLowPass(im0,fc)
% fc is the circular cutoff frequency which is normalized to [0 1], that is,
% the highest radian frequency \pi of digital signals is mapped to 1.

[ir,ic,iz] = size(im0);
hr = (ir-1)/2;
hc = (ic-1)/2;
[x, y] = meshgrid(-hc:hc, -hr:hr);

mg = sqrt((x/hc).^2 + (y/hr).^2);
lp = double(mg <= fc);

IM = fftshift(fft2(double(im0)));
IP = zeros(size(IM));
for z = 1:iz
    IP(:,:,z) = IM(:,:,z) .* lp;
end
im = abs(ifft2(ifftshift(IP)));


function oeprint1(mu, oev)

% print six classical orbital elements
% and orbital period in minutes

% input

%  mu     = gravitational constant (km**3/sec**2)
%  oev(1) = semimajor axis (kilometers)
%  oev(2) = orbital eccentricity (non-dimensional)
%           (0 <= eccentricity < 1)
%  oev(3) = orbital inclination (radians)
%           (0 <= inclination <= pi)
%  oev(4) = argument of perigee (radians)
%           (0 <= argument of perigee <= 2 pi)
%  oev(5) = right ascension of ascending node (radians)
%           (0 <= raan <= 2 pi)
%  oev(6) = true anomaly (radians)
%           (0 <= true anomaly <= 2 pi)

% Orbital Mechanics with Matlab

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

rtd = 180 / pi;

% unload orbital elements array

sma = oev(1);
ecc = oev(2);
inc = oev(3);
argper = oev(4);
raan = oev(5);
tanom = oev(6);

arglat = mod(tanom + argper, 2.0 * pi);

if (sma > 0.0)
    period = 2.0d0 * pi * sma * sqrt(sma / mu);
else
    period = 99999.9;
end

% print orbital elements

fprintf ('\n        sma (km)              eccentricity          inclination (deg)         argper (deg)');

fprintf ('\n %+16.14e  %+16.14e  %+16.14e  %+16.14e \n', sma, ecc, inc * rtd, argper * rtd);

fprintf ('\n       raan (deg)          true anomaly (deg)         arglat (deg)            period (min)');

fprintf ('\n %+16.14e  %+16.14e  %+16.14e  %+16.14e \n', raan * rtd, tanom * rtd, arglat * rtd, period / 60);


%% WGMGRATE Test convergence of multigrid methods for weak Galerkin method
%
% Reference
%
% An auxiliary space multigrid preconditioner for the weak Galerkin method.
% By Long Chen, Junping Wang, Yanqiu Wang, and Xiu Ye. Computers and
% Mathematics with Applications, 70(4):330?344 2015.
% doi:10.1016/j.camwa.2015.04.016

%% Options
clear variables;
close all;
option.maxIt = 4;
option.elemType = 'WG';
option.solver = 'mg';
option.smoothingstep = 2;
option.plotflag = 1;
option.rateflag = 0;
option.dispflag = 1;
colname = {'#Dof','Steps','Time'};

%% Example: circle mesh and Poisson equation
pde = sincosdata;
[node,elem] = circlemesh(0,0,1,0.25);
% showmesh(node,elem,'Facecolor','w');
bdFlag = setboundary(node,elem,'Dirichlet');
mesh = struct('node',node,'elem',elem,'bdFlag',bdFlag);

option.L0 = 1;
option.maxN = 3e5;
option.reducesystem = 0; % Solve the original system
[err,time,solver] = femPoisson(mesh,pde,option);
disptable(colname,solver.N,[],solver.itStep,[],solver.time,'%4.2g');

option.reducesystem = 1; % Solve the reduced system
[err,time,solver] = femPoisson(mesh,pde,option);
disptable(colname,solver.N,[],solver.itStep,[],solver.time,'%4.2g');

%% Example: square mesh and variable Poisson equation
[node,elem] = squaremesh([0,1,0,1],0.25);
% showmesh(node,elem,'Facecolor','w');
bdFlag = setboundary(node,elem,'Dirichlet');
mesh = struct('node',node,'elem',elem,'bdFlag',bdFlag);

option.L0 = 2;
option.dquadorder = 4;
pde = oscdiffdata;

option.reducesystem = 0; % Solve the original system
[err,time,solver] = femPoisson(mesh,pde,option);
disptable(colname,solver.N,[],solver.itStep,[],solver.time,'%4.2g');

option.reducesystem = 1; % Solve the reduced system
[err,time,solver] = femPoisson(mesh,pde,option);
disptable(colname,solver.N,[],solver.itStep,[],solver.time,'%4.2g');

%% Example: adaptive mesh and Poisson equation with less regularity
[node,elem] = squaremesh([-1,1,-1,1],1);
[node,elem] = delmesh(node,elem,'x>0 & y<0');
bdFlag = setboundary(node,elem,'Dirichlet');
mesh = struct('node',node,'elem',elem,'bdFlag',bdFlag);

pde = Lshapedata;
option.maxIt = 30;
option.maxN = 1e4;
option.printlevel = 0;
option.rateflag = 1;

option.reducesystem = 0; % Solve the original system
[err,time,solver] = afemPoisson(mesh,pde,option);
disptable(colname,solver.N,[],solver.itStep,[],solver.time,'%4.2g');

option.reducesystem = 1; % Solve the reduced system
[err,time,solver,eqn,node,elem] = afemPoisson(mesh,pde,option);
disptable(colname,solver.N,[],solver.itStep,[],solver.time,'%4.2g');
% figure; showmesh(node,elem,'Facecolor','w');


function [sh,pnl,pos] = marisa(x,N,M)
% this is a combo model, MA+RSI
thresh=55;
S=length(x);
e=ema(x,N);
% take the RSI of the *DETRENDED* series
r=rsi2(x-ema(x,15*M),M);
% bid/ask spreads
cost=0.01;     % BUND/BOBL
%cost=0.005;    % SCHATZ
%cost=1/64;     %Treasury futures
%cost = 0.0001;  %US/EUR
%cost = 0.05;   %EUR/JPY
%cost = 0.04;   %US/JPY
%cost = 0.0005;  %AUS/USD
%cost= 0.02;
%cost=1;        % eurostoxx

rpos=zeros(S,1);
% position of the ema
epos=sign(x-e);
% position of the rsi
I= (thresh-r)<0;
IU=[~1;I(1:end-1) & ~I(2:end)];
rpos(IU)=-1;
% crossing the lower threshold
I= ((100-thresh)-r)>0;
IL=[~1;I(1:end-1) & ~I(2:end)];
rpos(IL)=1;
% copy down previous position values
for i=2:S
    if rpos(i)==0;
        rpos(i)=rpos(i-1);
    end
end

% get the combined signal position
pos=(rpos+epos)/2;
pos( abs(pos) < 1)=0;

% pnl calculation
pnl= pos(1:end-1).*diff(x) - abs(diff(pos))*cost/2;
sh= sqrt(250)*mean(pnl)/std(pnl);