function matrix = genMatVIFE3DmgHcurl(A,mesh,fem,femI)
%% Generate global matrices and load vector of PPIFEM for 3D ellipic eq
%     -div(A grad u)  = f,    x\in \Omega
%      where A is a piecewise constant on Omega^+ and Omega^-.
% INPUTS:
% pde --- given data function from equation, e.g.
%         pde.A --- diffusion coefficient
%         pde.f --- right hand side function
%         pde.gD --- Dirichlet boundary value function
%         pde.one --- constant function 1.
% mesh --- mesh structure.
% fem --- global degree of freedom of FEM
% femI --- quadrature info on interface cells
% femIF --- quadrature info on interface faces, required in PPIFE.
% PPtype --- partial penalty type possible value
%            'N' : Nonsymmetric PPIFE (e = 1)
%            'S' : Symmetric PPIFE (e = -1)
%            'I' : Incomplete PPIFE (e = 0)
% OUTPUTS:
% matrix.S --- stiffness matrix (w/o boundary condition)
% matrix.E --- consistence matrix (w/o boundary condition)
% matrix.P --- penalty matrix (w/o boundary condition)
% matrix.A --- final FEM matrix (after boundary condition)
% matrix.rhsF --- load vector (w/o boundary condition)
% matrix.rhsE --- consistence vector (=0 if no interface face on boundary)
% matrix.rhsP --- penalty vector (=0 if no interface face on boundary)
% matrix.f --- final RHS matrix (after boundary condition)

% Last Modified: 08/07/2020 by Xu Zhang

%% 1. Stiffness Matrix
S = globMatrixVIFE3DStiff(A,mesh,femI,fem,fem);

Ndof = size(femI.p,1);
bdidx = zeros(Ndof,1);
isBdEdge = true(Ndof,1);
isBdEdge(femI.mapper) = false;
bdidx(isBdEdge) = 1;
Tbd = spdiags(bdidx,0,Ndof,Ndof);
T = spdiags(1-bdidx,0,Ndof,Ndof);
A = T*S*T + Tbd;

%% 5. Outputs
matrix = struct('A',A);


function result  = omp(Dict, X, K, epsilon, options)
    if(isobject(Dict))
        Dict = double(Dict);
    end
    if ~isa(Dict, 'double')
        error('Dict must be a double matrix');
    end
    if nargin < 4
        epsilon = 1e-3;
    end
    if nargin < 5
        options = struct;
    end
    if ~isfield(options, 'sparse_output')
        options.sparse_output = 1;
    end
    % Options for least squares
    ls_ls = 0;
    ls_chol = 1;
    if ~isfield(options, 'ls_method')
        options.ls_method = 'chol';
    end
    ls_method = ls_chol;
    if strcmp(options.ls_method,'ls')
        ls_method = ls_ls;
    elseif strcmp(options.ls_method, 'chol')
        ls_method = ls_chol;
    end
    if ~isfield(options, 'verbose')
        options.verbose = 0;
    end
    result = mex_omp_chol(Dict, X, K, epsilon, ...
        options.sparse_output,...
        ls_method, ...
        options.verbose);
end


function [solution, model] = solveCobraCPLEX(model, printLevel, basisReuse, conflictResolve, contFunctName, minNorm)
% Calls CPLEX to solve an LP or QP problem using the matlab API to cplex written by ILOG
%
% USAGE:
%
%    [solution, model] = solveCobraCPLEX(model, printLevel, basisReuse, conflictResolve, contFunctName, minNorm)
%
% INPUT:
%    model:              structure with mandatory and optional fields:
%
%                          * .A or .S: - `m` x `n` LHS matrix
%                          * .b - `m x 1` RHS vector
%                          * .c - `n x 1` Objective coeff vector
%                          * .lb - `n x 1` Lower bound vector
%                          * .ub - `n x 1` Upper bound vector
%                          * .osense - scalar Objective sense (-1 max, +1 min)
%                          * .rxns - (optional) cell array of reaction abbreviations (necessary for
%                            making a readable confilict resolution file).
%                          * .csense - (optional) Constraint senses, a string containting the constraint sense for
%                            each row in `A` ('E', equality, 'G' greater than, 'L' less than).
%                          * .LPBasis - (optional) Basis from previous solution of similar LP problem.
%                            See `basisReuse`
%
% OPTIONAL INPUTS:
%    printLevel:         Printing level in the CPLEX m-file and CPLEX C-interface.
%
%                          * 0 - Silent
%                          * 1 - Warnings and Errors
%                          * 2 - Summary information (Default)
%                          * 3 - More detailed information
%                          * > 10 - Pause statements, and maximal printing (debug mode)
%    basisReuse:         0 - Use this for one of solution of an LP (Default);
%                        1 - Returns a basis for reuse in the next LP i.e. outputs `model.LPBasis`
%    conflictResolve:    0 (Default);
%                        1 If LP problem is proven to be infeasible by CPLEX,
%                        it will print out a 'conflict resolution file',
%                        which indicates the irreducible infeasible set of
%                        equaltiy & inequality constraints that together,
%                        combine to make the problem infeasible. This is
%                        useful for debugging an LP problem if you want to
%                        try to resolve a constraint conflict
%    contFunctName:
%
%                        1. contFunctName = [] Use all default CLPEX control parameters, (Default);
%                        2.  contFunctName = someString e.g. 'someFunctionName'
%                        uses the user specified control parameters defined
%                        in `someFunctionName.m`;
%                        (see template function CPLEXParamSet for details).
%                        3. contFunctName = `cpxControl` structure (output from a file like `CPLEXParamSet.m`)
%    minNorm:            {(0), 1 , `n x 1` vector} If not zero then, minimise the Euclidean length
%                        of the solution to the LP problem. Gives the same objective,
%                        but minimises the square of flux. `minNorm` ~1e-6 should be
%                        high enough for regularisation yet keep the same objective
%
% OUTPUT:
%    solution:           Structure containing the following fields describing a LP solution:
%
%                          * .full:               Full LP solution vector
%                          * .obj:                Objective value
%                          * .rcost:              Lagrangian multipliers to the simple inequalties (Reduced costs)
%                          * .dual:               Lagrangian multipliers to the equalities
%                          * .nInfeas:            Number of infeasible constraints
%                          * .sumInfeas:          Sum of constraint violation
%                          * .stat:               COBRA Standardized solver status code:
%
%                            * 1 - Optimal solution
%                            * 2 - Unbounded solution
%                            * 0 - Infeasible
%                            * -1 - No solution reported (timelimit, numerical problem etc)
%                          * .origStat:           CPLEX status code. Use `cplexStatus(solution.origStat)` for
%                            more information from the CPLEX solver
%                          * .solver              solver used by `cplex`
%                          * .time                time taken to solve the optimization problem
%
% OPTIONAL OUTPUT:
%    model:              with field:
%
%                          * .LPBasis - When input basisReuse=1, we return a basis for reuse in the next LP
%
% CPLEX consists of 4 different LP solvers which can be used to solve sysbio optimization problems
% you can control which of the solvers, e.g. simplex vs interior point solver using the
% CPLEX control parameter cpxControl.LPMETHOD. At the moment, the solver is
% automatically chosen for you.
%
% .. Author: - Ronan Fleming 23 Oct  09  ILOG-CPLEX 12.1 via  matlab API

global CBT_LP_SOLVER
global CBT_MILP_SOLVER
global CBT_QP_SOLVER
global CBT_MIQP_SOLVER

% Note: Certain parts of the conflict resolution only work with tomlab cplex: http://tomwiki.com/CPLEX_Conflict_refiner
tomlabSelected = false;
if (strcmp(CBT_LP_SOLVER, 'tomlab_cplex') || strcmp(CBT_QP_SOLVER, 'tomlab_cplex') || strcmp(CBT_MILP_SOLVER, 'tomlab_cplex') || strcmp(CBT_MIQP_SOLVER, 'tomlab_cplex'))
    tomlabSelected = true;
end

if ~exist('printLevel','var')
    printLevel=0;
end
if ~exist('basisReuse','var')
    basisReuse=0;
end
if ~exist('conflictResolve','var')
    conflictResolve=0;
end

if ~exist('minNorm','var')
    minNorm=0;
end

if basisReuse
    if isfield(model,'LPBasis')
        basis=model.LPBasis;
        %use advanced starting information when optimization is initiated.
        %cpxControl.ADVIND=1;
    else
        basis=[];
    end
else
    basis=[];
    %do not use advanced starting information when optimization is initiated.
    cplex.Param.ADVIND=0;
end

if ~isfield(model,'A')
    if ~isfield(model,'S')
        error('Equality constraint matrix must either be a field denoted A or S.')
    end
    model.A=model.S;
end

if ~isfield(model,'csense')
    nMet=size(model.A);
    if printLevel>0
        fprintf('%s\n','Assuming equality constraints, i.e. S*v=b');
    end
    %assuming equality constraints
    model.csense(1:nMet,1)='E';
end

if ~isfield(model,'osense')
    %assuming maximisation
    model.osense=-1;
    if printLevel>0
        fprintf('%s\n','Assuming maximisation of objective');
    end
end

if size(model.A,2)~=length(model.c)
    error('dimensions of A & c are inconsistent');
end

if size(model.A,2)~=length(model.lb) || size(model.A,2)~=length(model.ub)
    error('dimensions of A & bounds are inconsistent');
end

%Conflict groups descriptor (cpxBuildConflict can be used to generate the input). Set this if
%conflict refinement is desired in the case that infeasibility is detected
%by CPLEX.
if conflictResolve
    if tomlabSelected
        [m_lin,n]=size(model.A);
        m_quad=0;
        m_sos=0;
        m_log=0;
        %determines how elaborate the output is
        mode='full';%'minimal';
        fprintf('%s\n%s\n','Building Structure for Conflict Resolution...','... this slows CPLEX down so should not be used for repeated LP');
        cpxBuildConflict(n,m_lin,m_quad,m_sos,m_log,mode);
    end
    prefix=pwd;
    suffix='CPLEX_conflict_file.txt';
end

% Initialize the CPLEX object
try
	cplex = Cplex('fba');
catch ME
	error('CPLEX not installed or licence server not up')
end

% Now populate the problem with the data
cplex.Model.sense = 'minimize';
if model.osense == 1
    %minimise linear objective
    cplex.Model.obj   = model.c;
else
    %maximise linear objective by reversing sign
    cplex.Model.obj   = - model.c;
end

cplex.Model.lb    = model.lb;
cplex.Model.ub    = model.ub;
cplex.Model.A     = model.A;

%cplex interface
if isfield(model,'csense')
    %set up constant vectors for CPLEX
    b_L(model.csense == 'E',1) = model.b(model.csense == 'E');
    b_U(model.csense == 'E',1) = model.b(model.csense == 'E');
    b_L(model.csense == 'G',1) = model.b(model.csense == 'G');
    b_U(model.csense == 'G',1) =  Inf;
    b_L(model.csense == 'L',1) = -Inf;
    b_U(model.csense == 'L',1) = model.b(model.csense == 'L');
    cplex.Model.lhs   = b_L;
    cplex.Model.rhs   = b_U;
else
    cplex.Model.lhs   = model.b;
    cplex.Model.rhs   = model.b;
end

%quadratic constraint matrix, size n x n
if sum(minNorm)~=0
    if length(minNorm)==1
        % same weighting of min norm for all variables
        cplex.Model.Q=model.osense*speye(length(model.c))*minNorm;
    else
        if length(minNorm)~=length(model.c)
            error('Either minNorm is a scalar, or is an n x 1 vector')
        else
            % individual weighting of min norm for all variables
            cplex.Model.Q=model.osense*spdiags(minNorm,0,length(model.c),length(model.c));
        end
    end
end

%set the solver parameters
if exist('contFunctName','var')
    if isstruct(contFunctName)
        cplex.Param=contFunctName;
    else
        if ~isempty(contFunctName)
            %calls a user specified function to create a CPLEX control structure
            %specific to the users problem. A TEMPLATE for one such function is
            %CPLEXParamSet
            %e.g. Param.lpmethod.Cur=0;
            cplex.Param=Param;
        end
    end
end

if printLevel==0
    cplex.DisplayFunc=[];
else
    %print level
    cplex.Param.barrier.display.Cur = printLevel;
    cplex.Param.simplex.display.Cur = printLevel;
    cplex.Param.sifting.display.Cur = printLevel;
end

%limit the processing to 3 threads
cplex.Param.threads.Cur = 3;

% Optimize the problem
cplex.solve();
solution.origStat   = cplex.Solution.status;

if printLevel>0 && solution.origStat~=1 && tomlabSelected
    %use tomlab code to print out exit meassage
    [ExitText,ExitFlag] = cplexStatus(solution.origStat);
    solution.ExitText=ExitText;
    solution.ExitFlag=ExitFlag;
    if any(model.c~=0)
        if isfield(cplex.Solution, 'objval')
            fprintf('\n%s%g\n',[ExitText ', Objective '], model.osense*cplex.Solution.objval);
        else
            fprintf('\n%s\n', ExitText);
        end
    end
end

if solution.origStat==1
    %extract the solution
    solution.obj        = model.osense*cplex.Solution.objval;
    solution.full       = cplex.Solution.x;
    solution.rcost      = cplex.Solution.reducedcost;
    solution.dual       = cplex.Solution.dual;
    solution.nInfeas    = NaN;
    solution.sumInfeas  = NaN;
    solution.solver     = cplex.Solution.method;
    solution.time       = cplex.Solution.time;
else
    solution.time=NaN;
    %conflict resolution
    if conflictResolve ==1
        cplex.refineConflict();
        cplex.writeConflict(suffix);
        if isfield(model,'mets') && isfield(model,'rxns')
            %this code reads the conflict resolution file and replaces the
            %arbitrary names with the abbreviations of metabolites and reactions
            [nMet,nRxn]=size(model.A);
            totAbbr=nMet+nRxn;
            conStrFind=cell(nMet+nRxn,1);
            conStrReplace=cell(nMet+nRxn,1);
            %only equality constraint rows
            for m=1:nMet
                conStrFind{m,1}=['c' int2str(m) ':'];
                conStrReplace{m,1}=[model.mets{m} ':  '];
            end
            %reactions
            for n=1:nRxn
                conStrFind{nMet+n,1}=['x' int2str(n) ' '];
                conStrReplace{nMet+n,1}=[model.rxns{n} ' '];
            end
            fid1 = fopen(suffix);
            fid2 = fopen(['COBRA_' suffix], 'w');
            while ~feof(fid1)
                tline{1}=fgetl(fid1);
                %replaces all occurrences of the string str2 within string str1
                %with the string str3.
                %str= strrep(str1, str2, str3)
                for t=1:totAbbr
                    tline= strrep(tline, conStrFind{t}, conStrReplace{t});
                end
                fprintf(fid2,'%s\n', tline{1});
            end
            fclose(fid1);
            fclose(fid2);
        else
            warning('Need reaction and metabolite abbreviations in order to make a readable conflict resolution file');
        end
        fprintf('%s\n',['Conflict resolution file written to: ' prefix filesep 'COBRA_' suffix]);
        fprintf('%s\n%s\n','The Conflict resolution file gives an irreducible infeasible subset ','of constraints which are making this LP Problem infeasible');
    else
        if printLevel>0
            fprintf('%s\n','No conflict resolution file. Perhaps set conflictResolve = 1 next time.');
        end
    end
end

% Try to give back COBRA Standardized solver status:
%           1   Optimal solution
%           2   Unbounded solution
%           0   Infeasible
%           -1  No solution reported (timelimit, numerical problem etc)
if solution.origStat==1
    solution.stat = 1;
else
    %use tomlab code to print out exit meassage
    if tomlabSelected
        [ExitText,ExitFlag] = cplexStatus(solution.origStat);
        solution.ExitText=ExitText;
        solution.ExitFlag=ExitFlag;
        if any(model.c~=0) && isfield(cplex,'Solution')
            if isfield(cplex.Solution,'x')
                fprintf('\n%s%g\n',[ExitText ', Objective '],  model.c'*cplex.Solution.x);
            end
        end
    end
    if solution.origStat==2
        solution.stat = 2;
    else
        if solution.origStat==3
            solution.stat = 0;
        else
            %this is a conservative view
            solution.stat = -1;
        end
    end
end

%return basis
if basisReuse
    model.LPBasis=basis;
end

if sum(minNorm)~=0 && printLevel>0
    fprintf('%s\n','This objective corresponds to a flux with minimum Euclidean norm.');
    if length(minNorm)==1
        fprintf('%s%d%s\n','The weighting for minimising the norm was ',minNorm,'.');
    else
        fprintf('%s%d%s\n','The sum of the weighting for minimising the norm was ',sum(minNorm),'.');
    end
    fprintf('%s\n','Check that the objective is the same without minimising the norm.');
end


function [post] = spm_mci_post (mcmc,M,U,Y,true_P)
% Estimate posterior density
% FORMAT [post] = spm_mci_post (mcmc,M,U,Y,true_P)
%
% mcmc          .inference = 'amc','ais','vl' or 'langevin'
%               .verbose = 0 or 1 to plot progress (default 0)
%               .maxits = max number of iterations for sampling
%               .init = init parameter values (default is prior mean)
% M             model structure
% U             inputs (shouldn't be empty)
% Y             data
% true_P        true parameters (if known)
%
% post          structure containing posterior (mean, samples etc)
%__________________________________________________________________________
% Copyright (C) 2014 Wellcome Trust Centre for Neuroimaging

% Will Penny
% $Id: spm_mci_post.m 6697 2016-01-27 14:57:28Z spm $

try, verbose=mcmc.verbose; catch, verbose=0; end
if nargin < 5 || isempty(true_P)
    tp=0;
else
    tp=1;
end

tic;
switch mcmc.inference,

    case 'ais',
        disp('Annealed Importance Sampling');
        disp(' ');

        mcmc.nsamp=mcmc.maxits;

        tic;
        post = spm_mci_ais (mcmc,M,U,Y);
        toc

        Nsamp=size(post.P,2);
        post.ind=[1:Nsamp];
        post.Ep=mean(post.P(:,post.ind)')';
        post.mcmc=mcmc;

        % Eigenrep needed for spm_mci_joint later
        M = spm_mci_minit (M);

    case 'multi-amc',
        disp('Multiple chains of Adaptive Monte Carlo');
        disp(' ');
        Nsamp=ceil(0.5*mcmc.J);
        Nscale=0;
        Ntune=Nsamp;
        mc = spm_mci_popdef (Nscale,Ntune,Nsamp);
        mc.verbose=verbose;

        MM{1}=M;
        UU{1}=U;

        for it=1:mcmc.maxits,
            % Loop over chains
            mcmc.init{1}=spm_normrnd(M.pE,M.pC,1);
            Psamp = spm_mci_pop (mc,MM,UU,Y);
            if it ==1
                P=Psamp{1}.theta;
            else
                P=[P,Psamp{1}.theta];
            end
        end
        post.ind=[1:size(P,2)];
        post.Ep=mean(P(:,post.ind)')';
        post.P=P;
        post.mcmc=mcmc;

        % Eigenrep needed for spm_mci_joint later
        M = spm_mci_minit (M);

    case 'amc',
        disp('Adaptive Monte Carlo');
        disp(' ');

        % MH defaults
        tune=1;
        if tune
            Nscale=ceil(0.25*mcmc.maxits);
            Ntune=Nscale;
            Nsamp=ceil(0.5*mcmc.maxits);
        else
            Nscale=ceil(0.5*mcmc.maxits);
            Ntune=0;
            Nsamp=Nscale;
        end
        mc = spm_mci_popdef (Nscale,Ntune,Nsamp);
        mc.verbose=verbose;

        % Draw initialisation point from prior ?
        %mcmc.init{1}=spm_normrnd(M.pE,M.pC,1);
        try, mc.init{1}=mcmc.init; catch, mc.init{1}=spm_vec(M.pE); end

        MM{1}=M;
        UU{1}=U;
        tic;
        [Psamp,logev,D,MM] = spm_mci_pop (mc,MM,UU,Y);
        toc
        M=MM{1};

        if tp
            [post.Ep,post.SDp]=spm_mci_report (Psamp,mc,true_P);
        else
            disp('Initial params:');
            disp(mc.init{1});
            [post.Ep,post.SDp]=spm_mci_report (Psamp,mc);
        end

        post.Ep=post.Ep';
        post.P=Psamp{1}.theta;
        post.E=-Psamp{1}.logq;
        post.dL=Psamp{1}.dL;
        post.bayes_fb=zeros(1,length(post.E));
        post.acc=Psamp{1}.acc;
        post.logev=logev;
        post.D=D;
        post.mcmc=mcmc;
        post.ind=mc.ind_samp;

    case 'vl',
        disp('Variational Laplace');
        disp(' ');

        D.y=Y;
        if ~verbose
            M.nograph=1;
        end

        if isstruct(U)
            UI=U;
        else
            UI.u=U';
            UI.dt=M.T/M.N;
        end

        % Change VL defaults
        if isfield(mcmc,'maxits'), M.Nmax=mcmc.maxits; end
        if isfield(mcmc,'init'), M.P=mcmc.init; end
        if isfield(mcmc,'hE'), M.hE=mcmc.hE; end
        if isfield(mcmc,'hC'), M.hC=mcmc.hC; end

        [Ep,Cp,Eh,F,tmp1,tmp2,tmp3,k] = spm_nlsi_GN (M,UI,D);

        post.Ep=spm_vec(Ep);
        post.Cp=Cp;
        post.Eh=Eh;
        post.Ce=diag(1./exp(Eh));
        post.logev=F;
        post.its=k;
        if isfield(M,'P')
            post.init=M.P;
        end

        % Eigenrep needed for spm_mci_joint later
        M = spm_mci_minit (M);

    case 'langevin',
        disp('Langevin Monte Carlo');
        disp(' ');

        [M,stats]=spm_mci_lgv(mcmc,M,U,Y);
        Psamp=stats.P';
        Nsamp=size(Psamp,1);
        burn_in=round(0.3*size(Psamp,1));
        post=stats;
        post.ind=[burn_in+1:Nsamp];
        post.targ=Psamp(post.ind,:);
        post.Ep=mean(post.targ)';

        % 2.5%, 50% and 97.5% quantiles
        q = [.025 .5 .975];
        for j=1:M.Np,
            sx = post.P(j,post.ind);
            post.quantiles(j,:) = quantile(sx,q);
        end

    otherwise
        disp('Unknown inference method');
end

if strcmp(mcmc.inference,'VL')
    Up=UI;
else
    Up=U;
end

% Generate data fit from posterior mean
if isfield(M,'IS')
    if strcmp(M.IS,'spm_gen_erp')
        Ps=spm_unvec(post.Ep,M.pE);
        post.Yhat=feval('spm_gen_erp',Ps,M,Up);
    else
        post.Yhat = feval(M.IS,post.Ep,M,Up);
    end
else
    post.Yhat = spm_mci_fwd (post.Ep,M,Up);
end

post.els=toc;
disp(sprintf('Optimisation time = %1.2f seconds',post.els));

lw=2;
if ~isfield(M,'IS')
    % Plot time series
    figure
    rm=ceil(sqrt(M.l));
    for i=1:M.l,
        if M.l>3
            subplot(rm,rm,i);
        else
            subplot(M.l,1,i);
        end
        plot(M.t,Y(:,i),'LineWidth',lw);
        hold on
        plot(M.t,post.Yhat(:,i),'r','LineWidth',lw);
        grid on
        set(gca,'FontSize',16);
        legend('Data','Fit');
        xlabel('Time');
        ylabel(sprintf('y(%d)',i));
    end
end

% get parameters in reduced space
Pr=M.V'*(post.Ep-M.vpE);
post.L_est = spm_mci_joint (Pr,M,U,Y);
disp(sprintf('Estimated Log Joint=%1.2f',post.L_est));

if tp
    % get parameters in reduced space
    Pr=M.V'*(spm_vec(true_P)-M.vpE);
    post.L_true = spm_mci_joint (Pr,M,U,Y);
    disp(sprintf('True Log Joint=%1.2f',post.L_true));
    disp(' ');
end

pt=4;
if M.Np > pt
    hp=figure;
    set(hp,'Name','Parameters');
    plot(post.Ep,'r','LineWidth',lw);
    xlabel('Parameter');
    set(gca,'FontSize',16);
    grid on
else
    disp('Estimated (latent) params:');
    disp(post.Ep);
end

if tp
    if M.Np > pt
        hold on
        plot(spm_vec(true_P),'LineWidth',lw);
        legend('Estimated','True');
    else
        disp('True (latent) params:');
        disp(spm_vec(true_P));
    end
end

switch mcmc.inference,
    case {'amc','langevin'},
        post.type='sample';
    otherwise
        post.type='gaussian';
end


function G = gradient( f )
%GRADIENT   Numerical gradient of a DISKFUN.
%   G = GRADIENT(F) returns the numerical gradient of the
%   DISKFUN F as a DISKFUNV G.
%
% See also DISKFUNV/DIV, DISKFUNV/CURL, DISKFUN/CURL, DISKFUNV/VORTICITY

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

% Empty check.
if isempty( f )
    G = diskfunv;
    return
end

fx = diff(f, 1);   % diff in x-variable
fy = diff(f, 2);   % diff in y-variable

G = diskfunv(fx,fy);

end


function findquadelem(node,elem,range,varargin)
%% FINDQUADELEM highlights some elements
%
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

hold on

if (nargin==2) || isempty(range) || (ischar(range) && strcmp(range,'all'))
    range = (1:size(elem,1))';
end
if islogical(range)
    range = find(range);
end
if size(range,2)>size(range,1)
    range = range';
end
center = ( node(elem(range,1),:) + node(elem(range,2),:) ...
         + node(elem(range,3),:) + node(elem(range,4),:))/4;
if length(range) < size(elem,1)
    x = reshape(node(elem(range,:),1),size(range,1), size(elem,2));
    y = reshape(node(elem(range,:),2),size(range,1), size(elem,2));
    h = patch(x,y,'y');
    if nargin > 3
        if strcmp(varargin{1},'noindex') || strcmp(varargin{1},'index')
           if size(varargin,2)>=2
                set(h,varargin{2:end});
           end
        else
            set(h,varargin{:});
        end
    end
end
if (nargin <=3) || ~(strcmp(varargin{1},'noindex'))
    if size(node,2) == 2
        plot(center(:,1),center(:,2),'o','LineWidth',1,'MarkerEdgeColor','k',...
         'MarkerFaceColor','y','MarkerSize',20);
        text(center(:,1)-0.015,center(:,2),int2str(range),'FontSize',12,...
        'FontWeight','bold','Color','k');
    elseif size(node,2) == 3 % surface mesh
        plot3(center(:,1),center(:,2),center(:,3),'o','LineWidth',1,'MarkerEdgeColor','k',...
         'MarkerFaceColor','y','MarkerSize',20);
        text(center(:,1)-0.015,center(:,2),center(:,3),int2str(range),'FontSize',12,...
        'FontWeight','bold','Color','k');
    end
end
hold off


function z = plus( x, y )
    %PLUS Addition of two TT/MPS operators.
    %   Z = PLUS(X,Y) adds to TT/MPS operators. The resulting TT/MPS operator
    %   has rank equal to the sum of the individual ranks.
    %
    %   TTeMPS Toolbox.
    %   Michael Steinlechner, 2013-2016
    %   Questions and contact: michael.steinlechner@epfl.ch
    %   BSD 2-clause license, see LICENSE.txt

    % add sanity check...
    rx = x.rank;
    ry = y.rank;

    z = TTeMPS_op( cell(1, x.order) );

    % first core:
    tmp = zeros( 1, x.size_col(1), x.size_row(1), rx(2)+ry(2) );
    tmp( 1, :, :, 1:rx(2) ) = x.U{1};
    tmp( 1, :, :, rx(2)+1:end ) = y.U{1};
    z.U{1} = tmp;

    %z.U{1} = reshape( [unfold( x.U{1}, 'left'), unfold( y.U{1}, 'left')], [1, x.size(1), x.rank(2) + y.rank(2)]);

    % central cores:
    for i = 2:x.order-1
        tmp = zeros( rx(i)+ry(i), x.size_col(i), x.size_row(i), rx(i+1)+ry(i+1) );
        tmp( 1:rx(i), :, :, 1:rx(i+1) ) = x.U{i};
        tmp( rx(i)+1:end, :, :, rx(i+1)+1:end ) = y.U{i};
        z.U{i} = tmp;
    end

    % last core:
    tmp = zeros( rx(end-1)+ry(end-1), x.size_col(end), x.size_row(end), 1 );
    tmp( 1:rx(end-1), :, :, 1 ) = x.U{end};
    tmp( rx(end-1)+1:end, :, :, 1 ) = y.U{end};
    z.U{end} = tmp;

    z = update_properties( z );
end


classdef MFEA < ALGORITHM
% <single> <real/integer/label/binary/permutation> <large/none> <multitask>
% Multifactorial evolutionary algorithm
% rmp --- 0.3 --- Random mating probability

%------------------------------- Reference --------------------------------
% A. Gupta, Y. Ong, and L. Feng, Multifactorial evolution: towards
% evolutionary multitasking, IEEE Transactions on Evolutionary Computation,
% 2016, 20(3): 343-357.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    methods
        function main(Algorithm,Problem)
            %% Parameter setting
            rmp = Algorithm.ParameterSet(0.3);

            %% Initialize population
            Population    = Problem.Initialization();
            SubPopulation = Divide(Population,length(Problem.SubD));

            %% Optimization
            while Algorithm.NotTerminated([SubPopulation{:}])
                SubParent    = SelectHalf(SubPopulation);
                SubOffspring = Child(Problem,SubParent,rmp);
                for i = 1 : length(Problem.SubD)
                    SubPopulation{i}= [SubPopulation{i},SubOffspring{i}];
                end
                SubPopulation = SelectPop(SubPopulation,Problem);
            end
        end
    end
end


function sF = log(sF, varargin)
% log of a function
%
% Syntax
%   sF = log(sF)
%   sF = log(sF, 'bandwidth', bandwidth)
%
% Input
%  sF - @S2FunHarmonic
%
% Output
%  sF - @S2FunHarmonic
%
% Options
%  bandwidth - minimal degree of the spherical harmonic
%

%sF = sF.quadrature(@(v) log(sF.eval(v)),varargin{:});

sF = S2FunHandle(@(v) log(sF.eval(v)));

end


% configure parameters for wheel-slam

paras.datapath       = "data\wheel-ins_DR.bin";
paras.gt_path        = "data\ground_truth.bin";
paras.initheading    = 27.58;  %only for comparison with ground truth

paras.sigmaPhi       = (0.05 * pi/180);
paras.sigmaDis_scale = 0.05;

paras.odomdata_scale    = 0.5;%only process half of the data
paras.NPARTICLES        = 100;
paras.NEFFECTIVE        = paras.NPARTICLES * 0.5;
paras.rollSeqdimension  = 100;
paras.gridlen           = 1.5;
paras.conRevisitNumThr  = 5;
paras.corrCoefThr       = 0.4;
paras.corrCoefNumThr    = 2;


function Yi = qinterp1(x,Y,xi,methodflag)
% Performs fast interpolation compared to interp1
%
% qinterp1 provides a speedup over interp1 but requires an evenly spaced
% x array.  As x and y increase in length, the run-time for interp1 increases
% linearly, but the run-time for
% qinterp1 stays constant.  For small-length x, y, and xi, qinterp1 runs about
% 6x faster than interp1.
%
%
% Usage:
%   yi = qinterp1(x,Y,xi)  - Same usage as interp1
%   yi = qinterp1(x,Y,xi,flag)
%           flag = 0       - Nearest-neighbor
%           flag = 1       - Linear (default)
%
% Example:
%   x = [-5:0.01:5];   y = exp(-x.^2/2);
%   xi = [-4.23:0.3:4.56];
%   yi = qinterp1(x,y,xi,1);
%
% Usage restrictions
%    x must be monotonically and evenly increasing
%    e.g.,  x=-36:0.02:123;
%
%    Y may be up to two-dimensional
%
% Using with non-evenly spaced arrays:
%   Frequently the user will wish to make interpolations "on the fly" from
%   a fixed pair of library (i.e., x and y) vectors.  In this case, the
%   user can generate an equally-spaced set of library data by calling
%   interp1 once, and then storing this library data in a MAT-file or
%   equivalent.  Because the speed of qinterp1 is independent of the length
%   of the library vectors, the author recommends over-sampling this
%   generated set untill memory considerations start limitting program speed.
%
%   If the user wishes to use two or more spacings (i.e., a closely-spaced
%   library in the region of fine features, and a loosely-spaced library in
%   the region of coarse features), just create multiple libraries, record
%   the switching points, and send the search data to different qinterp1
%   calls depending on its value.
%
%   Example:
%       x1 = [-5:0.01:5];   x2 = [-40:1:-5 5:1:40];
%       y1 = exp(-x1.^2/3); y2 = exp(-x2.^2/3);
%       xi = [-30:0.3:30];
%       in = xi < 5 & xi > -5;
%       yi(in) = qinterp1(x1,y1,xi(in));
%       yi(~in) = qinterp1(x2,y2,xi(~in));

% Author: N. Brahms
% Copyright 2006

% Forces vectors to be columns
x = x(:); xi = xi(:);
sx = size(x); sY = size(Y);
if sx(1)~=sY(1)
    if sx(1)==sY(2)
        Y = Y';
    else
        error('x and Y must have the same number of rows');
    end
end

if nargin>=4
    method=methodflag;
else
    method = 1;    % choose nearest-lower-neighbor, linear, etc.
                   % uses integer over string for speed
end

% Gets the x spacing
ndx = 1/(x(2)-x(1)); % one over to perform divide only once
xi = xi - x(1);      % subtract minimum of x

% Fills Yi with NaNs
s = size(Y);
if length(s)>2
    error('Y may only be one- or two-dimensional');
end
Yi = NaN*ones(length(xi),s(2));

switch method
    case 0 %nearest-neighbor method
        rxi = round(xi*ndx)+1;        % indices of nearest-neighbors
        flag = rxi<1 | rxi>length(x) | isnan(xi);
                                      % finds indices out of bounds
        nflag = ~flag;                % finds indices in bounds
        Yi(nflag,:) = Y(rxi(nflag),:);
    case 1 %linear interpolation method
        fxi = floor(xi*ndx)+1;          % indices of nearest-lower-neighbors
        flag = fxi<1 | fxi>length(x)-1 | isnan(xi);
                                        % finds indices out of bounds
        nflag = ~flag;                  % finds indices in bounds
        Yi(nflag,:) = (fxi(nflag)-xi(nflag)*ndx).*Y(fxi(nflag),:)+...
            (1-fxi(nflag)+xi(nflag)*ndx).*Y(fxi(nflag)+1,:);
end


function output=user7sym()

%**************************************************************************
 %*************************************************************************
                %//input signal form transmitter side for symbol based\\
 clear all;
close all;
clc;
% us=input('enter the number of users');
% nb1=input('number of bits for user1');
% m1=input('enter the message sequence1');
% nb2=input('number of bits for user2');
% m2=input('enter the message sequence2');
% nb3=input('number of bits for user3');
% m3=input('enter the message sequence3');
% nb4=input('number of bits for user4');
% m4=input('enter the message sequence4');
% nb5=input('number of bits for user5');
% m5=input('enter the message sequence5');
us=3;
nb1=20;
nb2=20;
nb3=20;
nb4=20;
nb5=20;
nb6=20;
nb7=20;
m1=[1 1 1 1 1 0 1 1 1 0 1 0 1 1 1 1 0 1 1 0];
m2=[1 1 0 1 1 1 1 0 1 1 1 0 1 1 0 1 1 1 1 0 ];
m3=[1 0 1 1 0 1 1 0 1 1 1 0 1 0 1 1 0 1 1 0];
m4=[1 1 1 1 0 1 1 1 0 1 1 0 1 1 1 1 1 1 0 1 ];
m5=[1 1 1 1 0 1 1 0 1 1 1 0 1 1 1 1 0 1 1 1 ];
m6=[1 0 1 1 0 1 0 1 1 1 1 1 1 1 0 1 1 1 1 1 ];
m7=[1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1];

% nb1=20;
% nb2=20;
% nb3=20;
% nb4=20;
% nb5=20;
% nb6=20;
% nb7=20;
% m1=[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1];
% m2=[1 0 1 0 1  0 1 1 0 1 1 1 1 0 1 0 1 0 1 0];
% m3=[1 0 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 0 1 1 ];
% m4=[1 1 0 1 0  1 0 1 0 1 1 1 1 0 1 1 0 1 0 1];
% m5=[1 0 1 1 0  0 1 1 0 1 1 0 1 1 1 0 0 1 0 0];
% m6=[1 0 1 0 1  1 0 1 0 1 1 1 0 0 1 0 1 0 1 1];
% m7=[1 1 0 1 1 0 1 1 1 0 1 0 1 0 1 1 0 1 1 0];

                    %//message1 into polar form\\

for i=1:nb1
    if m1(i)==1
        mb1(i)=m1(i);
    else
        mb1(i)=-1;
    end
end
  % disp(mb1);

                %//message2 into polar form\\

for i=1:nb2
    if m2(i)==1
        mb2(i)=m2(i);
    else
        mb2(i)=-1;
    end
end
  %disp(mb2);

                %//message3 into polar form\\

for i=1:nb3
    if m3(i)==1
        mb3(i)=m3(i);
    else
        mb3(i)=-1;
    end
end
  %disp(mb3);

       %//message4 into polar form\\

for i=1:nb4
    if m4(i)==1
        mb4(i)=m4(i);
    else
        mb4(i)=-1;
    end
end
  %disp(mb4);

    %//message5 into polar form\\

for i=1:nb5
    if m5(i)==1
        mb5(i)=m5(i);
    else
        mb5(i)=-1;
    end
end
  %disp(mb5);

       %//message6 into polar form\\

for i=1:nb6
    if m6(i)==1
        mb6(i)=m6(i);
    else
        mb6(i)=-1;
    end
end
  %disp(mb6);

    %//message7 into polar form\\

for i=1:nb7
    if m7(i)==1
        mb7(i)=m7(i);
    else
        mb7(i)=-1;
    end
end
  %disp(mb7);

                  %//generation of maximal length sequence1\\

  f1=1;f2=1;f3=0;f4=0;f5=1;
m=(2^5)-1;
for j=1:m
    p=xor(f2,f5);
    f5=f4;
    op1(j)=f5;
    f4=f3;
    f3=f2;
    f2=f1;
    f1=p;

end
  %disp(op1);

                    %//msequence1 into polar form\\

    for i=1:31

         if op1(i)==1
             pb1(i)=1;
         else
         pb1(i)=-1;
        end
    end
    %disp(op1);
    %disp(pb1);

                    %//generation of maximal length sequence2\\

  f1=1;f2=0;f3=0;f4=1;f5=1;
m=(2^5)-1;
for j=1:m
    p=xor(f3,f5);
    f5=f4;
    op2(j)=f5;
    f4=f3;
    f3=f2;
    f2=f1;
    f1=p;

end
  %disp(op2);

                    %//msequence2 into polar form\\

    for i=1:31
        if op2(i)==1
             pb2(i)=1;
         else
         pb2(i)=-1;
        end
    end
    %disp(op2);
    %disp(pb2);

                     %//generation of maximal length sequence3\\

  f1=1;f2=1;f3=1;f4=0;f5=1;
m=(2^5)-1;
for j=1:m
    p=xor(f4,f5);
    f5=f4;
    op3(j)=f5;
    f4=f3;
    f3=f2;
    f2=f1;
    f1=p;

end
  %disp(op3);

                    %//msequence3 into polar form\\

    for i=1:31

         if op3(i)==1
             pb3(i)=1;
         else
         pb3(i)=-1;
        end
    end
    %disp(op3);
    %disp(pb3);

                     %//generation of maximal length sequence4\\

  f1=0;f2=1;f3=1;f4=0;f5=1;
m=(2^5)-1;
for j=1:m
    p=xor(f4,f5);
    f5=f4;
    op4(j)=f5;
    f4=f3;
    f3=f2;
    f2=f1;
    f1=p;

end
  %disp(op4);

                    %//msequence4 into polar form\\

    for i=1:31

         if op4(i)==1
             pb4(i)=1;
         else
         pb4(i)=-1;
        end
    end
    %disp(op4);
    %disp(pb4);

                     %//generation of maximal length sequence5\\

  f1=1;f2=1;f3=0;f4=0;f5=1;
m=(2^5)-1;
for j=1:m
    p=xor(f4,f5);
    f5=f4;
    op5(j)=f5;
    f4=f3;
    f3=f2;
    f2=f1;
    f1=p;

end
  %disp(op5);

                    %//msequence5 into polar form\\

    for i=1:31

         if op5(i)==1
             pb5(i)=1;
         else
         pb5(i)=-1;
        end
    end
    %disp(op5);
    %disp(pb5);

                     %//generation of maximal length sequence6\\

  f1=0;f2=0;f3=1;f4=0;f5=1;
m=(2^5)-1;
for j=1:m
    p=xor(f4,f5);
    f5=f4;
    op6(j)=f5;
    f4=f3;
    f3=f2;
    f2=f1;
    f1=p;

end
  %disp(op6);

                            %//msequence6 into polar form\\

    for i=1:31

         if op6(i)==1
             pb6(i)=1;
         else
         pb6(i)=-1;
        end
    end
    %disp(op6);
    %disp(pb6);

                 %//generation of maximal length sequence7\\

  f1=1;f2=1;f3=0;f4=0;f5=1;
m=(2^5)-1;
for j=1:m
    p=xor(f4,f5);
    f5=f4;
    op7(j)=f5;
    f4=f3;
    f3=f2;
    f2=f1;
    f1=p;

end
  %disp(op7);

                      %//msequence7 into polar form\\

    for i=1:31

         if op7(i)==1
             pb7(i)=1;
         else
         pb7(i)=-1;
        end
    end
    %disp(op7);
    %disp(pb7);

                    %//spreading signals from transmitter side\\

                         %//first transmit bit\\

k=1;
for i=1:nb1
    for j=1:31
        tb1(k)=mb1(i)*pb1(j);
        k=k+1;
    end
end
%disp(tb1);

                     %//second transmit bit\\

k=1;
for i=1:nb2
    for j=1:31
        tb2(k)=mb2(i)*pb2(j);
        k=k+1;
    end
end
%disp(tb2);

                    %//third transmit bit\\

k=1;
for i=1:nb3
    for j=1:31
        tb3(k)=mb3(i)*pb3(j);
        k=k+1;
    end
end
%disp(tb3);

                %//fourth transmit bit\\

k=1;
for i=1:nb4
    for j=1:31
        tb4(k)=mb4(i)*pb4(j);
        k=k+1;
    end
end
%disp(tb4);

             %//fifth transmit bit\\

k=1;
for i=1:nb5
    for j=1:31
        tb5(k)=mb5(i)*pb5(j);
        k=k+1;
    end
end
%disp(tb5);

     %//sixth transmit bit\\

k=1;
for i=1:nb6
    for j=1:31
        tb6(k)=mb6(i)*pb6(j);
        k=k+1;
    end
end
%disp(tb6);

     %//seventh transmit bit\\

k=1;
for i=1:nb7
    for j=1:31
        tb7(k)=mb7(i)*pb7(j);
        k=k+1;
    end
end
%disp(tb7);

                 %//Addition of seven  signals transmitted in the channel\\

n=1;
for i=1:k-1
    tb(n)=tb1(n)+tb2(n)+tb3(n)+tb4(n)+tb5(n)+tb6(n)+tb7(n);
    n=n+1;
end
%disp(tb);
chn=awgn(tb,10);

                         %//%receiver side\\
                    %//reconstruction of user2 signal\\

s2=0;
t2=1;
for i=0:31:k-32
    for j=1:31
        ob2(t2)=chn(i+j)*pb2(j)+s2;
        s2=ob2(t2);
        if ob2(t2)>0
            ob2(t2)=1;
        else ob2(t2)=0;
        end
    end
    t2=t2+1;
    s2=0;
end
%disp('second message is')
%disp(ob2);
n1=awgn(ob2,10);
 figure(1);
grid on;
subplot(2,2,1);
plot(ob2);
title('Received signal with out noise for SB');
xlabel('Time');
ylabel('Amplitude');
%g=awgn(ob2,10);
%disp(g);
subplot(2,2,2);
plot(chn);
title('Received signal with noise for SB');
xlabel('Time');
ylabel('Amplitude');

                    %//reconstruction of received signal from noise\\

for i=1:nb2
     if chn(i)>0
            g2(i)=1;
        else g2(i)=0;
        end
    end

% disp(g2);

                 % //calculating optimum weight using minimum variance\\

 ob=randint(1,31);
q=length(10);
%q1=input('enter the sequence');
s=randsrc(1,q);
c1=complex(ob,s);
%disp(c);
d=conj(c1);
d1=d*d';
%disp(d1);
m=mean(d1);
lamda=5;
teta=45;
k=((2*pi)/lamda);
K=4;
for i=0:K-1
    v=(exp(j*k*i*d*sin(teta)))';
end
%disp(v);
v1=conj(v)';
teta=30;
k=((2*pi)/lamda);
K=5;
for i=0:K-1
    eta=exp(sqrt(-1)*k*i*d*sin(teta))';
end
%u1=[2+2j 3-1j 4+3j 5+2j]'
%m=randsrc(1,124);
%a=randsrc(1,124);
l=length(10);
%l1=input('enter the sequence');
u1=complex(ob2,l);
u=eta*u1;
u2=conj(u)';
u3=u*u2;
Ru=mean(u3);

%Ru1=imresize(Ru,[124 124]);
%a1=inv(Ru1);
%a1=Ru1';
a1=Ru';
%disp(a1);
%calculating beta value
%g=1;
dem1=v*v1*a1;
beta1=dem1.^-1;
 %optimum weight
%Wopt=beta*a1*v';
temp1=beta1*v';
Wopt1=temp1*a1;
%disp(Wopt1);
 subplot(2,2,3);
plot(Wopt1);
title('Received signal with optimum weight for SB');
xlabel('Time');
ylabel('weight');

                    %//beamformer output\\

o1=conj(Wopt1)*ob2;
%disp('Beamformer output for SB')
%disp(o1);
 subplot(2,2,4);
plot(o1);
title('Beamformer output  for SB');
xlabel('Time');
ylabel('Beam former output');

                    %//SINR CALCULATION FOR SB CONFIGURATION\\

%s=length(m2);
%q1=input('enter the sequence');
s=randsrc(1,q);
c=complex(ob2,s);

hop1=conj(pb2)';
hob1=conj(c)';
nr3=hop1*hob1';
sum2=nr3'*Wopt1;
%disp('sum2');
%disp(sum2);
cm2=sum2'*sum2;
signal1=mean(cm2);
%disp('cm2');
%disp(cm2);
hop2=conj(pb2)';
hx2=conj(n1)';
nr5=hop2*hx2';
 sum3=nr5'*Wopt1;
 %disp('sum');
 %disp(sum);
  cm3=sum3'*sum3;
  noise1=mean(cm3);
 %disp('cm3');
 %disp(cm3);
 SSINR=signal1/noise1;
 disp('SSINR');
 disp(SSINR);

                %//GRAPH FOR DOA VERSUS SINR\\

    DOA=-80:10:80;
    figure(4);
    plot(DOA,SSINR,'B-*');
    title('simulation for DOA versus SSINR');
    xlabel('DOA in degree');
    ylabel('SINR in db');

                %// BER CALCULATION FOR SB CONFIGURATION\\

       k1=biterr(m2,g2);
       output=k1;
       disp('biterror rate for Sb configuration');
       disp(k1);

                 %//GRAPH FOR NUMBER USERS VERSUS BER\\

     figure(5);
     plot(us,k1,'R-*');

     title('simulation for No. of users versus BER SYMBOL BASED ');
     xlabel('NUMBER OF USERS');
     ylabel('BER');


classdef nnbnorm < nntest
  properties (TestParameter)
    rows = {2 8 13}
    cols = {2 8 17}
    numDims = {1 3 4}
    batchSize = {2 7}
  end
  methods (Test)
    function basic(test, rows, cols, numDims, batchSize)
      r = rows ;
      c = cols ;
      nd = numDims ;
      bs = batchSize ;
      x = test.randn(r, c, nd, bs, 'single') ;
      g = test.randn(1, 1, nd, 1, 'single');
      b = test.randn(1, 1, nd, 1, 'single');
      g = test.randn(nd, 1, 'single');
      b = test.randn(nd, 1, 'single');

      y = vl_nnbnorm(x,g,b) ;
      dzdy = test.randn(size(y), 'single') ;
      [dzdx,dzdg,dzdb] = vl_nnbnorm(x,g,b,dzdy) ;

      test.der(@(x) vl_nnbnorm(x,g,b), x, dzdy, dzdx, test.range * 1e-2, -1e-3) ;
      test.der(@(g) vl_nnbnorm(x,g,b), g, dzdy, dzdg, test.range * 1e-2, -1e-3) ;
      test.der(@(b) vl_nnbnorm(x,g,b), b, dzdy, dzdb, test.range * 1e-2, -1e-3) ;
    end
  end
end


%-------------------------------------------------------------------------------------------------------------------%
%
% IB2d is an Immersed Boundary Code (IB) for solving fully coupled non-linear
% 	fluid-structure interaction models. This version of the code is based off of
%	Peskin's Immersed Boundary Method Paper in Acta Numerica, 2002.
%
% Author: Nicholas A. Battista
% Email:  nickabattista@gmail.com
% Date Created: May 27th, 2015
% Institution: UNC-CH
%
% This code is capable of creating Lagrangian Structures using:
% 	1. Springs
% 	2. Beams (*torsional springs, non-invariant beams*)
% 	3. Target Points
%	4. Muscle-Model (combined Force-Length-Velocity model, "Hill+(Length-Tension)")
%
% One is able to update those Lagrangian Structure parameters, e.g., spring constants, resting lengths, etc
%
% There are a number of built in Examples, mostly used for teaching purposes.
%
% If you would like us to add a specific muscle model, please let Nick (nickabattista@gmail.com) know.
%
%--------------------------------------------------------------------------------------------------------------------%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION: updates the spring attributes!
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function springs_info = update_Springs(dt,current_time,xLag,yLag,springs_info)

%springs_info: col 1: starting spring pt (by lag. discretization)
%              col 2: ending spring pt. (by lag. discretization)
%              col 3: spring stiffness
%              col 4: spring resting lengths

%RL = springs_info(:,4); % resting-length vector

% Contraction Frequency
freq = 2.0;

% CHANGE RESTING LENGTH BTWN SIDES OF JELLYFISH BELL 1
springs_info(319:357,4) = abs( cos(freq*current_time*pi) );

% CHANGE RESTING LENGTH BTWN SIDES OF JELLYFISH BELL 2
%springs_info(676:714,4) = abs( cos(freq*current_time*pi) );


function PanoLabelIm(id, ANNO_ALL, config, options)
% load image
im_name = config.IMGLIST(id).name;
im = imread([config.folderName im_name '/' im_name '.jpg']);
[im_h, im_w, im_dim] = size(im);
im_o = im2double(im);
% alignment
if 1
imgSize = 320;
qError = 0.7;
global config;
config.NewProjFolder = './panoContext_code/';
config.lsdLocation = [config.NewProjFolder 'VpEstimation/lsd '];
config.bufferFolder = './Buffer_gt/';
if ~exist(config.bufferFolder, 'dir')
    mkdir(config.bufferFolder);
end
[ olines, vp, views, edges, panoEdge, score, angle] = panoEdgeDetection( im_o, imgSize, qError);
save(['./label_vp/pc/' im_name '.mat'], 'vp');
%keyboard
return
end
load(['./label_vp/pc/' im_name '.mat']);
[rotImg, R] = rotatePanorama(im_o, vp(3:-1:1,:));

if exist(['./label_cor/pc/' im_name '.mat'], 'file')
    gt = load(['./label_cor/pc/' im_name '.mat']);
    gt = gt.cor;
    keyboard
else

r_id = find([ANNO_ALL(id).ANNO3D.objects.type] == 3);
    pt = ANNO_ALL(id).ANNO3D.objects(r_id).points *ANNO_ALL(id).ANNO3D.R;
    pt = pt*R'; % algin pt also
    [ uv ] = xyz2uvN( pt ); % transform xyz to im coordinates
    [ uvcoord ] = uv2coords( uv, im_w, im_h );
%sort
[~,gt_id] = sort(uvcoord(:,1));
gt = uvcoord(gt_id,:);
for i = 1:2:size(gt,1)
    gt_t = gt(i:i+1,:);
    [~, gt_t_id] = sort(gt_t(:,2));
    gt(i:i+1,:) = gt_t(gt_t_id,:);
end
end
gt_all = [gt;
               gt(1,:);gt(3,:);gt(3,:);gt(5,:);
               gt(5,:);gt(7,:);gt(7,:);gt(1,:);
               gt(2,:);gt(4,:);gt(4,:);gt(6,:);
               gt(6,:);gt(8,:);gt(8,:);gt(2,:)];
    [ uv ] = coords2uv( gt_all, im_w, im_h );
    [ xyz ] = uv2xyzN( uv);
    [ lines ] = lineFromTwoPoint( xyz(1:2:end,:), xyz(2:2:end,:) );
    [ panoEdgeC2 ] = paintParameterLine2(lines, im_w, im_h, rotImg, 2 );

figure(1), axis off, hold off,
ha = tight_subplot(1, 1);
axes(ha(1)), imagesc(panoEdgeC2), axis image, hold on

if 1 % corner debug
disp('Click y if label this image');
[~,~,b] = ginput(1);
if b ~= 'y'
    return
end

% Allow user to input line segments; compute centers, directions, lengths
%disp('Draw Pano lines...')

% find concave lines
lines = [];
while 1
    disp(' ')
    disp('Draw concave lines or q to stop')
    [x1,y1,b] = ginput(1);
    if b=='q'
        break;
    end
    [x2,y2, ~] = ginput(1);
    % single line fitting
    vert = (x1+x2)/2;
    axes(ha(1)); h1 = plot([vert vert], [1 im_h], 'b');
    disp('Click y if accept this line')
    [~,~, b] = ginput(1);
    % save
    if b == 'y'
        lines(end+1,:) = [vert y1 1]; % 1 for concave signal
        lines(end+1,:) = [vert y2 1];
    else
        axes(ha(1)); delete(h1);
    end
end

% find convex lines
while 1
    disp(' ')
    disp('Draw convex lines or q to stop')
    [x1,y1,b] = ginput(1);
    if b=='q'
        break;
    end
    [x2,y2, ~] = ginput(1);
    % single line fitting
    vert = (x1+x2)/2;
    axes(ha(1)); h1 = plot([vert vert], [1 im_h], 'r');
    disp('Click y if accept this line')
    [~,~, b] = ginput(1);
    % save
    if b == 'y'
        lines(end+1,:) = [vert y1 2]; % 2 for convex signal
        lines(end+1,:) = [vert y2 2];
    else
        axes(ha(1)); delete(h1);
    end
end

% sort lines
[~,l_id] = sort(lines(:,1));
lines = lines(l_id,:);
for i = 2:2:size(lines,1)
    sub_l = lines(i-1:i,:);
    [~,l_id] = sort(sub_l,1);
    lines(i-1,:) = sub_l(l_id(1),:);
    lines(i,:) = sub_l(l_id(2),:);
end
end

% solve for pano
if size(lines,1) == 8
    [wall_d, x, f] = pano_line_solver(lines, im_w, options); % bos-shape case
else if size(lines,1) == 12
       [wall_d, x, f] = pano_line_solver_6(lines, im_w, options); % L-shape case
    else if size(lines,1) == 16
            [wall_d, x, f] = pano_line_solver_8(lines, im_w, options); % T-shape case
        end
    end
end

lines_ = lines;
% annotate box height
cor = [];
%c_h = 1.7;
flag = 0;
while 1
    disp('Draw corners or q to stop')
    [x1,y1,b] = ginput(1);
    axes(ha(1)); h1 = plot(x1, y1, 'xr');
    if b=='q'
        break;
    end
    [x2,y2] = ginput(1);
    axes(ha(1)); h3 = plot(x2, y2, 'xr');
    disp('Click y if accept this corner');
    [~,~,b] = ginput(1);
    if b == 'y'
        cor(end+1,:) = [x1 y1];
        cor(end+1,:) = [x2 y2];
        % find closet wall
        %keyboard
        vert = (x1+x2)/2;
        cor_d = abs(lines(:,1) - vert);
        [~, l_id] = min(cor_d);
        cor = [lines(l_id,1) cor(1,2); lines(l_id,1) cor(2,2)];
        % solve for all walls
        [~, cor_id] = sort(cor(:,2));
        cor = cor(cor_id,:);
        theta_y = pi*cor(2,2)/im_h-pi/2;
        d = abs(cot(theta_y));lines_ = lines;%c_h*abs(cot(theta_y));
        theta_y_ = pi/2 - pi*cor(1,2)/im_h;
        h = d*tan(theta_y_);%c_h + d*tan(theta_y_);
        d_m = d/wall_d((l_id+1)/2);
        line_ya = [];
        line_ya_ = [];
        for i = 1:2:size(lines,1)
            if i == l_id
                continue
            end
            line_d = d_m*wall_d((i+1)/2);
            line_theta_y = acot(line_d);%acot(line_d/c_h);
            line_y = (line_theta_y + pi/2)*im_h/pi;
            cor = [cor;lines(i,1) line_y];
            line_y_ = atan(h/line_d);%atan((h-c_h)/line_d);
            line_y_ = (pi/2-line_y_)*im_h/pi;
            cor = [cor;lines(i,1) line_y_ ];
            axes(ha(1)); h1 = plot([lines(i,1) lines(i,1)], [line_y line_y_], 'xr');
        end
        % sort cor
        [~, cor_id] = sort(cor(:,1));
        cor = cor(cor_id,:);
        for i = 1:2:size(cor,1)
                cor_sub = cor(i:i+1,:);
                [~, cor_id] = sort(cor_sub(:,2));
                cor(i,:) = cor_sub(cor_id(1),:);
                cor(i+1,:) = cor_sub(cor_id(2),:);
        end

        % visual full
        if size(cor,1) == 8
            cor_all = [cor;
                cor(1,:);cor(3,:);cor(3,:);cor(5,:);
                cor(5,:);cor(7,:);cor(7,:);cor(1,:);
                cor(2,:);cor(4,:);cor(4,:);cor(6,:);
                cor(6,:);cor(8,:);cor(8,:);cor(2,:)];
        else if size(cor,1) == 12
            cor_all = [cor;
                cor(1,:);cor(3,:);cor(3,:);cor(5,:);
                cor(5,:);cor(7,:);cor(7,:);cor(9,:);
                cor(9,:);cor(11,:);cor(11,:);cor(1,:);
                cor(2,:);cor(4,:);cor(4,:);cor(6,:);
                cor(6,:);cor(8,:);cor(8,:);cor(10,:);
                cor(10,:);cor(12,:);cor(12,:);cor(2,:)];
		else if size(cor,1) == 16
		    cor_all = [cor;
                	cor(1,:);cor(3,:);cor(3,:);cor(5,:);
                	cor(5,:);cor(7,:);cor(7,:);cor(9,:);
                	cor(9,:);cor(11,:);cor(11,:);cor(13,:);
                        cor(13,:);cor(15,:);cor(15,:);cor(1,:);
                	cor(2,:);cor(4,:);cor(4,:);cor(6,:);
                	cor(6,:);cor(8,:);cor(8,:);cor(10,:);
                	cor(10,:);cor(12,:);cor(12,:);cor(14,:);
			cor(14,:);cor(16,:);cor(16,:);cor(2,:)];
		end
            end
        end
        [ uv ] = coords2uv( cor_all, im_w, im_h );
        [ xyz ] = uv2xyzN( uv);
        [ lines ] = lineFromTwoPoint( xyz(1:2:end,:), xyz(2:2:end,:) );
        [ panoEdgeC ] = paintParameterLine2(lines, im_w, im_h, rotImg, 1 );
        axes(ha(1));imagesc(panoEdgeC); axis image; hold on;
        for i = 1:size(line,1)
            axes(ha(1)); plot([lines(i,1) lines(i,1)], [1 im_h], 'b');
            axes(ha(1)); plot([lines(i,1) lines(i,1)], [line_y line_y_], 'xr');
        end

        disp('Click y if accept this box');
        [~,~,b] = ginput(1);
        if b == 'y'
            flag = 1;
            break
        else
            axes(ha(1)); imagesc(rotImg), axis image, hold on
            for i = 1:size(lines,1)
                axes(ha(1)); plot([lines(i,1) lines(i,1)], [1 im_h], 'b');
            end
            cor = [];
        end
    else
        axes(ha(1)); delete(h1); delete(h3);
    end
    if flag
        break
    end
end

if 0
% sort cor
[~, cor_id] = sort(cor(:,1));
cor = cor(cor_id,:);
for i = 1:2:size(cor,1)
    cor_sub = cor(i:i+1,:);
    [~, cor_id] = sort(cor_sub(:,2));
    cor(i,:) = cor_sub(cor_id(1),:);
    cor(i+1,:) = cor_sub(cor_id(2),:);
end

% visual full
cor_all = [cor;
               cor(1,:);cor(3,:);cor(3,:);cor(5,:);
               cor(5,:);cor(7,:);cor(7,:);cor(1,:);
               cor(2,:);cor(4,:);cor(4,:);cor(6,:);
               cor(6,:);cor(8,:);cor(8,:);cor(2,:)];
[ uv ] = coords2uv( cor_all, im_w, im_h );
[ xyz ] = uv2xyzN( uv);
[ lines ] = lineFromTwoPoint( xyz(1:2:end,:), xyz(2:2:end,:) );
[ panoEdgeC ] = paintParameterLine2(lines, im_w, im_h, rotImg, 1 );
axes(ha(1));imagesc(panoEdgeC); axis image;
end

cor = [cor lines_(:,3)];

imwrite(panoEdgeC, ['./label_vis/pc/' im_name '.png'], 'png');
save(['./label_cor/pc/' im_name '.mat'], 'cor');


% ========================================================================
% Fast Multi-Scale Structural Patch Decomposition for Multi-Exposure Image Fusion, TIP,2020
% algorithm Version 1.0
% Copyright(c) 2020, Hui Li, Kede Ma, Yongwei Yong and Lei Zhang
% All Rights Reserved.
% ----------------------------------------------------------------------
% Permission to use, copy, or modify this software and its documentation
% for educational and research purposes only and without fee is hereby
% granted, provided that this copyright notice and the original authors'
% names appear on all copies and supporting documentation. This program
% shall not be used, rewritten, or adapted as the basis of a commercial
% software or hardware product without first obtaining permission of the
% authors. The authors make no representations about the suitability of
% this software for any purpose. It is provided "as is" without express
% or implied warranty.
%----------------------------------------------------------------------
% Please refer to the following paper:
% H. Li et al., "Fast Multi-Scale Structural Patch Decomposition for Multi-Exposure Image Fusion, 2020" In press
% IEEE Transactions on Image Processing
% Please kindly report any suggestions or corrections to xiaohui102788@126.com
%----------------------------------------------------------------------

%% motion detection in dynamic scenes

function imgSeqcor= detection_color(imgSeqColor,r)

[h,w,~,n]=size(imgSeqColor);
N = boxfilter(ones(h, w), r);
i_mean=zeros(h,w,n);

C = 0.03 ^ 2 / 2;
structureThres=0.8;
consistencyThres=0.2;
exposureThres=0.02;
ref=ceil(n/2);

%   ref = selectRef(imgSeqColor);
se = strel('disk',2*r+1);
% se = strel('square',10);

R_img=imgSeqColor(:,:,:,ref);
R_mean=boxfilter(R_img(:,:,1), r)./ N+boxfilter(R_img(:,:,2), r)./ N+boxfilter(R_img(:,:,3), r)./ N;
R_mean= R_mean./3;

R_var= boxfilter(R_img(:,:,1).*R_img(:,:,1), r)./ N+ boxfilter(R_img(:,:,2).*R_img(:,:,2), r)./ N+...
    boxfilter(R_img(:,:,3).*R_img(:,:,3), r)./ N- R_mean.* R_mean*3;

R_var = R_var./3;
R_std=sqrt(max(R_var,0));

i_mean(:,:,ref)=R_mean;
muIdxMap = R_mean < exposureThres | R_mean > 1 - exposureThres;
% R=2*r+1;
% countWindowt = ones(R, R);
% countWindow=countWindowt./sum(countWindowt(:));
i_std=zeros(h,w,n);
sRefMap=zeros(h,w,n);
imgSeqcor=zeros(h,w,3,n);

for i = 1 : n
    if i ~= ref
        img= imgSeqColor(:,:,:,i);

        i_mean(:,:,i)=boxfilter(img(:,:,1), r)./ N+boxfilter(img(:,:,2), r)./ N+boxfilter(img(:,:,3), r)./ N;
        i_mean(:,:,i)= i_mean(:,:,i)./3;

        i_var= boxfilter(img(:,:,1).*img(:,:,1), r)./ N+ boxfilter(img(:,:,2).*img(:,:,2), r)./ N+...
            boxfilter(img(:,:,3).*img(:,:,3), r)./ N- i_mean(:,:,i).* i_mean(:,:,i)*3;

        i_var = i_var./3;
        i_std(:,:,i)=sqrt(max(i_var,0));

        mean_iR=boxfilter(img(:,:,1).*R_img(:,:,1), r)./ N+boxfilter(img(:,:,2).*R_img(:,:,2), r)./ N+...
            boxfilter(img(:,:,3).*R_img(:,:,3), r)./ N;
        mean_iR=mean_iR/3;
        cov_iR = mean_iR -  i_mean(:,:,i).* R_mean;

        %         mean_iR=boxfilter(img(:,:,1).*R_img(:,:,1), r)./ N+boxfilter(img(:,:,2).*R_img(:,:,2), r)./ N+...
        %             boxfilter(img(:,:,3).*R_img(:,:,3), r)./ N-i_mean(:,:,i).* R_mean*3;
        %         cov_iR=mean_iR./3;
        %

        sMap= (cov_iR + C) ./ (R_std.* i_std(:,:,i) + C);
        sRefMapt=(sMap >structureThres);

        %         t= sRefMap(:,:,i) ;
        %         t(muIdxMap) = 1;

        sRefMapt(muIdxMap) = 1;
        %         sRefMap(:,:,i) =sRefMapt;

        sRefMap(:,:,i) = imopen(sRefMapt,se);

        %     sRefMap(:,:,i) =bwareaopen( sRefMap(:,:,i),150);
        %  sRefMap(:,:,i) = imopen(sRefMap(:,:,i),se);

        %   figure,imshow( sRefMap(:,:,i))

        %   sRefMap(:,:,i) = imopen(sRefMap(:,:,i),se);

        %
        cMu  = imhistmatch(i_mean(:,:,i), R_mean,256);
        diff = abs(cMu - R_mean);
        cMap = diff <= consistencyThres;
        sRefMap(:,:,i) =  sRefMap(:,:,i).*cMap;

        %     figure,imshow( sRefMap(:,:,i))

        %     sRefMap(:,:,i) =bwareaopen( sRefMap(:,:,i),150);

        %         figure,imshow( sRefMap(:,:,i))

        %         sRefMap(:,:,i) = imopen(sRefMap(:,:,i),se);

        temp = imhistmatch(imgSeqColor(:,:,:,ref),...
            imgSeqColor(:,:,:,i),256);
        %         temp(temp<0) = 0;
        %         temp(temp>1) = 1;

        %         figure,imshow(temp)

        imgSeqcor(:,:,:,i)=imgSeqColor(:,:,:,i).*repmat(sRefMap(:,:,i),[1 1 3])+...
            temp.*repmat(1-sRefMap(:,:,i),[1 1 3]);
    end
    imgSeqcor(:,:,:,ref)=imgSeqColor(:,:,:,ref);

end


% This is a template script that runs the HMM on a fictional fMRI data set
% using a number of different settings, involving how many PCA components we use to
% describe the data, and how many HMM states we set up for the HMM inference.
% It assumes that there are 2 different
% conditions (for example rest and some task). It performs permutation
% testing on the HMM results for each of the HMM settings, and plots the results.
% More specifically, it tests for fractional occupancy differences and state
% switching rate differences between the conditions, using GLM-based
% permutation testing (function hmmtest.m)
%
% This script can be adapted to block-designed real data with any number of
% conditions by configuring the variable Y.
% Note that the data contain no dynamics, and this
% script is only for the purposes of demonstration
%
% It assumes that the toolbox paths are in the right place.
%
% Author: Diego Vidaurre, OHBA, University of Oxford (2017)

%% Prepare data

N = 25; % subjects
Q = 4; % sessions per subject
ttrial = 500; % time points
nregions = 50; % regions or voxels
Y = zeros(N*Q,2); % design matrix with conditions
X = randn(Q*N*ttrial,nregions); % all data concatenated
T = ttrial * ones(N*Q,1);  % length of data for each session
Tsubject = Q*ttrial * ones(N,1);  % length of data for each subject

% Functional connectivity profile for condition 1
FC_condition1 = randn(nregions);
FC_condition1 = FC_condition1' * FC_condition1;
% Functional connectivity profile for condition 2
FC_condition2 = randn(nregions);
FC_condition2 = FC_condition2' * FC_condition2;
% Note that there is no difference in the mean activity between conditions

for j1 = 1:N
    for j2 = 1:Q
        t = (1:ttrial) + (j2-1)*ttrial + Q*(j1-1)*ttrial;
        n = (j1-1)*Q + j2;
        if rem(j2,2)
            Y(n,1) = 1;
            X(t,:) = X(t,:) * FC_condition1;
        else
            Y(n,2) = 1;
            X(t,:) = X(t,:) * FC_condition2;
        end
        for i = 1:nregions % do some smoothing
            X(t,i) = smooth(X(t,i));
        end
    end
end

options = struct();
e = explainedvar_PCA(X,T,options); % how much variance PCA explains on the data
pc1 = find(e>0.5,1); % get no. of PCA components to explain 50% of variance
pc2 = find(e>0.6,1); % get no. of PCA components to explain 60% of variance
pc3 = find(e>0.7,1); % get no. of PCA components to explain 70% of variance
pc4 = find(e>0.8,1); % get no. of PCA components to explain 80% of variance
pc5 = find(e>0.9,1); % get no. of PCA components to explain 90% of variance
pc6 = 0; % no pca
number_pca_components = [pc1 pc2 pc3 pc4 pc5 pc6];
number_states = 4:6;

template_configuration = struct();
template_configuration.order = 0;
template_configuration.dropstates = 0;
template_configuration.verbose = 0;
template_configuration.cyc = 50;
template_configuration.initcyc = 5;

i = 1;
configurations = {}; % parameters of the HMM
% Gaussian distribution with  mean and full covariance
for k = number_states
    for pca_comp = number_pca_components
        configurations{i} = template_configuration;
        configurations{i}.K = k;
        configurations{i}.pca = pca_comp;
        configurations{i}.zeromean = 0;
        configurations{i}.covtype = 'full';
        i = i + 1;
    end
end
% Gaussian distribution with just covariance
for k = number_states
    for pca_comp = number_pca_components
        configurations{i} = template_configuration;
        configurations{i}.K = k;
        configurations{i}.pca = pca_comp;
        configurations{i}.zeromean = 1;
        configurations{i}.covtype = 'full';
        i = i + 1;
    end
end
% Gaussian distribution with just mean
for k = number_states
    for pca_comp = number_pca_components
        configurations{i} = template_configuration;
        configurations{i}.K = k;
        configurations{i}.pca = pca_comp;
        configurations{i}.zeromean = 0;
        configurations{i}.covtype = 'sharedfull';
        i = i + 1;
    end
end

%% Run HMM and perform statistical testing on the HMM results vs the conditions

L = length(configurations);
Gamma = cell(length(configurations),1);
test_group = cell(length(configurations),1);

options_test = struct();
options_test.subjectlevel = 0;
options_test.Nperm = 1000;

for i = 1:length(configurations)
    [hmm,Gamma{i}] = hmmmar(X,T,configurations{i});
    t = hmmtest(Gamma{i},T,Tsubject,Y,options_test,hmm);
    test_group{i} = t.grouplevel; % only doing group-level testing
    disp([num2str(i) ' of ' num2str(L)])
end

%% Plot

L1 = length(number_pca_components) * length(number_states);
L2 = length(number_states);
L3 = length(number_pca_components);
titles = {'Gaussian','Gaussian no Mean','Gaussian no Cov'};

% fractional occupancies
figure(1);clf(1)
ii = 1;
for i = 1:3
    for j = 1:L2
        subplot(3,L2,ii)
        K = number_states(j);
        M = zeros(L3,K);
        for l = 1:L3
            ind = (i-1)*L1 + (j-1)*L3 + l;
            M(l,:) = test_group{ind}.p_fractional_occupancy';
        end
        imagesc(M,[0 0.25]); colorbar
        title([titles{i} ' K=' num2str(K)])
        ylabel('PCA components');xlabel('States')
        ii = ii + 1;
    end
end

% switching rate
figure(2);clf(2)
ii = 1;
for i = 1:3
    subplot(1,3,i)
    M = zeros(L3,L2);
    for j = 1:L2
        for l = 1:L3
            ind = (i-1)*L1 + (j-1)*L2 + l;
            M(l,j) = test_group{ind}.p_switching_rate;
        end
    end
    imagesc(M,[0 0.25]); colorbar
    title([titles{i}])
    ylabel('PCA components');xlabel('No. States')
end


function x = stretch_rs ( r, s, i )

%*****************************************************************************80
%
%% STRETCH_RS returns a data component given (R,S).
%
%  Discussion:
%
%    This routine shifts by (1,2) and stretches by (3,4).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 October 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real R, S, the coordinates of a point that lies on the
%    boundary of the square.
%
%    Input, integer I, the component of the data which is to be returned.
%
%    Output, real X, the I-th component of the data vector X, evaluated
%    at the point (R,S), which is on a corner, or edge, of the unit square.
%
  if ( i == 1 )
    x = 3.0 * r + 1.0;
  elseif ( i == 2 )
    x = 4.0 * s + 2.0;
  else
    fprintf ( 1, '\n' );
    fprintf ( 1, 'STRETCH_RS - Fatal error!\n' );
    fprintf ( 1, '  Illegal component index I = %d\n', i );
    error ( 'STRETCH_RS - Fatal error!' );
  end

  return
end


% Focussed 2D Array with Directional Elements
%
% This example demonstrates the use of k-Wave to compute the outputs from a
% curved detector array which consists of several elements, each of which
% consists of a number of grid points.
%
% author: Ben Cox
% date: 29th October 2010
% last update: 22nd February 2012
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox

% This file is part of k-Wave. k-Wave is free software: you can
% redistribute it and/or modify it under the terms of the GNU Lesser
% General Public License as published by the Free Software Foundation,
% either version 3 of the License, or (at your option) any later version.
%
% k-Wave 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 Lesser General Public License for
% more details.
%
% You should have received a copy of the GNU Lesser General Public License
% along with k-Wave. If not, see <http://www.gnu.org/licenses/>.

clear all;

% =========================================================================
% SETUP THE GRID
% =========================================================================

% create the computational grid
Nx = 180;           % number of grid points in the x (row) direction
Ny = 180;           % number of grid points in the y (column) direction
dx = 0.1e-3;        % grid point spacing in the x direction [m]
dy = 0.1e-3;        % grid point spacing in the y direction [m]
kgrid = makeGrid(Nx, dx, Ny, dy);

% define the properties of the propagation medium
medium.sound_speed = 1500;    % [m/s]

% define the array of time points [s]
[kgrid.t_array, dt] = makeTime(kgrid, medium.sound_speed);
Nt = round(0.75*length(kgrid.t_array));
kgrid.t_array = (0:Nt-1)*dt;

% =========================================================================
% DEFINE A FOCUSSED ARRAY OF DIRECTIONAL ELEMENTS
% =========================================================================

% define a semicircular sensor centered on the grid
semicircle_radius = 65; % [grid points]
arc = makeCircle(Nx, Ny, Nx/2, Ny/2, semicircle_radius, pi);

% find total number and indices of the grid points constituting the
% semicircle
arc_indices = find(arc == 1);
Nv = length(arc_indices);

% calculate angles between grid points in the arc and the centre of the
% grid
arc_angles = atan((kgrid.y(arc_indices))./kgrid.x(arc_indices));

% sort the angles into ascending order, and adjust the indices accordingly
[sorted_arc_angles,sorted_index] = sort(arc_angles);
sorted_arc_indices = arc_indices(sorted_index);

% divide the semicircle into Ne separate sensor elements
Ne = 13;
sensor.mask = zeros(Nx,Ny);
for loop = 1:Ne

    % the indices of the grid points belonging to one element.
    % (There is a two grid point gap between the elements.)
    voxel_indices = sorted_arc_indices(floor((loop-1)*Nv/Ne)+2:floor(loop*Nv/Ne)-1);

    % add the element to the sensor.mask
    sensor.mask(voxel_indices) = 1;

end

% =========================================================================
% SIMULATION
% =========================================================================

% Define an infinitely wide plane wave source. (This is achieved by turning
% off the PML.)
source.p_mask = zeros(Nx,Ny);
source.p_mask(140,:) = 1;

% set the display mask for the simulation
display_mask = source.p_mask + sensor.mask;

% define a time varying sinusoidal source
source_freq = 1e6;
source_mag = 0.5;
source.p = source_mag*sin(2*pi*source_freq*kgrid.t_array);
source.p = filterTimeSeries(kgrid, medium, source.p);

% run the simulation with the PML switched off on the sides, so that the
% source continues up to the edge of the domain (and from there infinitely,
% because of the periodic assumption implicit in pseudospectral methods).
input_args = {'PMLAlpha', [2 0], 'DisplayMask', display_mask, 'PlotScale', [-0.75 0.75]};
sensor_data = kspaceFirstOrder2D(kgrid, medium, source, sensor, input_args{:});

% split up the data, recorded on all the grid points, between the elements
element_data = zeros(Ne,Nt);
for loop = 1:Ne

    % the indices of the sensor grid points in the sensor mask
    sensor_indices = find(sensor.mask==1);

    % the indices of the grid points belonging to one element.
    voxel_indices = sorted_arc_indices(floor((loop-1)*Nv/Ne)+2:floor(loop*Nv/Ne)-1);

    % indices of sensor_data that refer to the data for this element
    data_indices = zeros(length(voxel_indices),1);
    for loop2 = 1:length(voxel_indices)
        data_indices(loop2) = find(sensor_indices == voxel_indices(loop2));
    end

    % for one element per loop, average the time series from each of the
    % element's grid points to give one time series for the whole element
    element_data(loop,:) = mean(sensor_data(data_indices,:),1);

end

% =========================================================================
% VISUALISATION
% =========================================================================

% plot the elements of the array, and the source mask
figure;
imagesc(display_mask);
axis image;
colormap(flipud(gray));

% plot the time series recorded at each array element
figure;
stackedPlot(kgrid.t_array*1e6, element_data);
xlabel('time [\mus]');
ylabel('time series, one for each element');


%TRAINSEG	Interactively train a color segmentation
%
%	map = trainseg(im)
%
%	Two windows are displayed, one the bivariant histogram in
%	normalized (r,g) coordinates, the other the original image.
%
%	For each pixel selected and clicked in the original image a point
%	is marked in the bivariant histogram.  By selecting numerous points
%	in the color region of interest, its extent in the (r,g) plane
%	develops.
%
%	This map can be smoothed, expanded and filled in using morphological
%	operations.
%
% SEE ALSO: colorseg imorph

% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Machine Vision Toolbox for Matlab (MVTB).
%
% MVTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% MVTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with MVTB.  If not, see <http://www.gnu.org/licenses/>.
function map = colorseg(im)

	% convert image to (r,g) coordinates
	y = sum(im, 3);
	r = round( im(:,:,1) ./ y * 255);
	g = round( im(:,:,2) ./ y * 255);

	% display the original image

	% create and display the map
	map = zeros(256, 256);
	hm = figure
	set(gcf, 'Units', 'normalized', 'Position', [0.1 0.5 0.8 0.4])
	subplot(121)
	image(im)
	axis('equal')
	title('input image')

	subplot(122)
	image(map)
	axis('equal')
	xlabel('r');
	ylabel('g');
	colormap(gray(2));
	title('segmentation map')

	while 1,
		subplot(121)
		[y,x] = ginput(1);
		if isempty(y),
			break;
		end
		x = round(x);
		y = round(y);
		map(r(x,y), g(x,y)) = 256;
		subplot(122)
		image(map)
		drawnow
	end

	map = map';


function [] = dualcolorplot(x,y,F,OPT)
%DUALCOLORPLOT linear plot with dividing line.
% DUALCOLORPLOT(X,Y,F) plots vector Y versus vector X, and places a
% horizontal line on the plot at y-value F.  The line divides the plot into
% red (top) and blue (bottom).  The user is able to click on the dividing
% line then drag it up and down to change the proportion of red to blue.
%
% DUALCOLORPLOT(X,Y,F,'interp') forces linear interpolation between top and
% bottom colors so that they meet at the horizontal line.  This is slightly
% slower than the default for very large vectors.
%
% A context menu is provided for each of the lines in order to alter their
% appearance.  Simply right-click on any of the lines to see the
% options.  A context menu is also provided for the axes to turn on or off
% automatic scaling.  This can be useful if in zoom mode.
%
% NOTE:
% Calling DUALCOLORPLOT will set the following properties of the current
%         figure:  windowbuttondownfcn
%                  windowbuttonupfcn,
%                  windowbuttonmotionfcn
%
% and the uicontextmenu for the current axes.
%
% THIS FUNCTION REQUIRES LINECMENU BE ON THE PATH.
%
%
% EXAMPLES:
%           x = -2*pi:.01:2*pi;
%           f = @(x) sin(x).*exp(x/5);
%           dualcolorplot(x,f(x),0)  % Right click on lines and axes!
%
%
%           % Show the difference interpolation makes by exaggeration...
%           x = 0:.25:8*pi;  % A thinly populated plot
%           y = sin(x);
%           subplot(1,2,1)
%           dualcolorplot(x,y,0)
%           title('No Interpolation.')
%           subplot(1,2,2)
%           dualcolorplot(x,y,0,'interp')
%           title('With Interpolation')
%
%
% See also plot
%
% Author:  Matt Fig
% Data:  3/30/2011

NARG = nargin;

if NARG==3
    flg = 0;
elseif NARG == 4
   if ~ischar(OPT) || ~strncmpi(OPT,'interp',6)
      error('Unknown Fourth option.  See help.')
   end
   flg = 1;  % User wants to interpolate.
else
    error('dualcolorplot requires 3 or 4 input arguments.  See help.')
end

fh = get(0,'currentfigure');

if isempty(fh)
    fh = figure('windowbuttondownfcn',{@fh_wndbtnfcn},...
                'windowbuttonupfcn',{@fh_wndbtnfcn},...
                'windowbuttonmotionfcn',{@fh_wndmtnfcn});
    AX = axes;
else
    set(fh,'windowbuttondownfcn',{@fh_wndbtnfcn},...
           'windowbuttonupfcn',{@fh_wndbtnfcn},...
           'windowbuttonmotionfcn',{@fh_wndmtnfcn});
    AX = get(fh,'currentaxes');

    if isempty(AX)
        AX = axes;
    end
end

L = [];  % This hold the handles to the lines.
V = 1:length(x);  % For indexing... avoid FIND.
mxx = max(x(:));  mnx = min(x(:));  % For the axis limits.
mxy = max(y(:));  mny = min(y(:));
D = (mxy-mny)/10;  % Resize buffer.
fbd = false;  % figure button up/down.
axzm =  true;  % On and off resize axes...  for zoom state.
LUICM = linecmenu;  % Call the LINECMENU function.
AUICM = uicontextmenu('userdata',axzm);
AUIM = uimenu(AUICM,'label','Set Resize OFF');
set(AUIM,'callback',{@ax_cntxtcb});  % Callback for uimenu.
set_colors();  % This is the function which does the work.

    function [] = set_colors(varargin)
    % Sets the appropriate colors, and divides x and y.
        idxlt = y<=F;  % Find the lower portion of the data.
        idxgt = V(~idxlt);
        idxlt = V(idxlt);
        y1 = y;  x1 = x;  % The lower portion of the plot.
        y2 = y;  x2 = x;  % The upper portion of the plot.
        y1(idxgt) = nan;  % NAN won't get plotted.
        y2(idxlt) = nan;

        if flg % User wants interpolated values.
            NN = isnan(y1);
            A = strfind(NN,[1 0]);  % Where interpolations will go.
            B = strfind(NN,[0 1]);
            y1(A) = F;
            y1(B+1) = F;  % At interpolation point, y is the horiz line.
            y2(B) = F;
            y2(A+1) = F;
            % Interpolations for the x variables.
            idx1 = (x(A+1)-x(A))./(y(A+1)-y(A)).*(F-y(A))+x(A);
            idx2 = (x(B+1)-x(B))./(y(B+1)-y(B)).*(F-y(B))+x(B);
            x1(A) = idx1;
            x1(B+1) = idx2;
            x2(B) = idx2;
            x2(A+1) = idx1;
        end

        if isempty(L)  % First time through
            L(1) = line(x2,y2,'color','r');
            L(2) = line(x1,y1,'color','b');
            L(3) = line([mnx mxx],[F F],'color','g',...
                        'tag','HorizLine');
                    % Store data in Horz line userdata.
            set(L(3),'userdata',{L,flg,x,y,D,mnx,mxx,mny,mxy})
            set(AX,'uicontextmenu',AUICM);
            axis([mnx mxx min(mny,F)-D max(mxy,F)+D]) % Adjust axis
            set(L,'uicontextmenu',LUICM)
        else  % Called from callback.
            UD = get(varargin{1},'userdata');
            set(UD{1}(1),'xdata',x2,'ydata',y2);
            set(UD{1}(2),'xdata',x1,'ydata',y1);
            UD{3} = x;
            UD{4} = y;
            set(varargin{1},'userdata',UD)
        end
    end

    function [] = fh_wndbtnfcn(varargin)
    % Windowbutton-up/down-function for figure.
        fbd = ~fbd; % Button up or down?
    end

    function [] = fh_wndmtnfcn(varargin)
    % Windowbuttonmotionfcn for figure.
        CL = get(fh,'currentobject');
        CO = findobj(fh,'tag','HorizLine');  % The horizontal line(s).
        if ~isempty(CL) && any(CL==CO)  % Is current one of the horiz?
            UD = get(CL,'userdata') ;
            flg = UD{2};  % Retrieve the flag for interpolation.

            if fbd  % Button is held down.
                AXD = get(gca,{'currentpo','uicontextm'});% AXES DATA
                set(CL,'ydata',AXD{1}(:,2));

                if get(AXD{2},'userdata')
                    axis([UD{6} UD{7} min(UD{8},AXD{1}(1,2))-...
                         UD{5} max(UD{9},AXD{1}(1,2))+UD{5}])
                end

                F = AXD{1}(1,2);
                x = UD{3};
                y = UD{4};
                set_colors(CL);  % Call the drawing function.
            end

        end
    end

    function [] = ax_cntxtcb(varargin)
    % Callback for the contextmenus to the axes.
        P = get(varargin{1},'parent');
        axzm = ~get(P,'userdata');  % The on/off state is stored here.

        if axzm  % Change the label for the next call.
            set(AUIM,'label','Set Resize OFF')
        else
            set(AUIM,'label','Set Resize ON')
        end

        set(P,'userdata',axzm)  % Set the new value.
    end
end


function [len, labels] = imLength(img, varargin)
% Compute total length of a binary 1D structure.
%
%   LEN = imLength(IMG);
%   When IMG is a binary image, returns the total length of the structure,
%   equal to the number of pixels.
%   This function is intended to be used for debugging purpose.
%
%   LEN = imLength(IMG, RESOL);
%   Compute the length in user unit, by multiplying length in pixel by the
%   resolution.
%
%   [LEN, LABELS] = imLength(LBL, ...);
%   When LBL is a label image, returns the total length of each label
%   different from 0. Returns also the set of unique values in LBL.
%

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

%   HISTORY

% check image dimension
if ndims(img)>2 || min(size(img))>1 %#ok<ISMAT>
    error('first argument should be a 1D image');
end

% in case of a label image, return a vector with a set of results
labels = 1;
if ~islogical(img)
    labels = unique(img);
    labels(labels==0) = [];

    len = zeros(length(labels), 1);
    for i=1:length(labels)
        len(i) = imLength(img==labels(i), varargin{:});
    end
    return;
end

% extract resolution if present
resol = 1;
if ~isempty(varargin)
    resol = varargin{1};
end

% Total length of stucture is equal to the number of vertices multiplied by
% the resolution
len = sum(img(:)) * resol;


%  INTERNAL FUNCTION: checks whether the covariance matrix has converged
%
%  ::
%
%    [is_steady,oldK]=check_steady_state_kalman(is_steady,K,oldK,options,t,no_more_missing)
%
%  Args:
%
%     - **is_steady** [true|false]: flag indicating whether or not the steady
%       state is reached
%     - **K** [matrix]: Kalman gain
%     - **oldK** [matrix]: old Kalman gain
%     - **options** [struct]: options for the Kalman filter
%     - **t** [integer]: iteration number
%     - **no_more_missing** [boolean]: true if there are no more missing
%       observations, false otherwise.
%
%  Returns:
%     :
%
%     - **is_steady** [true|false]: flag indicating whether or not the steady
%       state is reached
%     - **oldK** [matrix]: updated old Kalman gain
%
%


%% Hough Circle Transform
% An example using the Hough circle detector.
%
% This program demonstrates circle finding with the Hough transform. We show
% how to use the OpenCV function |cv.HoughCircles| to detect circles in an
% image.
%
% Sources:
%
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/cpp/houghcircles.cpp>
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/python/houghcircles.py>
% * <https://docs.opencv.org/3.2.0/d4/d70/tutorial_hough_circle.html>
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp>
% * <https://docs.opencv.org/3.2.0/da/d53/tutorial_py_houghcircles.html>
%

%% Theory
%
% The Hough Circle Transform works in a roughly analogous way to the
% Hough Line Transform.
%
% In the line detection case, a line was defined by two parameters
% $(r, \theta)$. In the circle case, we need three parameters to define a
% circle:
%
% $$C : ( x_{center}, y_{center}, r )$$
%
% where $(x_{center}, y_{center})$ define the center position (green point)
% and $r$ is the radius, which allows us to completely define a circle, as it
% can be seen below:
%
% <<https://docs.opencv.org/3.2.0/Hough_Circle_Tutorial_Theory_0.jpg>>
%
% For sake of efficiency, OpenCV implements a detection method slightly
% trickier than the standard Hough Transform: _The Hough gradient method_,
% which is made up of two main stages:
%
% * the first stage involves edge detection and finding the possible circle
%   centers
% * the second stage finds the best radius for each candidate center
%
% For more details, please check the book _Learning OpenCV_ or your favorite
% Computer Vision bibliography.
%

%% Code
%
% This program:
%
% * Loads an image and blur it to reduce the noise
% * Applies the _Hough Circle Transform_ to the blurred image .
% * Display the detected circle in a window.
%

%%
% Input image
if ~mexopencv.isOctave() && mexopencv.require('images')
    fname = which('coins.png');
else
    fname = fullfile(mexopencv.root(), 'test', 'detect_blob.png');
end
assert(~isempty(fname) && exist(fname,'file')==2, 'Image not found');
img = cv.imread(fname, 'Color',true);
figure, imshow(img), title('source')

%%
% convert it to grayscale, and reduce noise to avoid false circles detection
gray = cv.cvtColor(img, 'RGB2GRAY');
if true
    gray = cv.medianBlur(gray, 'KSize',5);
else
    gray = cv.GaussianBlur(gray, 'KSize',[7,7], 'SigmaX',0.9, 'SigmaY',0.9);
end

%%
% Hough Circle Transform
%
% * change |MinDist| to detect circles with different distances to each other
% * change |MinRadius| and |MaxRadius| to detect circles of different sizes
tic
circles = cv.HoughCircles(gray, 'Method','Gradient', 'DP',2, ...
    'MinDist',size(gray,1)/8, 'Param1',200, 'Param2',100, ...
    'MinRadius',20, 'MaxRadius',80);
toc

%%
% draw detected circles (outlines and centers), and display the result
circles = cat(1, circles{:});
center = round(circles(:,1:2));
radius = round(circles(:,3));
out = cv.circle(img, center, radius, 'Color',[0 0 255], ...
    'Thickness',2, 'LineType','AA');
out = cv.circle(out, center, 3, 'Color',[0 255 0], ...
    'Thickness','Filled', 'LineType','AA');
figure, imshow(out), title('detected circles')


function savemap()
    % save a current map and its coordinates
    % turned into function by Celso G Reyes 2017

    ZG=ZmapGlobal.Data; % used by get_zmap_globals

    [XX,YY] = meshgrid(gx,gy);
    [nr, nc] = size(valueMap);

    dats = [  reshape(XX,nr*nc,1) reshape(YY,nr*nc,1) reshape(valueMap,nr*nc,1) ];

    [filename, pathname] = uiputfile( ...
        {'*.dat'}, ...
        'Save as');

    fid = fopen([pathname filename],'w') ;
    fprintf(fid,'%9.4f  %9.4f %12.5f \n',dats');
    fclose(fid);
end


function tests = test_drawSphericalPolygon
% Test suite for the file drawSphericalPolygon.
%
%   Test suite for the file drawSphericalPolygon
%
%   Example
%   test_drawSphericalPolygon
%
%   See also
%     drawSphericalPolygon

% ------
% Author: David Legland
% e-mail: david.legland@inrae.fr
% Created: 2022-09-20,    using Matlab 9.9.0.1570001 (R2020b) Update 4
% Copyright 2022 INRAE - BIA-BIBS.

tests = functiontests(localfunctions);

function test_Simple(testCase) %#ok<*DEFNU>
% Test call of function without argument.

p1 = [0 -1 0];
p2 = [0 0 1];
p3 = [-1 0 1];
p4 = [-1 -1 1];
p5 = [-1 -1 0];
poly = [p1 ; p2 ; p3;p4;p5];
hFig = figure; hold on;

h = drawSphericalPolygon([0 0 0 1], poly, 'LineWidth', 2);
assertTrue(testCase, all(ishandle(h)));

close(hFig);


%| argmin(x)
%| argmin(f, x)
%| akin to julia argmin
function out = argmin(f, x)
if isa(f, 'function_handle')
   [~, out] = min(f(x));
else
   [~, out] = min(f);
end


function res = vis_eigmodes(varargin)
%
% Visualize the results of an eigenmode decomposition of a VAR[p] model as
% computed using est_eigmode().
% This plots the characteristic frequencies and damping times of the
% eigenmodes, optionally sorted by dynamical importance [1].
%
% TODO: this function is incomplete. Plotting functionality not yet
% implemented in this function.
%
% Inputs:
%
%   EEG:        EEGLAB dataset containing CAT.EIGMODE substructure
%
% Optional:
%
%     TopPercentEigenmodes: Top percent eigenmodes (0-100)
%                           The percent of eigmodes with highest dynamical importance to plot
%                           Input Range  : [0  100]
%                           Default value: 100
%                           Input Data Type: real number (double)
%
%     ConvertPeriodToHz:    Convert res.period to Hertz
%                           Input Data Type: boolean
%
%     sortEigmodes:         Sort eigmodes by dynamical importance
%                           If true, sort for each window independently.If false, and topPercent < 100, sort each window,
%                           determine the topPercent most frequently occuring eigenmodes (mode across windows),and return these
%                           eigenmodes, unsorted across windows
%                           Input Data Type: boolean
%
%     plotResults:          Plot results
%                           Input Data Type: boolean
%
% Output:
%
%   res:        results structure
%
% See Also: est_eigenmode()
%
% References:
%
% [1] Neumaier A, Schneider T (2001) Estimation of parameters and
%   eigenmodes of multivariate autoregressive models. ACM Transactions on
%   Mathematical Software (TOMS) 27:57
%
% Author: Tim Mullen, 2010, SCCN/INC, UCSD.
% Email:  tim@sccn.ucsd.edu

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

    g = arg_define([0 1],varargin, ...
            arg_norep('EEG',mandatory), ...
            arg({'topPercent','TopPercentEigenmodes'},100,[0 100],'Top percent eigenmodes (0-100). The percent of eigmodes with highest dynamical importance to plot'), ...
            arg({'convertPeriodToHz','ConvertPeriodToHz'},true,[],'Convert res.period to Hertz.'), ...
            arg({'sortEigmodes'},true, [], ['Sort eigmodes by dynamical importance. ' ...
                                            'If true, sort for each window independently.' ...
                                            'If false, and topPercent < 100, sort each window, determine the topPercent most frequently occuring eigenmodes (mode across windows),' ...
                                            'and return these eigenmodes, unsorted across windows']), ...
            arg({'plotResults'},false,[],'Plot results') ...
            );

    % commit some variables to the workspace
    [data g] = hlp_splitstruct(g,{'EEG'});
    arg_toworkspace(data);
    clear data;

    [nch nmodes] = size(EEG.CAT.EIGMODE.modes{1});
    nwins        = length(EEG.CAT.EIGMODE.modes);

    % convert cell data to matrix format
    res.eigmodes    = cell2mat(EEG.CAT.EIGMODE.modes);
    res.eigmodes    = reshape(res.eigmodes,[nch nmodes nwins]);

    if ~isempty(EEG.CAT.EIGMODE.modeconf{1})
        res.eigmodesConf = cell2mat(EEG.CAT.EIGMODE.modeconf);
        res.eigmodesConf = reshape(res.eigmodesConf,[nmodes nwins]);
    else
        res.eigmodesConf = zeros(nmodes, nwins);
    end

    res.period = cell2mat(EEG.CAT.EIGMODE.period);
    res.period = reshape(res.period,[2 nmodes nwins]);
    res.periodConf = squeeze(res.period(2,:,:));
    res.period = squeeze(res.period(1,:,:));

    res.dampingTime = cell2mat(EEG.CAT.EIGMODE.dampingTime);
    res.dampingTime = reshape(res.dampingTime,[2 nmodes nwins]);
    res.dampingTimeConf = squeeze(res.dampingTime(2,:,:));
    res.dampingTime = squeeze(res.dampingTime(1,:,:));

    res.eigenvalues      = cell2mat(EEG.CAT.EIGMODE.lambda);

    % sort the eigmodes by dynamical importance
    res.exctn = cell2mat(EEG.CAT.EIGMODE.exctn);
    res.exctn = reshape(res.exctn,[nmodes nwins]);

    % sort eigmodes by dynamical importance
    if g.sortEigmodes
        [dummy res.topEigmodesIndex] = sort(res.exctn,1,'descend');
    elseif g.topPercent < 100
        % determine which modes occur most frequently across windows
        % and sort rows -- for all windows jointly -- in this order
        [dummy topmodes] = sort(res.exctn,1,'descend');
        topmodes = mode(topmodes,2);

        % remove duplicate topmodes
        for i=1:length(topmodes)
            val = topmodes(i);
            if ~isnan(val)
                topmodes(topmodes==topmodes(i))=NaN; % mark all duplicates
                topmodes(i)=val;
            end
        end
        topmodes(isnan(topmodes))=[];

%         [b m n] = unique_bc(topmodes);
%         mostFreqModes = topmodes(sort(m));
        res.topEigmodesIndex = repmat(topmodes,1,nwins);
    else
        res.topEigmodesIndex = repmat((1:nmodes)',1,nwins);
    end

    % extract the top percent of most important eigenmodes
    numTopEigmodes = round((g.topPercent/100)*size(res.topEigmodesIndex,1));
    res.topEigmodesIndex = res.topEigmodesIndex(1:numTopEigmodes,:);

    % extract the data corresponding to the top eigenmodes
    colshift = nmodes*(0:nwins-1);
    eigmodeLinearIndex = res.topEigmodesIndex + repmat(colshift,numTopEigmodes,1);
    res.exctn       = res.exctn(eigmodeLinearIndex);
    res.eigmodesConf = res.eigmodesConf(eigmodeLinearIndex);
    res.period       = res.period(eigmodeLinearIndex);
    res.periodConf   = res.periodConf(eigmodeLinearIndex);
    res.dampingTime  = res.dampingTime(eigmodeLinearIndex);
    res.dampingTimeConf = res.dampingTimeConf(eigmodeLinearIndex);
    res.eigenvalues     = res.eigenvalues(eigmodeLinearIndex);
    tmp = zeros(nch,numTopEigmodes,nwins);
    for ch=1:nch
        tmpeigmode  = squeeze(res.eigmodes(ch,:,:));
        tmp(ch,:,:) = tmpeigmode(eigmodeLinearIndex);
    end
    res.eigmodes = tmp;

    res.convertPeriodToHz = g.convertPeriodToHz;
    if g.convertPeriodToHz
        res.period = 1./res.period;
        res.periodConf = 1./res.periodConf;
    end


function xyl = Xl(s,row,b0,b1)

if nargin == 1
    row = 2. ;
    b0 = 1. ;
    b1 = 2. ;
end

x = 0 ;

y = b0+(b1-b0)*s ;

xyl = [x ; y] ;