function [x, c, funVal, ValueL]=LogisticR(A, y, z, opts)
%
%%
% Function LogisticR
%      Logistic Loss with the L1-norm Regularization
%
%% Problem
%
%  min  f(x,c) = - weight_i * log (p_i) + 1/2 rsL2 * ||x||_2^2
%                 + z * \|x\|_1
%
%  By default, rsL2=0.
%
%  a_i denotes a training sample,
%      and a_i' corresponds to the i-th row of the data matrix A
%
%  y_i (either 1 or -1) is the response
%
%  p_i= 1/ (1+ exp(-y_i (x' * a_i + c) ) ) denotes the probability
%
%  weight_i denotes the weight for the i-th sample
%
%% 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 -        Lq/L1 norm regularization parameter (z >=0)
%  opts-      Optional inputs (default value: opts=[])
%
%% Output parameters:
%  x-         The obtained weight of size n x 1
%  c-         The obtained intercept (scalar)
%  funVal-    Function value during iterations
%
%% Copyright (C) 2009-2010 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 February 18, 2010.
%
%% Related papers
%
% [1]  Jun Liu, Jianhui Chen, and Jieping Ye, Large-Scale Sparse Logistic
%      Regression, KDD09
%
% [2]  Jun Liu and Jieping Ye, Efficient Euclidean Projections
%      in Linear Time, ICML 2009.
%
%% Related functions
%
%  sll_opts, initFactor, pathSolutionLeast
%  LogisticC, nnLogisticR, nnLogisticC
%
%%

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

[m,n]=size(A);

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

if (z<=0)
    error('\n z should be positive!\n');
end

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

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

% The parameter 'weight' contains the weight for each training sample.
% See the definition of the problem above.
% The summation of the weights for all the samples equals to 1.
if (isfield(opts,'sWeight'))
    sWeight=opts.sWeight;

    if ( length(sWeight)~=2 || sWeight(1) <=0 || sWeight(2) <= 0)
        error('\n Check opts.sWeight, which contains two positive values');
    end

    % we process the weight, so that the summation of the weights for all
    % the samples is 1.

    p_flag=(y==1);                  % the indices of the postive samples
    m1=sum(p_flag) * sWeight(1);    % the total weight for the positive samples
    m2=sum(~p_flag) * sWeight(2);   % the total weight for the positive samples

    weight(p_flag,1)=sWeight(1)/(m1+m2);
    weight(~p_flag,1)=sWeight(2)/(m1+m2);
else
    weight=ones(m,1)/m;             % if not specified, we apply equal weight
end

%% Starting point initialization

% process the regularization parameter

% L2 norm regularization
if isfield(opts,'rsL2')
    rsL2=opts.rsL2;
    if (rsL2<0)
        error('\n opts.rsL2 should be nonnegative!');
    end
else
    rsL2=0;
end

p_flag=(y==1);                  % the indices of the postive samples
m1=sum(weight(p_flag));         % the total weight for the positive samples
m2=1-m1;                        % the total weight for the positive samples

% L1 norm regularization
if (opts.rFlag==0)
    lambda=z;
else % z here is the scaling factor lying in [0,1]
    if (z<0 || z>1)
        error('\n opts.rFlag=1, and z should be in [0,1]');
    end

    % we compute ATb for computing lambda_max, when the input z is a ratio

    b(p_flag,1)=m2;  b(~p_flag,1)=-m1;
    b=b.*weight;

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

    lambda_max=max(abs(ATb));
    lambda=z*lambda_max;

    rsL2=rsL2*lambda_max; % the input rsL2 is a ratio of lambda_max
end

% initialize a starting point
if opts.init==2
    x=zeros(n,1); c=log(m1/m2);
else
    if isfield(opts,'x0')
        x=opts.x0;
        if (length(x)~=n)
            error('\n Check the input .x0');
        end
    else
        x=zeros(n,1);
    end

    if isfield(opts,'c0')
        c=opts.c0;
    else
        c=log(m1/m2);
    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

%% The main program

%% The Armijo Goldstein line search scheme + accelearted gradient descent

if (opts.mFlag==0 && opts.lFlag==0)

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

    L=1/m + rsL2; % the intial guess of the Lipschitz continuous gradient

    weighty=weight.*y;
    % the product between weight and y

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

    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;  sc=c + beta* ccp;

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

        % compute As=A*s
        As=Ax + beta* (Ax-Axp);

        % aa= - diag(y) * (A * s + sc)
        aa=- y.*(As+ sc);

        % fun_s is the logistic loss at the search point
        bb=max(aa,0);
        fun_s= weight' * ( log( exp(-bb) +  exp(aa-bb) ) + bb )+...
            rsL2/2 * s'*s;

        % compute prob=[p_1;p_2;...;p_m]
        prob=1./( 1+ exp(aa) );

        % b= - diag(y.* weight) * (1 - prob)
        b= -weighty.*(1-prob);

        gc=sum(b); % the gradient of c

        % compute g= AT b, the gradient of x
        if (opts.nFlag==0)
            g=A'*b;
        elseif (opts.nFlag==1)
            g=A'*b - sum(b) * mu';  g=g./nu;
        else
            invNu=b./nu;              g=A'*invNu-sum(invNu)*mu';
        end

        g=g+ rsL2 * s;  % add the squared L2 norm regularization term

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

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

            % L1-norm regularized projection
            x=sign(v).*max(abs(v)-lambda / L,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

            % aa= - diag(y) * (A * x + c)
            aa=- y.*(Ax+ c);

            % fun_x is the logistic loss at the new approximate solution
            bb=max(aa,0);
            fun_x= weight'* ( log( exp(-bb) +  exp(aa-bb) ) + bb ) +...
                rsL2/2 * x'*x;

            r_sum= (v'*v + (c-sc)^2) / 2;
            l_sum=fun_x - fun_s - v'* g - (c-sc)* gc;

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

            % the condition is fun_x <= fun_s + v'* g + c * gc
            %                           + L/2 * (v'*v + (c-sc)^2 )
            if(l_sum <= r_sum * L)
                break;
            else
                L=max(2*L, l_sum/r_sum);
                %fprintf('\n L=%e, r_sum=%e',L, r_sum);
            end
        end

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

        ValueL(iterStep)=L;
        % store values for L

        xxp=x-xp;    ccp=c-cp;
        funVal(iterStep)=fun_x + lambda* sum(abs(x));

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

%% Reformulated problem + Nemirovski's line search scheme

% Original problem:           min  f(x,c) = - weight_i * log (p_i) + 1/2 rsL2 * ||x||_2^2
%                                                      + z * \|x\|_1
%
% Reformulated problem:   min  f(x,c) = - weight_i * log (p_i) + 1/2 rsL2 * ||x||_2^2
%                                                      + z * 1^T t
%                                   s.t., |x| <=t

if (opts.mFlag==1 && opts.lFlag==0)

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

    L=1/m + rsL2; % the intial guess of the Lipschitz continuous gradient

    weighty=weight.*y;
    % the product between weight and y

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

    t=abs(x); tp=t;
    % t is the upper bound of absolute value of x

    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;  sc=c + beta* ccp; s_t= t + beta * (t -tp);

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

        % compute As=A*s
        As=Ax + beta* (Ax-Axp);

        % aa= - diag(y) * (A * s + sc)
        aa=- y.*(As+ sc);

        % fun_s is the logistic loss at the search point
        bb=max(aa,0);
        fun_s= weight' * ( log( exp(-bb) +  exp(aa-bb) ) + bb )+...
            rsL2/2 * s'*s;

        % compute prob=[p_1;p_2;...;p_m]
        prob=1./( 1+ exp(aa) );

        % b= - diag(y.* weight) * (1 - prob)
        b= -weighty.*(1-prob);

        gc=sum(b); % the gradient of c

        % compute g= AT b, the gradient of x
        if (opts.nFlag==0)
            g=A'*b;
        elseif (opts.nFlag==1)
            g=A'*b - sum(b) * mu';  g=g./nu;
        else
            invNu=b./nu;              g=A'*invNu-sum(invNu)*mu';
        end

        g=g+ rsL2 * s;  % add the squared L2 norm regularization term

        % copy x and Ax to xp and Axp
        xp=x;    Axp=Ax;
        cp=c;    tp=t;

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

            % projection
            [x, t]=ep1R(u,v,n);

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

            % 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

            % aa= - diag(y) * (A * x + c)
            aa=- y.*(Ax+ c);

            % fun_x is the logistic loss at the new approximate solution
            bb=max(aa,0);
            fun_x= weight'* ( log( exp(-bb) +  exp(aa-bb) ) + bb ) +...
                rsL2/2 * x'*x;

            r_sum= (v'*v + (c-sc)^2 + v_t'*v_t) / 2;
            l_sum=fun_x - fun_s - v'* g - (c-sc)* gc;

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

            % the condition is fun_x <= fun_s + v'* g + c * gc
            %                           + L/2 * (v'*v + (c-sc)^2 )
            if(l_sum <= r_sum * L)
                break;
            else
                L=max(2*L, l_sum/r_sum);
                %fprintf('\n L=%e, r_sum=%e',L, r_sum);
            end
        end

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

        ValueL(iterStep)=L;
        % store values for L

        xxp=x-xp;    ccp=c-cp;
        funVal(iterStep)=fun_x + lambda* sum(t);

        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 + norm(t-tp)^2 + (c-cp)^2);
                if ( norm_xxp <=opts.tol)
                    break;
                end
            case 4
                norm_xp=sqrt(xp'*xp + cp^2 + tp'*tp);    norm_xxp=sqrt(xxp'*xxp + norm(t-tp)^2 + (c-cp)^2);
                if ( norm_xxp <=opts.tol * max(norm_xp,1))
                    break;
                end
            case 5
                if iterStep>=opts.maxIter
                    break;
                end
        end
    end
end

%% Reformulated problem + adaptive line search scheme

% Original problem:           min  f(x,c) = - weight_i * log (p_i) + 1/2 rsL2 * ||x||_2^2
%                                                      + z * \|x\|_1
%
% Reformulated problem:   min  f(x,c) = - weight_i * log (p_i) + 1/2 rsL2 * ||x||_2^2
%                                                      + z * 1^T t
%                                   s.t., |x| <=t

if (opts.mFlag==1 && opts.lFlag==1)

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

    L=1/m + rsL2; % the intial guess of the Lipschitz continuous gradient

    weighty=weight.*y;
    % the product between weight and y

    gamma=1;
    % we shall set the value of gamma = L,
    % and L is appropriate for the starting point

    % assign xp with x, and Axp with Ax
    xp=x; Axp=Ax; xxp=zeros(n,1);
    cp=c;         ccp=0;
    t=abs(x); tp=t;
    % t is the upper bound of absolute value of x

    for iterStep=1:opts.maxIter
        while (1)
            if (iterStep~=1)
                alpha= (-gamma+ sqrt(gamma*gamma + 4* L * gamma)) / (2*L);
                beta= (gamma - gamma* alphap) / (alphap * gamma + alphap* L * alpha);
                % beta is the coefficient for generating search point s

                s=x + beta* xxp;   s_t= t + beta * (t -tp); sc=c + beta* ccp;
                As=Ax + beta* (Ax-Axp);
            else
                alpha= (-1+ sqrt(5)) / 2;  beta=0;
                s=x; s_t=t; sc= c;
                As=Ax;
            end

            % aa= - diag(y) * (A * s + sc)
            aa=- y.*(As+ sc);

            % fun_s is the logistic loss at the search point
            bb=max(aa,0);
            fun_s= weight' * ( log( exp(-bb) +  exp(aa-bb) ) + bb )+...
                rsL2/2 * s'*s;

            % compute prob=[p_1;p_2;...;p_m]
            prob=1./( 1+ exp(aa) );

            % b= - diag(y.* weight) * (1 - prob)
            b= -weighty.*(1-prob);

            gc=sum(b); % the gradient of c

            % compute g= AT b, the gradient of x
            if (opts.nFlag==0)
                g=A'*b;
            elseif (opts.nFlag==1)
                g=A'*b - sum(b) * mu';  g=g./nu;
            else
                invNu=b./nu;              g=A'*invNu-sum(invNu)*mu';
            end

            g=g+ rsL2 * s;  % add the squared L2 norm regularization term

            % let s walk in a step in the antigradient of s to get v
            % and then do the Lq/L1-norm regularized projection
            cnew= sc- gc/L;
            u=s-g/L;
            v= s_t - lambda / L;

            % projection
            [xnew, tnew]=ep1R(u,v,n);

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

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

            % aa= - diag(y) * (A * x + c)
            aa=- y.*(Axnew+ cnew);

            % fun_x is the logistic loss at the new approximate solution
            bb=max(aa,0);
            fun_x= weight'* ( log( exp(-bb) +  exp(aa-bb) ) + bb ) +...
                rsL2/2 * xnew'*xnew;

            r_sum= (v'*v + (cnew-sc)^2 + v_t'*v_t) / 2;
            l_sum=fun_x - fun_s - v'* g - (cnew-sc)* gc;

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

            % the condition is fun_x <= fun_s + v'* g + c * gc
            %                           + L/2 * (v'*v + (c-sc)^2 )
            if(l_sum <= r_sum * L)
                break;
            else
                L=max(2*L, l_sum/r_sum);
                %fprintf('\n L=%e, r_sum=%e',L, r_sum);
            end
        end

        gamma=L* alpha* alpha;    alphap=alpha;
        % update gamma, and alphap

        ValueL(iterStep)=L;
        % store values for L

        tao=L * r_sum / l_sum;
        if (tao >=5)
            L=L*0.8;
        end
        % decrease the value of L

        xp=x;  x=xnew; xxp=x-xp;
        Axp=Ax; Ax=Axnew;
        tp=t; t=tnew;
        cp=c; c=cnew; ccp=c-cp;
        % update x, t, c, and Ax

        funVal(iterStep)=fun_x + lambda* sum(t);

        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 + norm(t-tp)^2 + (c-cp)^2);
                if ( norm_xxp <=opts.tol)
                    break;
                end
            case 4
                norm_xp=sqrt(xp'*xp + cp^2 + tp'*tp);    norm_xxp=sqrt(xxp'*xxp + norm(t-tp)^2 + (c-cp)^2);
                if ( norm_xxp <=opts.tol * max(norm_xp,1))
                    break;
                end
            case 5
                if iterStep>=opts.maxIter
                    break;
                end
        end
    end
end

%%
if(opts.mFlag==0 && opts.lFlag==1)
    error('\n The function does not support opts.mFlag=0 & opts.lFlag=1!');
end


function [x,err,it] = perform_conjugate_gradient(A,y,options)

% perform_conjugate_gradient - perform (bi)-conjugate gradient
%
%     [x,err,k] = perform_conjugate_gradient(A,y,options);
%
%   Solves for A*x=y.
%   Works both for vector x,y and matrix x,y (parralel soving of many
%   linear equations).
%
%   Important: the algorithm assumes that the matrix is symmetric definite
%   positive. If it is not the case, then you must set options.is_sdp=0,
%   and the algorithm will use a bi-conjugate gradient descent (x2 slower).
%
%   A can be a matrix or a callback function y=A(x,options).
%   In this case, you have to set options.ncols as the number of columns of
%   A (if it is a callback).
%   In the non-symmetric case, then options.transpose=1 for the computation
%   of A*x and options.transpose=-1 for the computation of A'*x.
%
%   err monitors the decreasing of |A*x-y|.
%   k is the total number of iterations.
%
%   You can set:
%       options.x is an initial guess
%       options.epsilon is maximum error
%       options.niter_max is maximum number of iterations
%
%   Copyright (c) 2007 Gabriel Peyre

options.null = 0;
niter = getoptions(options, 'niter_max', 100);
epsilon = getoptions(options, 'epsilon', 1e-5);
is_sdp = getoptions(options, 'is_sdp', 1);

use_callback = 0;
if not(isnumeric(A))
    use_callback = 1;
end
if isfield(options, 'x')
    x = options.x;
else
    if use_callback==0
        x = zeros(size(A,2),1);
    else
        if isfield(options, 'ncols')
            x = zeros(options.ncols, 1);
        else
            error('You have to specify options.ncols');
        end
    end
end

if norm(y(:), 'fro') == 0
    normb = epsilon;
else
    normb = epsilon; % * sum(y(:).^2);
end

if use_callback==0
    r  = y - A*x;
else
    options.transpose = 1;
    r  = y - feval(A,x,options);
end
p = r;
if is_sdp==0
    rr = r;
    pp = p;
end
r0 = sum(r(:).^2);

err = [sum(r0)];
for it=1:niter

    % auxiliary vector
    if use_callback==0
        w  = A*p;
    else
        options.transpose = 1;
        % options.transpose = -1;
        w  = feval(A,p,options);
    end

    if is_sdp==1
        d = sum(p(:) .* w(:));
    else
        d = sum(pp(:) .* w(:));
    end
    I = find(abs(d)<eps); d(I) = 1;
    alpha = repmat( r0 ./ d, [size(x,1) 1] );              % found optimal alpha in line search
    x = x + alpha.*p;                       % new guess
    r = r - alpha.*w;                       % the residual is in fact r=b-A*x
    if is_sdp==0
        if use_callback==0
            w  = A'*pp;
        else
            options.transpose = -1;
            w  = feval(A,pp,options);
        end
        rr = rr-alpha.*w;
    end

    rprev = r0;                             % save norm of the old residual
    if is_sdp==0
        r0 = sum(r.*rr);
    else
        r0 = sum(r.^2);                         % compute norm of new residual
    end

    err(end+1) = sqrt( sum(r.^2) );
    if err(end)<normb
        return;
    end

    % search direction
    beta = r0./rprev;
    p = r + repmat(beta, [size(x,1) 1]).*p;
    if is_sdp==0
        pp = rr + repmat(beta, [size(x,1) 1]).*pp;
    end

end


function z = he_polynomial_zeros ( nt )

%*****************************************************************************80
%
%% HE_POLYNOMIAL_ZEROS zeros of He(i,x).
%
%  Discussion:
%
%    He(i,x) represents the probabilist's Hermite polynomial.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 February 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer NT, the degree of the polynomial.
%
%    Output, real Z(NT,1), the zeros of the polynomial.
%
  aj = zeros ( nt, 1 );
  bj = sqrt ( ( 1 : nt )' / 2.0 );
  wts = zeros ( nt, 1 );
  wts(1,1) = sqrt ( sqrt ( pi ) );

  [ z, wts ] = imtqlx ( nt, aj, bj, wts );
%
%  Adjust for probabilist.
%
  z(1:nt,1) = z(1:nt,1) * sqrt ( 2.0 );

  return
end


function [ back, sigma ] = image_background( im, make_plot )
% IMAGE_BRACKGROUND Automatically find the pixel-value of the background,
% for images that are predominantly black
%
% [ back, sigma ] = image_background( im )
% [ back, sigma ] = image_background( im, make_plot )
%
% Automatically find the pixel-value of the background, for images that are
% predominantly black.
%
% In that case, the histogram of the image has a peak in the low values,
% of Gaussian shape which correspond to the background pixels.
% image_background returns the mean and the sigma of this peak
%
% if 'make_plot' is set and true, an histogram and detected values is displayed
%
% TODO: automatically detect when the method fails

% F. Nedelec, 2005 - April 2008
%
% Ramon Casero <rcasero@gmail.com>: Minor edits

%compatibility with tiffread
if ( isfield( im, 'data') )
    filename = im.filename;
    im = im(1).data;
else
    filename = inputname(1);
end

% add a plot:
if nargin < 2
    make_plot = 0;
end

h = image_histogram( im );
%remove under-exposed pixels, where there might be a peak:
h(1) = 0;

%% calculate a Gaussian filter:

filt_sig = 20;
filt = exp( -( (-2*filt_sig:2*filt_sig) / filt_sig ) .^ 2 );
filt = filt ./ sum( filt );

% convolve by the filter to get a smooth profile:

hs = double( conv( h, filt ) );

%crop to the same size as h
hs = hs( 2*filt_sig+(1:numel(h)) );

%% find the maximum in the smoothed histogram

%[ hsmax, upper ] = max(hs);

% iteratively search for the first maximum
%back = 1;
%while  back < upper  &&  hs(back+1) >= hs(back)
%    back = back + 1;
%end

[ hsmax, back ] = max(hs);
upper = back;

if sum( h(1:back) ) < numel(im) / 5
    fprintf(['  Background detection might have failed for ', filename, '\n']);
end

%% Make a figure to debug things
if make_plot

    x = (0:size(h)-1)';
    figure('Name','image_background', 'Position', [100 150 800 300]);
    axes('Position', [0.05 0.1 0.9 0.8] );
    hold on;
    xlim([0 size(h,1)]);
    set(gca, 'ytick', [])

    plot(x, h, 'g.' );
    plot(x, hs, 'k:', 'linewidth', 1);

    plot([back, back], ylim, 'b-', 'linewidth', 2);
    plot([upper, upper], ylim, 'k:');

    text(back, hsmax, sprintf(' %i', back), 'FontSize', 18 );
    title('Histogram of pixel values');

end

%% Gaussian fit of the distribution of dark pixels

    function f = gauss(x, a)
        f = exp( -(x-a(1)).^2 / a(2) );
    end

    function err = gauss_err(a)
        f = gauss(rx, a);
        s = sum(ry.*f) / sum(f.*f);
        err = sum( abs(f*s-ry) );   %robust fitting
        %err = norm( f*s-ry );      %least-square fitting
    end

if nargout > 1

    % Gaussian fit to obtain the variance of the black pixel values

    rwd = fix(back*0.8);
    ri = max(back-rwd, 1) : min(back+rwd, length(hs));
    rh = h(ri);

    rx = (ri-1)';
    ry = rh / sum(rh);
    esp = sum(rx.*ry);
    var = sum(rx.*rx.*ry);
    sigma = sqrt(var-esp*esp);

    if nargin > 1
        fprintf('Histogram  : mean %.2f, sigma %.2f\n', back, sigma);
    end

    [ pamG, pval, flag ] = fminsearch(@gauss_err, [ esp, 2*(var-esp*esp) ]);

    %if the fit is successful, we change our estimate of sigma:
    if flag == 1
        f     = gauss(rx, pamG);
        fitG  = f * ( sum(rh) * sum(ry.*f) / sum(f.*f) );

        backG = pamG(1);
        sigma = sqrt(pamG(2)/2);

        if nargin > 1
            fprintf('Gauss   fit: mean %.2f, sigma %.2f\n', backG, sigma);
        end
    end

    if make_plot
        %make an inset figure:
        axes('Position', [0.5 0.25 0.4 0.62]);
        plot( rx, h(1+rx), 'g.');
        hold on;
        plot( rx, hs(1+rx), 'b--');
        if exist('fitG', 'var')
            plot( rx, fitG, 'k-');
        end
        plot([back, back], ylim, 'k-');
        if exist('sigma', 'var')
            w = sqrt(2) * sigma;
            plot([back-w, back-w], ylim, 'k:');
            plot([back+w, back+w], ylim, 'k:');
        end
    end
end

%% Gamma fit (could be appropriate for low photon counts)

    function g = gamma_dis(x, a)
        %a is of dimension 2: a = { k, theta }
        %gamma density function
        g = exp( (a(1)-1)*log(x) - x/a(2) - a(1)*log(a(2)) ) / gamma(a(1));
    end

    function err = gamma_err(a)
        f = gamma_dis(rx, a);
        s = sum(ry.*f) / sum(f.*f);
        err = sum( abs(f*s-ry) );   %robust fitting
        %err = norm( f*s-ry );      %least-square fitting
    end

if nargout > 1

    [ pamP, pval, flag ] = fminsearch(@gamma_err, [ 5, esp/5 ]);

    if flag == 1

        f      = gamma_dis(rx, pamP);
        fitP   = f * ( sum(rh) * sum(ry.*f) / sum(f.*f) );

        %backP  = pamP(1) * pamP(2);  %mean-value
        sigmaP = sqrt(pamP(1)) * pamP(2); %sigma
        [v, id] = max(f);
        backP  = rx(id);  %position of peak

        if nargin > 1
            fprintf('Gamma   fit: mean %.2f, sigma %.2f\n', backP, sigmaP);
        end

        if make_plot
            plot( rx, fitP, 'r-');
        end

    end

end

%% Poisson fit

    function p = poisson(x, a)
        n = x ./ a(2);
        % discrete poisson distribution over n,
        p = exp( n .* ( 1 - log( n ./ a(1) ) ) + 0.5*log(n) );
    end

    function err = poisson_err(a)
        f = poisson(rx, a);
        s = sum(ry.*f) / sum(f.*f);
        err = sum( abs(f*s-ry) );   %robust fitting
        %err = norm( f*s-ry );      %least-square fitting
    end

if nargout > 1

    [ pamS, pval, flag ] = fminsearch(@poisson_err, [ esp / 10, 10 ]);

    if flag == 1

        grain  = pamS(2);
        backS  = pamS(2) * pamS(1);      %mean
        sigmaS = pamS(2) * sqrt(pamS(1));

        f      = poisson(rx, pamS);
        fitS   = f * ( sum(rh) * sum(ry.*f) / sum(f.*f) );

        if nargin > 1
            fprintf('Poisson fit: mean %.2f, sigma %.2f, grain %.2f\n', backS, sigmaS, grain);
        end

        if make_plot
            plot( rx, fitS, 'b-');
        end

    end

end

end


function [s, lam] = shcovft(x, shrinkvar)
% Shrinkage estimate of a covariance matrix, using optimal shrinkage coefficient.
% INPUT:
% x is n*p data matrix
% shrinkvar :
% 0: corshrink (default)
% 1: varshrink
%
% OUTPUT:
% s is the posdef p*p cov matrix
% lam is the shrinkage coefficient
%
% See  J. Schaefer and K. Strimmer.  2005.  A shrinkage approach to
%   large-scale covariance matrix estimation and implications
%   for functional genomics. Statist. Appl. Genet. Mol. Biol. 4:32.
% This code is based on their original code http://strimmerlab.org/software.html
% but has been vectorized and simplified by Kevin Murphy.
% Adapted by Marcel van Gerven

if nargin < 2, shrinkvar = 0; end

[n p] = size(x);
if p==1, s=var(x); return; end

switch num2str(shrinkvar)

  case '1' % Eqns 10 and 11 of Opgen-Rhein and Strimmer (2007)
    [v, lam] = varshrink(x);
    dsv = diag(sqrt(v));
    r = corshrink(x);
    s = dsv*r*dsv;

  otherwise % case 'D' of Schafer and Strimmer
    v = var(x);
    dsv = diag(sqrt(v));
    [r, lam] = corshrink(x);
    s = dsv*r*dsv;

end

%%%%%%%%

function [sv, lambda] = varshrink (x)
% Eqns 10 and 11 of Opgen-Rhein and Strimmer (2007)
[v, vv] = varcov(x);
v = diag(v); vv = diag(vv);
vtarget = median(v);
numerator = sum(vv);
denominator = sum((v-vtarget).^2);
lambda = numerator/denominator;
lambda = min(lambda, 1); lambda = max(lambda, 0);
sv = (1-lambda)*v + lambda*vtarget;

function [Rhat, lambda] = corshrink(x)
% Eqn on p4 of Schafer and Strimmer 2005
[n, p] = size(x);
sx = makeMeanZero(x); sx = makeStdOne(sx); % convert S to R
[r, vr] = varcov(sx);
offdiagsumrij2 = sum(sum(tril(r,-1).^2));
offdiagsumvrij = sum(sum(tril(vr,-1)));
lambda = offdiagsumvrij/offdiagsumrij2;
lambda = min(lambda, 1); lambda = max(lambda, 0);
Rhat = (1-lambda)*r;
Rhat(logical(eye(p))) = 1;

function [S, VS] = varcov(x)
% s(i,j) = cov X(i,j)
% vs(i,j) = est var s(i,j)
[n,p] = size(x);
xc = makeMeanZero(x);
S = cov(xc);
XC1 = repmat(reshape(xc', [p 1 n]), [1 p 1]); % size p*p*n !
XC2 = repmat(reshape(xc', [1 p n]),  [p 1 1]); % size p*p*n !
VS = var(XC1 .* XC2, 0,  3) * n/((n-1)^2);

function xc = makeMeanZero(x)
% make column means zero
[n,p] = size(x);
m = mean(x);
xc = x - ones(n, 1)*m;

function xc = makeStdOne(x)
% make column  variances one
[n,p] = size(x);
sd = ones(n, 1)*std(x);
xc = x ./ sd;


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

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

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

% ====================== YOUR CODE HERE ======================
% Instructions: Go over every example, find its closest centroid, and store
%               the index inside idx at the appropriate location.
%               Concretely, idx(i) should contain the index of the centroid
%               closest to example i. Hence, it should be a value in the
%               range 1..K
%
% Note: You can use a for-loop over the examples to compute this.
%
m = size(X,1);
for i = 1:m,
  minDistance = 10^6; % randomly chosen large enough value
  for j = 1:K,
    distance = sum((X(i,:) - centroids(j,:)).^2);
    if distance < minDistance,
      minDistance = distance;
      idx(i) = j;
    end
  end
end

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

end


function test_suite = test_polygonSecondAreaMoments
%TEST_POLYGONSECONDAREAMOMENTS Tests for polygonSecondAreaMoments.
%
%   Example
%       runtests('test_polygonSecondAreaMoments.m')
%
%   References
%       Expected (_exp) values are taken from:
%       https://en.wikipedia.org/wiki/List_of_second_moments_of_area
%       2020 - Bedford & Liechti - Mechanics of Materials
%           DOI: 10.1007/978-3-030-22082-2
%

% ------
% Author: oqilipo
% E-mail: N/A
% Created: 2022-12-21, using MATLAB 9.13.0.2080170 (R2022b) Update 1
% Copyright 2022

test_suite = functiontests(localfunctions);

function testCircle(testCase)
r = randi([1 100]);
circle = circleToPolygon([0 0 r], round(2*pi*r*1e2));

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(circle);
Ixx_exp = pi/4*r^4;
Iyy_exp = Ixx_exp;
Ixy_exp = 0;

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',3*1e-1);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',3*1e-1);
testCase.assertEqual(Ixy, Ixy_exp, 'AbsTol',1e-1);

function testAnnulus(testCase)
r2 = randi([50 100]);
r1 = r2 - randi([1 49]);
outerCircle = circleToPolygon([0 0 r2], round(2*pi*r2*1e2));
innerCircle = flipud(circleToPolygon([0 0 r1], round(2*pi*r1*1e2)));
annulus = {outerCircle; innerCircle};

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(annulus);
Ixx_exp = pi/4*(r2^4-r1^4);
Iyy_exp = Ixx_exp;
Ixy_exp = 0;

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',2*1e-1);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',2*1e-1);
testCase.assertEqual(Ixy, Ixy_exp, 'AbsTol',1e-1);

function testCircularSector(testCase)
r = randi([1 100]);
circle = circleToPolygon([0 0 r] , round(2*pi*r*1e2));
theta = (pi/2-0.2)*rand+0.1;
xPosLine = reverseLine(createLine(theta/2));
xNegLine = createLine(-theta/2);

semiCircle = clipPolygonHP(circle, xPosLine);
circularSector = clipPolygonHP(semiCircle, xNegLine);

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(circularSector);
Ixx_exp = (theta-sin(theta))*r^4/8;
Iyy_exp = (theta+sin(theta))*r^4/8;
Ixy_exp = 0;

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',1e-1);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',1e-1);
testCase.assertEqual(Ixy, Ixy_exp, 'AbsTol',1e-7);

function testCenteredSemiCircle(testCase)
r = randi([1 100]);
circle = circleToPolygon([0 0 r], round(2*pi*r*1e2));
semiCircle = clipPolygonHP(circle, [0 0 1 0]);
centeredSemiCircle = semiCircle - polygonCentroid(semiCircle);

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(centeredSemiCircle);
Ixx_exp = (pi/8-8/(9*pi))*r^4;
Iyy_exp = pi/8*r^4;
Ixy_exp = 0;

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',2*1e-1);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',2*1e-1);
testCase.assertEqual(Ixy, Ixy_exp, 'AbsTol',1e-7);

function testSemiCircle(testCase)
r = randi([1 100]);
circle = circleToPolygon([0 0 r], round(2*pi*r*1e2));
semiCircle = clipPolygonHP(circle, [0 0 1 0]);

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(semiCircle);
Ixx_exp = pi/8*r^4;
Iyy_exp = Ixx_exp;
Ixy_exp = 0;

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',2*1e-1);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',2*1e-1);
testCase.assertEqual(Ixy, Ixy_exp, 'AbsTol',1e-7);

function testQuarterCircle(testCase)
r = randi([1 100]);
circle = circleToPolygon([0 0 r], round(2*pi*r*1e2));
semiCircle = clipPolygonHP(circle, [0 0 1 0]);
quarterCircle = clipPolygonHP(semiCircle, [0 0 0 -1]);

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(quarterCircle);
Ixx_exp = pi/16*r^4;
Iyy_exp = pi/16*r^4;
Ixy_exp = r^4/8;

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',1e-1);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',1e-1);
testCase.assertEqual(Ixy, Ixy_exp, 'AbsTol',1e-1);

function testCenteredQuarterCircle(testCase)
r = randi([1 100]);
circle = circleToPolygon([0 0 r], round(2*pi*r*1e2));
semiCircle = clipPolygonHP(circle, [0 0 1 0]);
quarterCircle = clipPolygonHP(semiCircle, [0 0 0 -1]);
centeredQuarterCircle = quarterCircle - polygonCentroid(quarterCircle);

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(centeredQuarterCircle); %#ok<ASGLU>
Ixx_exp = (pi/16-4/(9*pi))*r^4;
Iyy_exp = Ixx_exp;
% Ixy_exp = ?;

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',1e-1);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',1e-1);

function testEllipse(testCase)
a = randi([51 100]);
b = randi([1 50]);
ellipse = ellipseToPolygon([0 0 a b], 4*a*sqrt(1-b^2/a^2)*1e2);

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(ellipse);
Ixx_exp = pi/4*a*b^3;
Iyy_exp = pi/4*a^3*b;
Ixy_exp = 0;

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',6*1e-1);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',6*1e-1);
testCase.assertEqual(Ixy, Ixy_exp, 'AbsTol',1e-1);

function testRectangle(testCase)
b = randi([51 100]);
h = randi([1 50]);
rectangle = [0 0; b 0; b h; 0 h];

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(rectangle);
Ixx_exp = b*h^3/3;
Iyy_exp = b^3*h/3;
Ixy_exp = b^2*h^2/4;

testCase.assertEqual(Ixx, Ixx_exp);
testCase.assertEqual(Iyy, Iyy_exp);
testCase.assertEqual(Ixy, Ixy_exp);

function testCenteredRectangle(testCase)
b = randi([51 100]);
h = randi([1 50]);
centeredRectangle = [b/2 -h/2; b/2 h/2; -b/2 h/2; -b/2 -h/2];

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(centeredRectangle);
Ixx_exp = b*h^3/12;
Iyy_exp = b^3*h/12;
Ixy_exp = 0;

testCase.assertEqual(Ixx, Ixx_exp);
testCase.assertEqual(Iyy, Iyy_exp);
testCase.assertEqual(Ixy, Ixy_exp);

function testHollowRectangle(testCase)
b = randi([51 100]);
h = randi([10 50]);
b1 = b - randi([10 20]);
h1 = h - randi([1 8]);
outerRectangle = [b/2 -h/2; b/2 h/2; -b/2 h/2; -b/2 -h/2];
innerRectangle = [-b1/2 -h1/2; -b1/2 h1/2; b1/2 h1/2; b1/2 -h1/2];
hollowRectangle = {outerRectangle; innerRectangle};

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(hollowRectangle);
Ixx_exp = (b*h^3 - b1*h1^3)/12;
Iyy_exp = (b^3*h - b1^3*h1)/12;
Ixy_exp = 0;

testCase.assertEqual(Ixx, Ixx_exp);
testCase.assertEqual(Iyy, Iyy_exp);
testCase.assertEqual(Ixy, Ixy_exp);

function testCenteredTriangle(testCase)
b = randi([51 100]);
h = randi([51 100]);
a = randi([1 25]);
triangle = [0 0; b 0; a h];
centeredTriangle = triangle - polygonCentroid(triangle);

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(centeredTriangle);
Ixx_exp = b*h^3/36;
Iyy_exp = (b^3*h-b^2*h*a+b*h*a^2)/36;
Ixy_exp = -b*h^2/72*(b-2*a);

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',1e-8);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',1e-8);
testCase.assertEqual(Ixy, Ixy_exp, 'AbsTol',1e-8);

function testTriangle(testCase)
b = randi([51 100]);
h = randi([51 100]);
a = randi([1 25]);
triangle = [0 0; b 0; a h];

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(triangle);
Ixx_exp = b*h^3/12;
Iyy_exp = (b^3*h+b^2*h*a+b*h*a^2)/12;
Ixy_exp = b*h^2/24*(b+2*a);

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',1e-8);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',1e-8);
testCase.assertEqual(Ixy, Ixy_exp, 'AbsTol',1e-8);

function testlSection(testCase)
L = randi([51 100]);
t = randi([1 25]);
lSection = [0 0; L 0; L t; t t; t L; 0 L];
lSection = lSection - polygonCentroid(lSection);

[Ixx, Iyy, Ixy] = polygonSecondAreaMoments(lSection);
Ixx_exp = (t*(5*L^2-5*L*t+t^2)*(L^2-L*t+t^2))/(12*(2*L-t));
Iyy_exp = Ixx_exp;
Ixy_exp = (L^2*t*(L-t)^2)/(4*(t-2*L));

testCase.assertEqual(Ixx, Ixx_exp, 'AbsTol',1e-8);
testCase.assertEqual(Iyy, Iyy_exp, 'AbsTol',1e-8);
testCase.assertEqual(Ixy, Ixy_exp, 'AbsTol',1e-8);


function A = matrix(k, n)
%MATRIX  Test matrices accessed by number.
%        MATRIX(K, N) is the N-by-N instance of matrix number K in
%        a set of test matrices comprising those in MATLAB plus those
%        in the Matrix Computation Toolbox,
%        with all other parameters set to their default.
%        N.B. - Only those matrices which are full and take an arbitrary
%               dimension N are included.
%             - Some of these matrices are random.
%        MATRIX(K) is a string containing the name of the K'th matrix.
%        MATRIX(0) is the number of matrices, i.e. the upper limit for K.
%        Thus to set A to each N-by-N test matrix in turn use a loop like
%             for k=1:matrix(0)
%                 A = matrix(k, N);
%                 Aname = matrix(k);   % The name of the matrix
%             end
%        MATRIX(-1) returns the version number and date of the
%        Matrix Computation Toolbox.
%        MATRIX with no arguments lists the names and numbers of the M-files in the
%        collection.

%         References:
%         N. J. Higham, Accuracy and Stability of Numerical Algorithms,
%            Second edition, Society for Industrial and Applied Mathematics,
%            Philadelphia, PA, 2002; sec. 20.5.

% Matrices from gallery:
matrices = [%
'cauchy  '; 'chebspec'; 'chebvand'; 'chow    ';
'circul  '; 'clement '; 'condex  ';
'cycol   '; 'dramadah'; 'fiedler ';
'forsythe'; 'frank   '; 'gearmat '; 'grcar   ';
'invhess '; 'invol   '; 'ipjfact '; 'jordbloc';
'kahan   '; 'kms     '; 'krylov  '; 'lehmer  ';
'lesp    '; 'lotkin  '; 'minij   '; 'moler   ';
'orthog  '; 'parter  '; 'pei     '; 'prolate ';
'randcolu'; 'randcorr'; 'rando   '; 'randsvd ';
'redheff '; 'riemann '; 'ris     '; 'smoke   ';
'toeppd  '; 'triw    ';];
n_gall = length(matrices);

% Other MATLAB matrices:
matrices = [matrices;
'hilb    '; 'invhilb '; 'magic   '; 'pascal  ';
'rand    '; 'randn   ';];
n_MATLAB = length(matrices);

% Matrices from Matrix Computation Toolbox:
matrices = [matrices;
'augment '; 'gfpp    '; 'magic   '; 'makejcf ';
'rschur  '; 'vand    '];
n_mats = length(matrices);

if nargin == 0

   rows = ceil(n_mats/5);
   temp = zeros(rows,5);
   temp(1:n_mats) = 1:n_mats;

   for i = 1:rows
      for j = 1:5
        if temp(i,j) == 0, continue, end
        fprintf(['%2.0f: ' sprintf('%s',matrices(temp(i,j),:)) '  '], ...
                temp(i,j))
      end
      fprintf('\n')
   end
   fprintf('Matrices 1 to %1.0f are from MATLAB\.', n_MATLAB)

elseif nargin == 1
   if k == 0
      A = length(matrices);
   elseif k > 0
      A = deblank(matrices(k,:));
   else
      % Version number and date of collection.
      A = 'Version 1.2, September 5 2002';
   end
else
   if k <= n_gall
      A = eval( ['gallery(''' deblank(matrices(k,:)) ''',n)'] );
   else
      A = eval( [deblank(matrices(k,:)) '(n)'] );
   end
end


function [ x, dp2, p1 ] = jacobi_ss_root ( x, n, alpha, beta, b, c )

%*****************************************************************************80
%
%% JACOBI_SS_ROOT improves an approximate root of a Jacobi polynomial.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 October 2005
%
%  Author:
%
%    Original FORTRAN77 version by Arthur Stroud, Don Secrest.
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Arthur Stroud, Don Secrest,
%    Gaussian Quadrature Formulas,
%    Prentice Hall, 1966,
%    LC: QA299.4G3S7.
%
%  Parameters:
%
%    Input, real X, the approximate root.
%
%    Input, integer N, the order of the polynomial to be computed.
%
%    Input, real ALPHA, BETA, the exponents of (1-X) and
%    (1+X) in the quadrature rule.
%
%    Input, real B(N), C(N), the recursion coefficients.
%
%    Output, real X, the improved approximate root.
%
%    Output, real DP2, the value of J'(N)(X).
%
%    Output, real P1, the value of J(N-1)(X).
%
  maxstep = 10;

  for i = 1 : maxstep

    [ p2, dp2, p1 ] = jacobi_ss_recur ( x, n, alpha, beta, b, c );

    d = p2 / dp2;
    x = x - d;

    if ( abs ( d ) <= eps * ( abs ( x ) + 1.0 ) )
      return
    end

  end

  return
end


function linplus_test30 ( )

%*****************************************************************************80
%
%% TEST30 tests R8GE_FA, R8GE_SL.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 March 2009
%
%  Author:
%
%    John Burkardt
%
  n = 10;
  seed = 123456789;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST30\n' );
  fprintf ( 1, '  For a matrix in general storage,\n' );
  fprintf ( 1, '  R8GE_FA computes the LU factors,\n' );
  fprintf ( 1, '  R8GE_SL solves a factored system.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Matrix order N = %d\n', n );
%
%  Set the matrix.
%
  [ a, seed ] = r8ge_random ( n, n, seed );
%
%  Set the desired solution.
%
  x = r8vec_indicator ( n );
%
%  Compute the corresponding right hand side.
%
  b = r8ge_mxv ( n, n, a, x );
%
%  Factor the matrix.
%
  [ a_lu, pivot, info ] = r8ge_fa ( n, a );

  if ( info ~= 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TEST30 - Fatal error!\n' );
    fprintf ( 1, '  R8GE_FA declares the matrix is singular!\n' );
    fprintf ( 1, '  The value of INFO is %d\n', info );
    return
  end
%
%  Solve the linear system.
%
  job = 0;
  x = r8ge_sl ( n, a_lu, pivot, b, job );

  r8vec_print ( n, x, '  Solution:' );
%
%  Set the desired solution.
%
  x(1:n) = 1.0E+00;
%
%  Compute the corresponding right hand side.
%
  job = 0;
  b = r8ge_ml ( n, a_lu, pivot, x, job );
%
%  Solve the system
%
  job = 0;
  x = r8ge_sl ( n, a_lu, pivot, b, job );

  r8vec_print ( n, x, '  Solution:' );
%
%  Set the desired solution.
%
  x = r8vec_indicator ( n );
%
%  Compute the corresponding right hand side.
%
  job = 1;
  b = r8ge_ml ( n, a_lu, pivot, x, job );
%
%  Solve the system
%
  job = 1;
  x = r8ge_sl ( n, a_lu, pivot, b, job );

  r8vec_print ( n, x, '  Solution of transposed system:' );

  return
end


function rs = corrdim(s, bins)

%tstoolbox/@signal/corrdim
%   Syntax:
%     * rs = corrdim(s, bins)
%
%   Input arguments:
%     * s - data points (row vectors)
%     * bins - maximal number of partition per axis (optional)
%
%   Compute the correlation dimension of a time-delay reconstructed
%   timeseries s for dimensions from 1 to D, where D is the dimension of
%   the input vectors using boxcounting approach. The default number of
%   bins is 100.
%
% Copyright 1997-2001 DPI Goettingen, License http://www.physik3.gwdg.de/tstool/gpl.txt

narginchk(1,2);

if ndim(s) ~= 2
    error('Signal must contain vector data');
end

if nargin<2
    bins = 100;
end

points = data(s);
[N,dim] = size(points);

% scale data to be within 0 and 1
points = points - min(min(points));
points = points / max(max(points));

% give a sortiment of (integer) partitionsizes with almost exponential behaviour
par = [2 3 4 5 6 7 8 10 12 14 16 20 23 27 32 39 46 54 64 77 91 108 128 153 182 216 256 ...
      305 363 431 512 609 725 862 1024 1218 1449 1723 2048 2436 2897 3445 4096 4871 ...
	  5793 6889 8192 9742 11586 13778 16384 19484 23171 27555 32768 38968 46341 55109 65536];

partitions = par(find(par<=bins));	% use no sizes greater than bins

[dummy,dummy2,e] = boxcount(points, partitions);

e = [zeros(1,dim) ; e];             % add zeros for partition size 1
partitions = [1 ; partitions(:)];	% add partition size 1

rs = signal(core(e), s);
a = achse(-log2(partitions));     		% create axis with arbitrary spacing
a = setname(a, 'ld r');
a2 = setname(achse(unit, 1, 1), 'Embedding dimension');
rs = setaxis(rs, 1, a);
rs = setaxis(rs, 2, a2);
rs = setplothint(rs, 'multigraph');
rs = addhistory(rs,  ['Computed correlation dimension']);
rs = addcommandlines(rs, 's = corrdim(s', bins);
rs = setyname(rs, 'ld C(r)');
rs = setlabel(rs, 'Scaling of D2');


function u = bsv_upwind ( a, b, alpha, beta, nu, n, output )

%*****************************************************************************80
%
%% BSV_UPWIND applies Newton's method to a discretized steady viscous Burgers equation.
%
%  Discussion:
%
%    An upwind scheme is used to combat the numerical oscillations that
%    can occur otherwise.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real A, B, the left and right endpoints.
%
%    Input, real ALPHA, BETA, the Dirichlet boundary values at the left
%    and right.
%
%    Input, real NU, the viscosity.  Normally, 0 < NU.
%
%    Input, integer N, the number of nodes to use between A and B.
%
%    Input, logical OUTPUT, is TRUE if printout is desired.
%
%    Output, real U(N), the computed discretized solution.
%
  if ( n < 2 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'BSV_UPWIND - Fatal error!\n' );
    fprintf ( 1, '  N < 2.\n' );
    error ( 'BSV_UPWIND - Fatal error!\n' );
  end
%
%  Set some iteration parameters.
%
  newton_step_max = 50;
  newton_resid_tol = sqrt ( eps );
  newton_step_tol = sqrt ( eps );
%
%  Use equally spaced nodes from A to B.
%
  dx = ( b - a ) / ( n - 1 );
%
%  The initial guess will be the linear interpolant to the boundary conditions.
%
  u = ( linspace ( alpha, beta, n ) )';
%
%  Prepare for the Newton iteration.
%
  J = sparse ( [], [], [], n, n, 3 * n );
  newton_step = 0;

  if ( output )
    fprintf ( 1, '\n' );
    fprintf ( 1, '  Step  ||F(U)||\n' );
    fprintf ( 1, '\n' );
  end

  while ( newton_step <= newton_step_max )

    f(1,1) = u(1) - alpha;

    f(2:n-1,1) = - nu * ( u(3:n) - 2.0 * u(2:n-1) + u(1:n-2) ) / ( dx^2 );
%
%  Massaging the results of FIND can be tedious.
%
    i = find ( 0.0 <= u(2:n-1) );
    i = i + 1;
    j = find ( u(2:n-1) < 0.0 );
    j = j + 1;

    f(i,1) = f(i,1) + 0.5 * ( u(i).^2 - u(i-1).^2 ) / dx;
    f(j,1) = f(j,1) + 0.5 * ( u(j+1).^2 - u(j).^2 ) / dx;

    f(n,1) = u(n) - beta;

    f_norm = norm ( f, inf );

    if ( output )
      fprintf ( 1, '  %4d  %g\n', newton_step, f_norm );
    end

    if ( f_norm < newton_resid_tol )
      break
    end
%
%  Define the Jacobian matrix.
%
    J(1,1) = 1.0;
    for i = 2 : n - 1
      if ( 0.0 <= u(i) )
        J(i,i-1) = - u(i-1) / dx        - nu / dx^2;
        J(i,i)   =   u(i)   / dx  + 2.0 * nu / dx^2;
        J(i,i+1) =                      - nu / dx^2;
      else
        J(i,i-1) =                      - nu / dx^2;
        J(i,i)   = - u(i)   / dx  + 2.0 * nu / dx^2;
        J(i,i+1) =   u(i+1) / dx        - nu / dx^2;
      end
    end
    J(n,n) = 1.0;
%
%  Solve the linear system J * du = -f to get the Newton update.
%
    du = J \ f;
    du_norm = norm ( du, inf );

    u_norm = norm ( u, inf );
    if ( du_norm < newton_step_tol * ( u_norm + 1.0 ) )
      break
    end

    u = u - du;
    newton_step = newton_step + 1;

  end

  if ( newton_step_max < newton_step )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'BSV_UPWIND - Warning!\n' );
    fprintf ( 1, '  The Newton iteration did not converge.\n' );
  end

  return
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright (C) 1995-2020 The Octave Project Developers
%
% See the file COPYRIGHT.md in the top-level directory of this
% distribution or <https://octave.org/copyright/>.
%
% This file is part of Octave.
%
% Octave is free software: you can redistribute it and/or modify it
% under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Octave 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 Octave; see the file COPYING.  If not, see
% <https://www.gnu.org/licenses/>.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% -*- texinfo -*-
% @deftypefn  {} {} cov (@var{x})
% @deftypefnx {} {} cov (@var{x}, @var{opt})
% @deftypefnx {} {} cov (@var{x}, @var{y})
% @deftypefnx {} {} cov (@var{x}, @var{y}, @var{opt})
% Compute the covariance matrix.
%
% If each row of @var{x} and @var{y} is an observation, and each column is
% a variable, then the @w{(@var{i}, @var{j})-th} entry of
% @code{cov (@var{x}, @var{y})} is the covariance between the @var{i}-th
% variable in @var{x} and the @var{j}-th variable in @var{y}.
% @tex
% $$
% \sigma_{ij} = {1 \over N-1} \sum_{i=1}^N (x_i - \bar{x})(y_i - \bar{y})
% $$
% where $\bar{x}$ and $\bar{y}$ are the mean values of @var{x} and @var{y}.
% @end tex
% @ifnottex
%
% @example
% cov (@var{x}) = 1/(N-1) * SUM_i (@var{x}(i) - mean(@var{x})) * (@var{y}(i) - mean(@var{y}))
% @end example
%
% @noindent
% where @math{N} is the length of the @var{x} and @var{y} vectors.
%
% @end ifnottex
%
% If called with one argument, compute @code{cov (@var{x}, @var{x})}, the
% covariance between the columns of @var{x}.
%
% The argument @var{opt} determines the type of normalization to use.
% Valid values are
%
% @table @asis
% @item 0:
%   normalize with @math{N-1}, provides the best unbiased estimator of the
% covariance [default]
%
% @item 1:
%   normalize with @math{N}, this provides the second moment around the mean
% @end table
%
% Compatibility Note:: Octave always treats rows of @var{x} and @var{y}
% as multivariate random variables.
% For two inputs, however, @sc{matlab} treats @var{x} and @var{y} as two
% univariate distributions regardless of their shapes, and will calculate
% @code{cov ([@var{x}(:), @var{y}(:)])} whenever the number of elements in
% @var{x} and @var{y} are equal.  This will result in a 2x2 matrix.
% Code relying on @sc{matlab}'s definition will need to be changed when
% running in Octave.
% @seealso{corr}
% @end deftypefn

function c = cov (x, y, opt)

if (nargin < 2)
    y = [];
end
if (nargin < 3)
    opt = 0;
end
if (nargin < 1 || nargin > 3)
    error('Usage: c = cov (x, y = [], opt = 0)');
end

if (~(isnumeric (x) || islogical (x)) || ~(isnumeric (y) || islogical (y)))
    error ('cov: X and Y must be numeric matrices or vectors');
end

if (ndims (x) ~= 2 || ndims (y) ~= 2)
    error ('cov: X and Y must be 2-D matrices or vectors');
end

if (nargin == 2 && isscalar (y))
    opt = y;
end

if (opt ~= 0 && opt ~= 1)
    error ('cov: normalization OPT must be 0 or 1');
end

% Special case, scalar has zero covariance
if (isscalar (x))
    if (isa (x, 'single'))
        c = single (0);
    else
        c = 0;
    end
    return;
end

if (isrow (x))
    x = x.';
end
n = size(x,1);

if (nargin == 1 || isscalar (y))
    %x = center (x, 1);
    x = bsxfun(@minus, x, mean (x, 1));
    c = x' * x / (n - 1 + opt);
else
    if (isrow (y))
        y = y.';
    end
    if (size(y,1) ~= n)
        error ('cov: X and Y must have the same number of observations');
    end
    %x = center (x, 1);
    %y = center (y, 1);
    x = bsxfun(@minus, x, mean (x, 1));
    y = bsxfun(@minus, y, mean (y, 1));
    c = x' * y / (n - 1 + opt);
end

end


function checkNNGradients(lambda)
%CHECKNNGRADIENTS Creates a small neural network to check the
%backpropagation gradients
%   CHECKNNGRADIENTS(lambda) Creates a small neural network to check the
%   backpropagation gradients, it will output the analytical gradients
%   produced by your backprop code and the numerical gradients (computed
%   using computeNumericalGradient). These two gradient computations should
%   result in very similar values.
%

if ~exist('lambda', 'var') || isempty(lambda)
    lambda = 0;
end

input_layer_size = 3;
hidden_layer_size = 5;
num_labels = 3;
m = 5;

% We generate some 'random' test data
Theta1 = debugInitializeWeights(hidden_layer_size, input_layer_size);
Theta2 = debugInitializeWeights(num_labels, hidden_layer_size);
% Reusing debugInitializeWeights to generate X
X  = debugInitializeWeights(m, input_layer_size - 1);
y  = 1 + mod(1:m, num_labels)';

% Unroll parameters
nn_params = [Theta1(:) ; Theta2(:)];
% Short hand for cost function
costFunc = @(p) nnCostFunction(p, input_layer_size, hidden_layer_size, ...
                               num_labels, X, y, lambda);
[cost, grad] = costFunc(nn_params);
numgrad = computeNumericalGradient(costFunc, nn_params);

% Visually examine the two gradient computations.  The two columns
% you get should be very similar.
disp([numgrad grad]);
fprintf(['The above two columns you get should be very similar.\n' ...
         '(Left-Your Numerical Gradient, Right-Analytical Gradient)\n\n']);

% Evaluate the norm of the difference between two solutions.
% If you have a correct implementation, and assuming you used EPSILON = 0.0001
% in computeNumericalGradient.m, then diff below should be less than 1e-9
diff = norm(numgrad-grad)/norm(numgrad+grad);

fprintf(['If your backpropagation implementation is correct, then \n' ...
         'the relative difference will be small (less than 1e-9). \n' ...
         '\nRelative Difference: %g\n'], diff);

end


function [ f, g, H ] = opt15_fgh ( x, flag )

%*****************************************************************************80
%
%% OPT15_FGH evaluates F, G and H for test case #15.
%
%  Discussion:
%
%    This example, if started at X = (-1,0), seems to get stuck.
%
%  Modified:
%
%    09 January 2008
%
%  Author:
%
%    Jeff Borggaard,
%    Gene Cliff,
%    Virginia Tech.
%
%  Reference:
%
%    John Dennis, Robert Schnabel,
%    Numerical Methods for Unconstrained Optimization
%    and Nonlinear Equations,
%    SIAM, 1996,
%    ISBN13: 978-0-898713-64-0,
%    LC: QA402.5.D44.
%
%  Parameters:
%
%    Input, real X(2), the evaluation point.
%
%    Input, string FLAG, indicates what must be computed.
%    'f' means only the value of F is needed,
%    'g' means only the value of G is needed,
%    'all' means F, G and H (if appropriate) are needed.
%    It is acceptable to behave as though FLAG was 'all'
%    on every call.
%
%    Output, real F, the optimization function.
%
%    Output, real G(2,1), the gradient column vector.
%
%    Output, real H(2,2), the Hessian matrix.
%
  n = length ( x );

  if ( n ~= 2 )
    fprintf ( '\n' );
    fprintf ( 'OPT15_FGH - Fatal error!\n' );
    fprintf ( '  The input vector X should have length 2.\n'),
    fprintf ( '  Instead, it has length = %d.\n', n );
    keyboard
  end

  f = - ( x(1) + x(2) ) ...
      + 0.5 * ( 1 - ( x(1)^2 + x(2)^2 ) ) ...
      + 5.0 * ( 1 - ( x(1)^2 + x(2)^2 ) )^2;

  g(1,1) = -1 - 21 * x(1) + 20 * x(1) * ( x(1)^2 + x(2)^2 );
  g(2,1) = -1 - 21 * x(2) + 20 * x(2) * ( x(1)^2 + x(2)^2 );

  H = zeros(n,n);

  H(1,1) = - 21 + 60 * x(1)^2 + 20 * x(2)^2;
  H(1,2) = 40 * x(1) * x(2);

  H(2,1) = 40 * x(1) * x(2);
  H(2,2) =  - 21 + 20 * x(1)^2 + 60 * x(2)^2;


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  In this script, we perform phase transition analysis
%  of Orthogonal matching pursuit.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
close all;
clear all;
clc;
rng('default');
% Create the directory for storing results
[status_code,message,message_id] = mkdir('bin');
target_file_path = 'bin/mmv_phase_transition_noiseless_s_16.mat';
N = 256;
S = 16;
pta = spx.pursuit.PhaseTransitionAnalysis(N);
% pta.NumTrials = 100;
dict_model = @(M, N) spx.dict.simple.gaussian_dict(M, N);
data_model = @(N, K) spx.data.synthetic.SparseSignalGenerator(N, K, S).gaussian;
recovery_solver = @(Phi, K, y) spx.pursuit.joint.CoSaMP(Phi, K).solve(y).Z;
pta.run(dict_model, data_model, recovery_solver);
pta.save_results(target_file_path);


function coeffs = ellipseCartesianCoefficients(elli)
%ELLIPSECARTESIANCOEFFICIENTS Cartesian coefficients of an ellipse.
%
%   COEFFS = ellipseCartesianCoefficients(ELLI)
%   Computes the cartesian coefficients of the ellipse ELLI, given by:
%     COEFFS = [A B C D E F]
%   such that the points on the ellipse follow:
%     A*X^2 + B*X*Y + C*Y^2 + D*X + E*Y + F = 0
%
%   Example
%     elli = [30 20 40 20 30];
%     coeffs = ellipseCartesianCoefficients(elli)
%     elli2 = createEllipse(coeffs)
%     elli2 =
%        30.0000   20.0000   40.0000   20.0000   30.0000
%
%   See also
%     ellipses2d, createEllipse, equivalentEllipse
%

% ------
% Author: David Legland
% E-mail: david.legland@inrae.fr
% Created: 2022-09-05, using Matlab 9.12.0.1884302 (R2022a)
% Copyright 2022 INRAE - BIA Research Unit - BIBS Platform (Nantes)

% retrieve ellipse center and squared radiusses
xc = elli(1);
yc = elli(2);
a2 = elli(3)^2;
b2 = elli(4)^2;

% pre-compute trigonometric functions (angle is in degrees)
cot = cos(elli(5) * pi / 180);
sit = sin(elli(5) * pi / 180);

% identification of each parameter
A = a2 * sit * sit + b2 * cot * cot;
B = 2 * (b2 - a2) * sit * cot;
C = a2 * cot * cot + b2 * sit * sit;
D = - 2 * A * xc - B * yc;
E = - B * xc - 2 * C * yc;
F = A * xc * xc + B * xc * yc + C * yc * yc - a2 * b2;

% concatenate into a single row vector
coeffs = [A B C D E F];


function A = create_3d_linear_interp_matrix(T, varargin)
% A = create_2d_bilinear_interp_matrix(T, [szin])
% T should contain displacements in pixels
% size(T) = [N1, N2, N3, 2]
%
% x_def = A * x(:);

sz = [size(T, 1), size(T, 2), size(T, 3)];

if numel(varargin) == 1
    szin = varargin{1};
else
    szin = sz;
end

npixin = szin(1) * szin(2) * szin(3);
npixout = sz(1) * sz(2) * sz(3);

[m1, m2, m3] = ndgrid(1:sz(1), 1:sz(2), 1:sz(3));
TT = T + cat(4, m1, m2, m3);

r = cell(3, 1);
rk = cell(3, 1);
for i = 1 : 3
    r{i} = floor(TT(:, :, :, i));
    rk{i} = TT(:,:,:, i) - r{i};
end

%
ssh =  [0, 0, 0, 0, 1, 1, 1, 1;...
        0, 1, 0, 1, 0, 1, 1, 0;...
        0, 0, 1, 1, 0, 0, 1, 1;];
A = sparse(npixout, npixin);
for i = 1 : 8
    t = 1 : npixout;
    s = ones(numel(rk{1}), 1);
    rid = cell(3, 1);
    for j = 1 : 3
        rid{j} = r{j} + ssh(j, i);
        if ssh(j, i) == 1
            tmps = rk{j};
        else
            tmps = 1 - rk{j};
        end
        s = s .* tmps(:);
    end
    idx = (rid{1} <= szin(1)) & (rid{1} >= 1) & (rid{2} <= szin(2)) & (rid{2} >= 1) & (rid{3} <= szin(3)) & (rid{3} >= 1);
    for j = 1 : 3
        rid{j} = rid{j}(idx);
    end
    s = s(idx);
    t = t(idx);
    tmp = sparse(t, rid{1} + szin(1) * (rid{2} - 1) + szin(2)*szin(1) * (rid{3} - 1), s, npixout, npixin);
    A = A + tmp;
end

end


function	[xdata,parm] = normalize_data(xdata,norm_mode,parm)
% Normalize data
% --- Usage
%  1. Normalize data and set mean & norm to 'parm'
%  [xdata, parm] = normalize_data(xdata)
%  [xdata, parm] = normalize_data(xdata, norm_mode)
%
%  2.  Normalize data using 'parm'
%  [xdata] = normalize_data(xdata, norm_mode, parm)
%
% --- Input
% xdata : [Xdim x Nsample x Ntrial]
% --- Optional input
% norm_mode : normalization mode
%           = 0: zero mean & std is calculated
%           = 1: zero mean & normalized [Default]
%           = 2: normalized (mean is unchanged)
%
% parm  : if the following fields exist, these values are used for mean & std
%    parm.xmean = mean of xdata
%    parm.xnorm = std (root of variance) of xdata
%
% --- Output
%    parm.xmean = mean of xdata                    [Xdim x 1]
%    parm.xnorm = std (root of variance) of xdata  [Xdim x 1]
%  if norm_mode == 0,
%     xdata : zero mean
%  if norm_mode = 1
%     xdata : zero mean & normalized
%  if norm_mode = 2
%     xdata : normalized  (mean is unchanged)
%
%  if 'parm.xmean' & 'parm.xnorm' are given,
%     these values are used as mean & std
%
% 2007/1/27 M. Sato
% 2007-4-8 Modified by M. Sato
% 2009-11-2 Modified by M. Sato, norm_mode = 2 is added

if ~exist('norm_mode','var'),
	norm_mode = 1;
end
if ~exist('parm','var'),
	parm = [];
end

[Xdim,Ndata,Ntrial] = size(xdata);

xdata = reshape(xdata, [Xdim, Ndata*Ntrial]);

% Mean
if ~isfield(parm,'xmean') | isempty(parm.xmean)
	parm.xmean = sum(xdata,2)/(Ndata*Ntrial);
end

xdim = length(parm.xmean);

if xdim > Xdim,
	parm.xmean = parm.xmean(1:Xdim);
elseif xdim < Xdim,
	parm.xmean = repmat(parm.xmean,[Xdim/xdim 1]);
end

% Zero mean
if norm_mode < 2
% 	xdata = xdata - repmat(parm.xmean, [1 Ndata]);
	xdata = repadd( double(xdata) , - double(parm.xmean) );
end

% Variance
if ~isfield(parm,'xnorm') | isempty(parm.xnorm)
	parm.xnorm = sqrt(sum(xdata.^2,2)/((Ndata-1)*Ntrial)); % modified by TH: use unbiased variance
end

xdim = length(parm.xnorm);

if xdim > Xdim,
	parm.xnorm = parm.xnorm(1:Xdim);
elseif xdim < Xdim,
	parm.xnorm = repmat(parm.xnorm,[Xdim/xdim 1]);
end

% Normalize amplitude
if norm_mode > 0
% 	xdata = xdata./repmat(parm.xnorm, [1 Ndata]);
	xdata = repmultiply( double(xdata) , 1./double(parm.xnorm) );
end

xdata = reshape(xdata, [Xdim, Ndata, Ntrial]);


function y = mat2lpc(x, f)
%MAT2LPC Compresses a matrix using 1-D lossles predictive coding.
%   Y = MAT2LPC(X, F) encodes matrix X using 1-D lossless predictive
%   coding. A linear prediction of X is made based on the
%   coefficients in F. If F is omitted, F = 1 (for previous pixel
%   coding) is assumed. The prediction error is then computed and
%   output as encoded matrix Y.
%
%   See also LPC2MAT.

%   Copyright 2002-2004 R. C. Gonzalez, R. E. Woods, & S. L. Eddins
%   Digital Image Processing Using MATLAB, Prentice-Hall, 2004
%   $Revision: 1.4 $  $Date: 2003/06/18 12:38:39 $

error(nargchk(1, 2, nargin));       % Check input arguments
if nargin < 2                       % Set default filter if omitted
    f = 1;
end

x = double(x);                      % Ensure double for computations
[m, n] = size(x);                   % Get dimensions of input matrix
p = zeros(m, n);                    % Init linear prediction to 0
xs = x;     zc = zeros(m, 1);       % Prepare for input shift and pad

for j = 1:length(f)                 % For each filter coefficient ...
    xs = [zc xs(:, 1:end - 1)];     % Shift and zero pad x
    p = p + f(j) * xs;              % Form partial prediction sums
end

y = x - round(p);                   % Compute the prediction error


function y0 = oddchebser0 ( x, coef, nc )

%*****************************************************************************80
%
%% ODDCHEBSER0 evaluates an odd Chebyshev series.
%
%  Discussion:
%
%    This function implements Clenshaw's modification of  his algorithm
%    for odd series.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 April 2014
%
%  Author:
%
%    Manfred Zimmer
%
%  Reference:
%
%    Charles Clenshaw,
%    Mathematical Tables, Volume 5,
%    Chebyshev series for mathematical functions,
%    London, 1962.
%
%  Parameters:
%
%    Input, real X, the evaluation point.
%    -1 <= X <= +1.
%
%    Input, real COEF(NC), the Chebyshev series.
%
%    Input, integer NC, the number of terms in the series.
%    0 < NC.
%
%    Output, real Y0, the value of the Chebyshev series at X.
%
  b0 = coef(nc);
  b1 = 0.0;
  b2 = 0.0;

  x2 = 4.0 * x * x - 2.0;

  for i = nc - 1 : -1 : 1

    b2 = b1;
    b1 = b0;
    b0 = coef(i) - b2 + x2 * b1;

  end

  y0 = ( b0 - b1 ) * x;

  return
end


function [y, Fout]=SincResample(xin, npoints, Fin, shift, mode)
% SincResample resamples signals to arbitrary lengths/frequencies and can
% timeshift them.
%
% SincResample can be faster than INTERP or RESAMPLE when X contains many
% relatively short data columns.
%
%
% Example:
% [Y, FOUT]=SincResample(X, NPOINTS, FIN, SHIFT, MODE)
%
% X is a vector or M x N  matrix where each column represents a signal.
% NPOINTS is the number of points required in each column after
% resampling.
% FIN (if supplied) is the sampling rate in X (default 1 samples/sec).
% SHIFT (if supplied) is the time (in seconds) to shift the points at which
% interpolation will be done (default 0). SHIFT should be between ą(1/Fin).
% SHIFT can be used to synchronize signals separated by up to ą(1/Fin)
% in time.
% MODE (if supplied) is a string:
%           'sinc' to use a hamming-windowed sinc function (default)
%           'lanczos' for a 3-lobed Lanczos function
%
% Y is the resulting M x NPOINTS matrix formed by resampling. The time
% of the first sample in each column of Y is shifted by SHIFT seconds
% relative to those in X.
% FOUT is the effective sample rate for output Y (normalised to FIN=1 if
% FIN is not supplied on input).
%
% If X is a bandlimited (filtered) signal containing components at
% DC - 0.5Fs where Fs is the sample rate, SincResample will return
% the signal that would have been seen with a higher sampling rate
% (and the same filter settings). The algorithm depends on the fact that
% the bandlimited signal is completely defined when sampling at Fs.
%
% SincResample returns the data convolved with a set of  time-shifted
% windowed sinc functions, one for each of the samples [1..size(x,1)]
% in the input signal. End-effects are reduced by adding a reflected
% and mirrored copy of the data at the beginning and end of each column
% before resampling.
%
% Note that points at the end of Y (and/or beginning if SHIFT is negative)
% will be extrapolated beyond the boundaries of X.
%
% SincResample is a generalization of the method used in Blanche &
% Swindale (2006).
%
% See also e.g. interp & resample (in the Signal Processing Toolbox) and
% the sinc online documentation.
%
% References:
% T.Blanche & N.V.Swindale (2006)
% Nyquist interpolation improves neuron yield in multiunit recordings
% Journal of Neuroscience Methods 155, 81-91 LinkOut
%
% also
%
% K. Turkowski, Filters for common resampling tasks LinkOut
%
% Toolboxes required: None
%
% Author: Malcolm Lidierth 07/06
% Copyright Š Kings College London 2006-8
%
% Acknowledgements: Steve Alty for comments
%
% Revisions: 10.07  Argument checks tidied (ML)
%            02.08  End-effect minimization now relects and mirrors data
%                   instead of simply reflecting it. This improves the
%                   slopes at the end and reduces the behaviour described at
%                   http://www.dsprelated.com/showmessage/79676/2.php
%                   (ML)
%            02.08  Mode option added (ML)

% Argument checks
if nargin<2
    y=[];
    Fout=0;
    return
end

if nargin<=2
    % Default
    Fin=1;
end

if nargin<=3
    % Zero shift default
    shift=0;
end

if nargin<=4
    % Set sinc as default
    mode='sinc';
end

if Fin==0
    error('SincResample: Fin specified as zero');
end

if abs(shift)>=1/Fin
    error('SincResample: shift must be less than 1/Fin');
end

if rem(npoints,1)~=0
    error('SincResample: npoints must be a whole number');
end

% Main routine
% Prepend and append a reflected and mirrored copy of the data
% to minimize end transients:
% Change 22.02.08: note change from reflected only

if isvector(xin)
    % Force column vector if row input
    xin=xin(:);
end

x=zeros(size(xin,1)*3, size(xin,2));
for k=1:size(xin,2)
    x(2:end-1,k)=[2*xin(1,k)-xin(end:-1:2,k);...
        xin(:,k);...
        2*xin(end,k)-xin(end-1:-1:1,k)];
    x(1,k)=2*x(1,k)-x(2,k);
    x(end,k)=2*x(end,k)-x(end-1,k);
end
clear('xin');
np=npoints*3;

% A column vector of sample times for x  - assume unit spacing and zero
% base
len=size(x,1);
t=(0:len-1)';

% times at which to interpolate data - based on spacing in t.
% ts will be a [npoints by size(x,1)] matrix
ts=(0:(max(t)+1)/np:(np-1)/(np/len))';
ts=(ts(:,ones(size(t)))-t(:,ones(size(ts)))');

% Hamming window
N=size(ts,2);
if N==1 || strcmp(mode, 'lanczos');
    w=1;
else
    th=ts+N-1;
    w=0.54-0.46*cos((2*pi*th/max(th(:)))) ;
end

% Add shift in multiples of a sampling interval i.e. shift/(1/Fin)
ts=ts+(shift*Fin);

switch mode
    case 'lanczos'
        % Generate Lanczos functions and calculate output
        y=lanczos(ts)*x;
    case 'sinc'
        % Generate sinc functions, apply Hamming window if w~=1 and
        % calculate output.
        y=sinc(ts).*w*x;
    otherwise
        error('mode should be ''sinc'' or ''lanczos''');
end

% Throw away what is not needed
y=y(size(y,1)/3+1:(size(y,1)/3)+(size(y,1)/3),:);
Fout=Fin*npoints/(len/3);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DEBUG Display the data - UNCOMMENT text below to display results
% x=x(size(x,1)/3+1:(size(x,1)/3)+(size(x,1)/3),:);
% debugdisplay(x, y, Fin, Fout, shift)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
return
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function y=sinc(x)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
i=find(x==0);
x(i)=1;
y=sin(pi*x)./(pi*x);
y(i)=1;
return
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function y=lanczos(x)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
n=3;
y=sinc(x).*sinc(x/n);
y(abs(x)>=n)=0;
return
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function debugdisplay(x, y, Fin, Fout, shift) %#ok<DEFNU>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Interp requires the Signal Processing Toolbox. The output of interp will
% be shown if Fout is an integer multiple of Fin.
% Note that shift is not applied to interp
% Sample times in seconds
t1= 0 : 1/Fin : (size(x,1)-1)/Fin;
t2= 0 : 1/Fout : (size(y,1)-1)/Fout;
if rem(Fout,Fin)==0
    y3=interp(x(:,1),Fout/Fin);
    t3=linspace(0,max(t2),size(y3,1));
end
t2=t2+shift;
handle=gca(figure);
xlabel(handle,'Time (seconds)');
for i=1:size(x,2)
    if ~ishandle(handle)
        break;
    end
    if rem(Fout,Fin)==0
        y3=interp(x(:,i),Fout/Fin);
        plot(handle,t1,x(:,i),'-bo',t2,y(:,i),'r-x',t3,y3,'g:s');
        xlim([min([0;min(t2)]) max([max(t3);max(t2);max(t1)])]);
    else
        plot(handle,t1,x(:,i),'-bo',t2,y(:,i),'r-x');
        xlim([min([0;min(t2)]) max([max(t2);max(t1)])]);
    end
    xlabel(handle,'Time (seconds)');
    title('Close the figure window to exit this loop');
    if rem(Fout,Fin)==0
        legend('Original','SincResample','MATLAB Interp (no shift)');
    else
        legend('Original','SincResample');
    end
    drawnow();
    pause(.1);
end
return
end


function [ a, b ] = assemble_fem ( x_num, x, element_num, element_node, ...
  quad_num, t, k_fun, rhs_fun )

%*****************************************************************************80
%
%% ASSEMBLE_FEM assembles the finite element stiffness matrix.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 February 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer X_NUM, the number of nodes.
%
%    Input, real X(X_NUM), the coordinates of nodes.
%
%    Input, integer ELEMENT_NUM, the number of elements.
%
%    Input, integer ELEMENT_NODE(2,ELEMENT_NUM);
%    ELEMENT_NODE(I,J) is the global index of local node I in element J.
%
%    Input, integer QUAD_NUM, the number of quadrature points used in assembly.
%
%    Input, real T, the current time.
%
%    Input, real K_FUN(), a function to evaluate the heat conductivity.
%
%    Input, real RHS_FUN(), a function to evaluate the right hand side.
%
%    Output, sparse real A(X_NUM,X_NUM), the finite element stiffness matrix.
%
%    Output, real B(X_NUM), the right hand side.
%
%  Local parameters:
%
%    Local, real BI, DBIDX, the value of some basis function
%    and its first derivative at a quadrature point.
%
%    Local, real BJ, DBJDX, the value of another basis
%    function and its first derivative at a quadrature point.
%

%
%  Initialize the arrays.
%
  b = zeros ( x_num, 1 );
  a = sparse ( x_num, x_num );
%
%  Get the quadrature weights and nodes.
%
  [ reference_w, reference_q ] = quadrature_set ( quad_num );
%
%  Consider each ELEMENT.
%
  for element = 1 : element_num

    element_x(1:2,1) = x(element_node(1:2,element));

    element_q(1:quad_num,1) = reference_to_physical ( element, element_node, ...
      x, quad_num, reference_q );

    element_area = element_x(2) - element_x(1);

    element_w(1:quad_num,1) = ( element_area / 2.0 ) * reference_w(1:quad_num);
%
%  Consider the QUAD-th quadrature point in the element.
%
    k_value = k_fun ( quad_num, element_q, t );
    rhs_value = rhs_fun ( quad_num, element_q, t );

    for quad = 1 : quad_num
%
%  Consider the TEST-th test function.
%
%  We generate an integral for every node associated with an unknown.
%
      for i = 1 : 2

        test = element_node(i,element);

        [ bi, dbidx ] = basis_function ( test, element, x, 1, element_q(quad) );

        b(test) = b(test) + element_w(quad) * rhs_value(quad) * bi;
%
%  Consider the BASIS-th basis function, which is used to form the
%  value of the solution function.
%
        for j = 1 : 2

          basis = element_node(j,element);

          [ bj, dbjdx ] = basis_function ( basis, element, x, 1, element_q(quad) );

          a(test,basis) = a(test,basis) + element_w(quad) * ( ...
            + k_value(quad) * dbidx * dbjdx );

        end

      end

    end

  end

  return
end


function val=perm(A,boolRowsSkip,boolColsSkip)
%%PERM Calculate the matrix permanent allowing for rows and columns to be
%      skipped if desired (operate on a submatrix). The permanent is
%      equivalent to calculating the determininant in the standard
%      summation manner taught in school, except all of the minus signs are
%      replaced with plus signs. Permanents play a role in combinatorics
%      and the ability to skip rows and columns can be useful when using
%      permanents to compute target-measurement association probabilities.
%
%INPUTS: A An mXn matrix. If m<=n, then the standard matrix permanent is
%         found. If m>n, then the permanent of A' is found to be consistent
%         with the permanents of A and A' being equal in square matrices.
%         Empty matrices have a permanent of one by definition.
% boolRowsSkip An optional list of rows in A that should be skipped when
%         computing the matrix permanent. This is an mX1 or 1Xm boolean
%         vector where a 1 means that row should be skipped. If omitted or
%         an empty matrix is passed, no rows are skipped.
% boolColsSkip An optional list of columns in A that should be skipped when
%         computing the matrix permanent. This is an nX1 or 1Xn boolean
%         vector where a 1 means that column should be skipped. If omitted
%         or an empty matrix is passed, no columns are skipped.
%
%OUTPUTS: val The matrix permanent of A, omitting any rows or columns as
%             necessary.
%
%Whereas polynomial-time algorithms exist for calculating determinants, it
%was proven in [1] that matrix permanents can not be computed in polynomial
%time unless P=NP. However, efficient non-polynomial time algorithms exist.
%This file implements the method in theorem 4.1 on page 26 in Chapter 2 of
%[2] when dealing with general rectangular matrices. When dealing with
%square matrices, an algorithm based on PERMAN from Chapter 23 of [3] is
%used, because it is more efficient and appears to be less susceptible to
%finite precision errors. When skipping rows or columns, only Ryser's
%algorithm is used.
%
%EXAMPLE 1:
%Suppose that one is given a boolean matrix where 1 indicates that a target
%gates with a measurement and a 0 indicates that it does not gate. To deal
%with the possibility of missed detections, one often adds dummy
%measurements, one per target, each gating with only one target. The total
%number of possible target-measurement (and missed detection) assignments
%equals the permanent of the matrix.
% %For 5 targets, 5 measurements (everything gates) and no missed
% %detections
% perm(ones(5,5))
% %One gets 120, there are 120 possible assignments (factorial(5)).
% %For 5 targets target where everything gates with the possibility of
% %missed detections, one has
% perm([ones(5,5),eye(5)])
% %Leading to 1546 possible assignments to measurements and missed
% %detections.
%
%EXAMPLE 2:
%This is an example with skip lists.
% numRow=12;
% numCol=4;
% A=magic(max(numRow,numCol));
% A=A(1:numRow,1:numCol);
% boolRowsSkip=false(numRow,1);
% boolColsSkip=false(numCol,1);
% boolRowsSkip(3)=true;
% boolColsSkip([1,4])=true;
% perm(A,boolRowsSkip,boolColsSkip)
% perm(A',boolColsSkip,boolRowsSkip)
% %The permanent values should both be 494938.
%
%REFERENCES:
%[1] L. G. Valiant, "The complexity of computing the permanent,"
%    Theoretical Computer Science, vol. 8, no. 2, pp. 189-201, 1979.
%[2] H. J. Ryser, Combinatorial Mathematics, ser. The Carus Mathematical
%    Monographs. The Mathematical Association of America, 1963, no. 14.
%[3] A. Nijenhuis and H. S. Wilf, Combinatorial Algorithms for Computers
%    and Calculators, 2nd ed. New York: Academic press, 1978.
%
%October 2014 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

    if(isempty(A))
        %Empty matrices have a permanent of 1 by definition.
        val=1;
        return;
    elseif(numel(A)==1)
        %Scalar values have a permanent equal to that value.
        val=A;
        return;
    end

    m=size(A,1);
    n=size(A,2);

    %Use a modified version of Ryser's algorithm if skip lists are
    %provided.
    if(nargin>1)
        mTotal=m;
        nTotal=n;
        if(nargin<3||isempty(boolColsSkip))
            boolColsSkip=false(nTotal,1);
        end

        if(isempty(boolRowsSkip))
            boolRowsSkip=false(mTotal,1);
        end

        numRowsSkipped=sum(boolRowsSkip);
        numColsSkipped=sum(boolColsSkip);

        m=mTotal-numRowsSkipped;
        n=nTotal-numColsSkipped;

        %Empty matrices have a permanent of 1 by definition.
        if(isempty(A)||m==0||n==0)
            val=1;
            return;
        end

        if(m>n)
            A=A';
            temp=m;
            m=n;
            n=temp;

            temp=mTotal;
            mTotal=nTotal;
            nTotal=temp;

            temp=boolRowsSkip;
            boolRowsSkip=boolColsSkip;
            boolColsSkip=temp;
        end

        %Set the mapping of indices of the rows in the submatrix to indices in
        %the full matrix.
        rows2Keep=zeros(m,1);%Allocate space
        cumSkip=0;
        curIdx=1;
        for curRow=1:mTotal
            if(boolRowsSkip(curRow)==true)
                cumSkip=cumSkip+1;
                continue;
            else
                rows2Keep(curIdx)=curIdx+cumSkip;
                curIdx=curIdx+1;
            end
        end

        %Set the mapping of indices of the columns in the submatrix to indices in
        %the full matrix.
        cols2Keep=zeros(n,1);%Allocate space
        cumSkip=0;
        curIdx=1;
        for curCol=1:nTotal
            if(boolColsSkip(curCol)==true)
                cumSkip=cumSkip+1;
                continue;
            else
                cols2Keep(curIdx)=curIdx+cumSkip;
                curIdx=curIdx+1;
            end
        end

        binomTerm=1;
        val=0;
        for x=0:(m-1)
            val=val+SigmaSSkip(A,n-m+x,rows2Keep,cols2Keep)*binomTerm;

            binomTerm=binomTerm*(1-m+n+x)/(1+x)*(-1);
        end

        return;
    end

    if(m~=n)%Use Ryser's algorithm
        if(m>n)
            A=A';
            temp=m;
            m=n;
            n=temp;
        end

        binomTerm=1;
        val=0;
        for x=0:(m-1)
            val=val+SigmaS(A,n-m+x)*binomTerm;

            binomTerm=binomTerm*(1-m+n+x)/(1+x)*(-1);
        end
    else%If the matrix is square, use the PERMAN algorithm.
        x=zeros(n,1);%Temporary storage space.
        p=0;

        for i=1:n
            sumVal=sum(A(i,:));
            x(i)=A(i,n)-sumVal/2;
        end

        sgn=-1;
        code=[];
        nCard=n-1;
        while(1)
            sgn=-sgn;
            prodVal=sgn;
            [code,nCard,isLast,j]=getNextGrayCode(code,nCard);

            if(nCard~=0)
                z=2*code(j)-1;
                x=x+z*A(:,j);
            end
            for i=1:n
                prodVal=prodVal*x(i);
            end
            p=p+prodVal;

            if(isLast)
                break;
            end
        end
        val=2*(2*mod(n,2)-1)*p;
    end
end

function val=S(A)
%This function gives us the product of the row sums of A.
    val=prod(sum(A,2));
end

function val=SigmaS(A,r)
    %This adds up all of the possible values of S(A) where r columns of A
    %have been replaced by zeros. We shall choose the
    %n-r columns of A that are NOT zero.
    n=size(A,2);
    combLen=n-r;
    curComb=1:combLen;
    val=0;
    while(~isempty(curComb))
        val=val+S(A(:,curComb));
        curComb=getNextCombo(curComb,n,1);
    end
end

function val=SigmaSSkip(A,r,rows2Keep,cols2Keep)
    %This adds up all of the possible values of S(A) where r columns of A
    %have been replaced by zeros. We shall choose the
    %n-r columns of A that are NOT zero.
    n=length(cols2Keep);
    combLen=n-r;
    curComb=0:(combLen-1);

    val=0;
    while(~isempty(curComb))
        val=val+S(A(rows2Keep,cols2Keep(curComb+1)));
        curComb=getNextCombo(curComb,n);
    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 [H,S]=create_CHS(A,B,C,N,M);
% CREATE_CHS Internal function to define matrices for MPC problem

% How many states
n=length(A);p=size(C,1);
[dummy,m]=size(B);

H=zeros(N*p,length(A));
S=zeros(N*p,N*m);

Acum=A;
for j=1:N,
  H(1+p*(j-1):p*j,:)=C*Acum;
  Acum=Acum*A;
end;

for j=1:N,
  Acum=eye(n);
  for k=j:-1:1,
    S(1+p*(j-1):p*j,1+m*(k-1):k*m)=C*Acum*B;
    Acum=Acum*A;
  end;
end;


function S = sample_mc_endstate(startprob, trans, endprob)
% SAMPLE_MC_ENDSTATE Generate a random sequence from a Markov chain until enter the endstate.
% seq = sample_mc(startprob, trans, endprob)

% add an end state
Q = size(trans,1);
transprob = zeros(Q,Q+1);
end_state = Q+1;
for i=1:Q
  for j=1:Q
    transprob(i,j) = (1-endprob(i)) * trans(i,j);
  end
  transprob(i,end_state) = endprob(i);
  %assert(approxeq(sum(transprob(i,:)), 1))
end

S = [];
S(1) = sample_discrete(startprob);
t = 1;
p = endprob(S(t));
stop = (S(1) == end_state);
while ~stop
  S(t+1) = sample_discrete(transprob(S(t),:));
  stop = (S(t+1) == end_state);
  t = t + 1;
end
S = S(1:end-1); % don't include end state


function kcoeff = kwiener_train(X,Y,s)
% FUNCTION kcoeff = kwiener_train(X,Y,param)
%   AUTHOR:    Makoto Yamada
%              (myamada@ism.ac.jp)
%   DATE:       12/25/07
%
%  DESCRIPTION:
%
%   This function compute the kernel Wiener filter (kernel Dependency
%   Estimation) using Canonical Correlation Analysis (CCA)
%   and outputs it in the abstract object "kcoeff".
%   The "kcoeff" object can then be used for finding pre-images.
%
%  INPUTS:
%
%            X:     "X" is a (n times N) dimensional input matrix,
%                   where "n" is the vector dimension and N is the number
%                    of samples.
%
%            Y:     "Y" is a (m times N) dimensional output matrix.
%                    where "m" is the vector dimension and N is the number
%                    of samples.
%
%            s:      "s" is a parameter for Gaussian kernel,
%                    exp(-norm(x - y)^2/s).
%
%  OUTPUTS:
%
%    kcoeff   :     The Kernel Wiener Filter object.
%
%
%  Example:
%              load usps; %loading USPS data
%              s = 256*0.7; %Gaussian Kernel Parameter
%              %Training Kernel Wiener Filter
%              kcoeff = kwiener_train(X,Y,s);
%
%  Reference:  1. J. Weston et.al. ``Kernel Dependency Estimation,'' NIPS
%                 2003
%
%              2. M. Yamada and M. R. Azimi-Sadjadi, ``Kernel Wiener Filter
%                 using Canonical Correlation Analysis Framework,''
%                 IEEE SSP'05, Bordeaux, France, July 17-20, 2005.
%
%              3. C. Cortes et.al. ``A General Regression Technique for
%                 Learning Transductions,'' ICML, Bonn, Germany, Aug 7-11.
%
%              4. M. Yamada and M. R. Azimi-Sadjadi, ``Kernel Wiener Filter
%                 with Distance Constraint,'' ICASSP,  Toulouse, France,
%                 May 14-19, 2006
%
%              5. Zhe Chen et.al, ``Correlative Learning: A Basis for Brain and Adaptive
%                 Systems,'' Wiley, Oct. 2007 (Section 4.6)

n = size(X,2); %Number of Training samples

%Kernel Computation (Gaussian Kernel)
disp('Computing the Gram Matrix of X');
Kx = kernelg(X,X,s);
disp('Computing the Gram Matrix of Y');
Ky = kernelg(Y,Y,s);

%Centering Matrix
J = eye(n) - 1/n*ones(n);
%Centering Kernel Gram Matrix
A = J*Kx*J;

%Computing the Kernel Wiener Filter (Kernel Dependency Estimation)
%Computing the first kernel Canonical Coordinate.
[F D] = eig(A);
Lambda = sqrt(abs(real(diag(D))));
[YY I]  = sort(-Lambda);

%Normalizing Eigenvectors.
for k = 1:n
    if Lambda(k) ~= 0
        F(:,k)=F(:,k)/Lambda(k);
    end
end

Lambda = -YY;
F      = F(:,I);
kcoeff.Df   = F;                 %First kernel Canonical mapping function.
kcoeff.lambda = Lambda;          %Eigenvalue of kernel CCA.

%Computing the second kernel Canonical Coordinate.
ry = rank(Ky);
[Uy Wy Vy] = svd(Ky);
invKy = Vy(:,1:ry)*inv(Wy(1:ry, 1:ry))*Uy(:,1:ry)';
kcoeff.Dg = invKy*Kx*J*kcoeff.Df; %Second kernel Canonical mapping function.

kcoeff.Kxt = kcoeff.Df'*Kx;

%Computing rank of kernel Wiener filter.
[temp1,temp2] = find(kcoeff.lambda > 0);

if sum(temp2) == size(kcoeff.Kxt,2)
    kcoeff.rnk = sum(temp2) -1;
else
    kcoeff.rnk = sum(temp2);
end

disp('Finished Kernel Wiener Estimation');


function output = runrmssd(rr)
% output = runrmssd(times, rr);
%   OVERVIEW:   calculates the rmssd: the square root of the mean
%               of the sum of the squares of the differences.
%   INPUT:      rr = a single row of rr interval data in seconds
%               times =  the time indices of the rr interval data (seconds)
%   OUTPUT:     output = rmssd
%   DEPENDENCIES
%   & LIBRARIES:    replaceOutliers.m
%                   AnnotationConversion.m
%   REFERENCE:
%	REPO:
%       https://github.com/cliffordlab/PhysioNet-Cardiovascular-Signal-Toolbox
%   SOURCE:     Adapted from Kaplan Tools
%               See: http://www.robots.ox.ac.uk/~gari/CODE/HRV/
%   AUTHORS:    Adriana Nicholson Vest, PhD
%   COPYRIGHT (C) 2016
%   LICENSE:
%%

leng = length(rr);

dif = diff(rr);

output = sqrt(mean(dif.*dif));

end


function de00 = deltaE2000(Labstd,Labsample)
% Based on the article:
% "The CIEDE2000 Color-Difference Formula: Implementation Notes,
% Supplementary Test Data, and Mathematical Observations,", G. Sharma,
% W. Wu, E. N. Dalal, Color Research and Application, vol. 30. No. 1, pp.
% 21-30, February 2005.
% available at http://www.ece.rochester.edu/~/gsharma/ciede2000/
kl = 1; kc=1; kh =1;
Lstd = Labstd(:,1)';
astd = Labstd(:,2)';
bstd = Labstd(:,3)';
Cabstd = sqrt(astd.^2+bstd.^2);
Lsample = Labsample(:,1)';
asample = Labsample(:,2)';
bsample = Labsample(:,3)';
Cabsample = sqrt(asample.^2+bsample.^2);
Cabarithmean = (Cabstd + Cabsample)/2;
G = 0.5* (1 - sqrt( (Cabarithmean.^7)./(Cabarithmean.^7 + 25^7)));
apstd = (1+G).*astd;
apsample = (1+G).*asample;
Cpsample = sqrt(apsample.^2+bsample.^2);
Cpstd = sqrt(apstd.^2+bstd.^2);
Cpprod = (Cpsample.*Cpstd);
zcidx = find(Cpprod == 0);
hpstd = atan2(bstd,apstd);
hpstd = hpstd+2*pi*(hpstd < 0);
hpstd((abs(apstd)+abs(bstd))== 0) = 0;
hpsample = atan2(bsample,apsample);
hpsample = hpsample+2*pi*(hpsample < 0);
hpsample((abs(apsample)+abs(bsample))==0) = 0;
dL = (Lsample-Lstd);
dC = (Cpsample-Cpstd);
dhp = (hpsample-hpstd);
dhp = dhp - 2*pi* (dhp > pi );
dhp = dhp + 2*pi* (dhp < (-pi) );
dhp(zcidx ) = 0;
dH = 2*sqrt(Cpprod).*sin(dhp/2);
Lp = (Lsample+Lstd)/2;
Cp = (Cpstd+Cpsample)/2;
hp = (hpstd+hpsample)/2;
hp = hp - ( abs(hpstd-hpsample)  > pi ) *pi;
hp = hp+ (hp < 0) *2*pi;
hp(zcidx) = hpsample(zcidx)+hpstd(zcidx);
Lpm502 = (Lp-50).^2;
Sl = 1 + 0.015*Lpm502./sqrt(20+Lpm502);
Sc = 1+0.045*Cp;
T = 1 - 0.17*cos(hp - pi/6 ) + 0.24*cos(2*hp) + 0.32*cos(3*hp+pi/30) ...
    -0.20*cos(4*hp-63*pi/180);
Sh = 1 + 0.015*Cp.*T;
delthetarad = (30*pi/180)*exp(- ( (180/pi*hp-275)/25).^2);
Rc =  2*sqrt((Cp.^7)./(Cp.^7 + 25^7));
RT =  - sin(2*delthetarad).*Rc;
klSl = kl*Sl;
kcSc = kc*Sc;
khSh = kh*Sh;
de00 = sqrt( (dL./klSl).^2 + (dC./kcSc).^2 + (dH./khSh).^2 + ...
    RT.*(dC./kcSc).*(dH./khSh) );
return


% function Cpsi = cwt_adm(type, opt)
%
% Calculate cwt admissibility constant int(|f(w)|^2/w, w=0..inf) as
% per Eq. (4.67) of [1].
%
% 1. Mallat, S., Wavelet Tour of Signal Processing 3rd ed.
%
%---------------------------------------------------------------------------------
%    Synchrosqueezing Toolbox
%    Authors: Eugene Brevdo (http://www.math.princeton.edu/~ebrevdo/)
%---------------------------------------------------------------------------------
function Cpsi = cwt_adm(type, opt)
    if nargin<2, opt=struct(); end
    switch type
      case 'sombrero',
        if ~isfield(opt,'s'), s = 1; else s = opt.s; end
        Cpsi = (4/3)*s*sqrt(pi);
      case 'shannon',
        Cpsi = log(2);
      otherwise
        psihfn = wfiltfn(type, opt);
        Cpsi = quadgk(@(x) (conj(psihfn(x)).*psihfn(x))./x, 0, Inf);
    end

    % Normalize
    Cpsi = Cpsi / (4*pi);
end


function [tm,T]=loctime(sig);
%LOCTIME Time localization caracteristics.
%	[TM,T]=LOCTIME(SIG) computes the time localization
%	caracteristics of signal SIG.
%
%	SIG is the signal.
%	TM  is the averaged time center.
%	T   is the time spreading.
%
%	Example :
%	 z=amgauss(160,80,50); [tm,T]=loctime(z)
%
%	See also LOCFREQ.

%	F. Auger, 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

[sigr,sigc]=size(sig);
if (sigc~=1),
 error('The signal must have 1 column');
else
 sig2=abs(sig).^2; sig2=sig2/mean(sig2);
 t=(1:sigr)';
 tm=mean(t.*sig2);
 T=2*sqrt(pi*mean((t-tm).^2 .* sig2));
end;