classdef matRad_MinMaxDose < DoseConstraints.matRad_DoseConstraint
    % matRad_MinMaxDose Implements a MinMaxDose constraint
    %   See matRad_DoseConstraint for interface description
    %
    % use log sum exp approximation, see appendix A in
    % http://scitation.aip.org/content/aapm/journal/medphys/41/8/10.1118/1.4883837
    %
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % Copyright 2020 the matRad development team.
    %
    % This file is part of the matRad project. It is subject to the license
    % terms in the LICENSE file found in the top-level directory of this
    % distribution and at https://github.com/e0404/matRad/LICENSES.txt. No part
    % of the matRad project, including this file, may be copied, modified,
    % propagated, or distributed except according to the terms contained in the
    % LICENSE file.
    %
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    properties (Constant)
        name = 'Min/Max dose constraint';
        parameterNames = {'d^{min}', 'd^{max}','method'};
        parameterTypes = {'dose','dose',{'approx','voxelwise'}};
    end

    properties
        parameters = {0,30,1};
        epsilon = 1e-3; %slack parameter for the logistic approximation
    end

    methods
        function obj = matRad_MinMaxDose(minDose,maxDose,method)

            %If we have a struct in first argument
            if nargin == 1 && isstruct(minDose)
                inputStruct = minDose;
                initFromStruct = true;
            else
                initFromStruct = false;
                inputStruct = [];
            end

            %Call Superclass Constructor (for struct initialization)
            obj@DoseConstraints.matRad_DoseConstraint(inputStruct);

            %now handle initialization from other parameters
            if ~initFromStruct

                if nargin < 3 || ~ischar(method)
                    method = 'approx';
                end

                methodIx = find(strcmp(method,obj.parameterTypes{3}));

                if isempty(methodIx) || numel(methodIx) > 1
                    methodIx = 1;
                    msg = ['Dose Constraint method can only be ', strjoin(obj.parameterTypes{3},' or '), '! Using method ''', obj.parameterTypes{3}{methodIx}, '''.'];
                    warning(msg);
                end

                obj.parameters{3} = methodIx;

                if nargin >= 2 && isscalar(maxDose)
                    obj.parameters{2} = maxDose;
                end

                if nargin >= 1 && isscalar(minDose)
                    obj.parameters{1} = minDose;
                end
            end
        end

        %Overloads the struct function to add constraint specific
        %parameters
        function s = struct(obj)
            s = struct@DoseConstraints.matRad_DoseConstraint(obj);
            s.epsilon = obj.epsilon;
        end

        function cu = upperBounds(obj,n)
            switch obj.parameters{3}
                case 1 %logsumexp approx
                    %Validate parameters
                    if obj.parameters{1} <= 0 && isinf(obj.parameters{2}) %Constraint doesn't make sense (min = 0 & max = Inf)
                        cu = [];
                    elseif obj.parameters{2} == Inf %Only min dose
                        cu = Inf;
                    elseif obj.parameters{1} <= 0 %Only max dose
                        cu = obj.parameters{2};
                    else %both are set sensible
                        cu = [Inf; obj.parameters{2}];
                    end
                case 2 %voxelwise
                    cu = obj.parameters{2}*ones(n,1);
                otherwise
                    error(['Min/max dose constraint evaluation method not known!']);
            end
            %cu = [Inf; obj.parameters{2}];
        end
        function cl = lowerBounds(obj,n)
            switch obj.parameters{3}
                case 1 %logsumexp approx
                    if obj.parameters{1} <= 0 && isinf(obj.parameters{2})
                        cl = [];
                    elseif obj.parameters{2} == Inf
                        cl = obj.parameters{1};
                    elseif obj.parameters{1} <= 0
                        cl = 0;
                    else
                        cl = [obj.parameters{1}; 0];
                    end
                case 2
                    cl = obj.parameters{1}*ones(n,1);
                otherwise
                    matRad_cfg = MatRad_Config.instance();
                    matRad_cfg.dispError('Min/max dose constraint evaluation method not known!');
            end
        end

        function jStruct = getDoseConstraintJacobianStructure(obj,n)
            switch obj.parameters{3}
                case 1 %logsumexp approx
                    %Validate parameters
                    if obj.parameters{1} <= 0 && isinf(obj.parameters{2}) %Constraint doesn't make sense (min = 0 & max = Inf)
                        jStruct = ones(n,0);
                    elseif obj.parameters{1} > 0 && isfinite(obj.parameters{2}) %both are set sensible
                        jStruct = ones(n,2);
                    else %Only min or max dose
                        jStruct = ones(n,1);
                    end
                    %jStruct = ones(n,2);
                case 2
                    jStruct = speye(n);
                otherwise
                    matRad_cfg = MatRad_Config.instance();
                    matRad_cfg.dispError('Min/max dose constraint evaluation method not known!');
            end

        end

        %% Calculates the Constraint Function value
        function cDose = computeDoseConstraintFunction(obj,dose)
            %cDose(2) = dose_max + obj.epsilon * log( sum(exp((dose - dose_max)/obj.epsilon)));
            %cDose(1) = dose_min - obj.epsilon * log( sum(exp((dose_min - dose)/obj.epsilon)));
            switch obj.parameters{3}
                case 1 %logsumexp approx
                    cDose = obj.computeDoseConstraintFunctionLogSumExp(dose);
                case 2
                    cDose = obj.computeDoseConstraintFunctionVoxelwise(dose);
                otherwise
                    matRad_cfg = MatRad_Config.instance();
                    matRad_cfg.dispError('Min/max dose constraint evaluation method not known!');
            end
        end

        %% Calculates the Constraint jacobian
        function cDoseJacob  = computeDoseConstraintJacobian(obj,dose)
            switch obj.parameters{3}
                case 1 %logsumexp approx
                    cDoseJacob = obj.computeDoseConstraintJacobianLogSumExp(dose);
                case 2
                    cDoseJacob = obj.computeDoseConstraintJacobianVoxelwise(dose);
                otherwise
                    matRad_cfg = MatRad_Config.instance();
                    matRad_cfg.dispError('Min/max dose constraint evaluation method not known!');
            end
        end
    end

    methods (Access = private)
        % LogSumExp Approximation
        function cDose = computeDoseConstraintFunctionLogSumExp(obj,dose)
            dose_min = min(dose);
            dose_max = max(dose);

            %Validate parameters
            if obj.parameters{1} <= 0 && isinf(obj.parameters{2}) %Constraint doesn't make sense (min = 0 & max = Inf)
                cDose = [];
            elseif obj.parameters{2} == Inf %Only min dose
                cDose = dose_min - obj.epsilon * log( sum(exp((dose_min - dose)/obj.epsilon)));
            elseif obj.parameters{1} <= 0 %Only max dose
                cDose = dose_max + obj.epsilon * log( sum(exp((dose - dose_max)/obj.epsilon)));
            else %both are set sensible
                cDose(2,1) = dose_max + obj.epsilon * log( sum(exp((dose - dose_max)/obj.epsilon)));
                cDose(1,1) = dose_min - obj.epsilon * log( sum(exp((dose_min - dose)/obj.epsilon)));
            end

        end
        function cDoseJacob  = computeDoseConstraintJacobianLogSumExp(obj,dose)
            %Validate parameters
            if obj.parameters{1} <= 0 && isinf(obj.parameters{2}) %Constraint doesn't make sense (min = 0 & max = Inf)
                cDoseJacob = [];
            elseif obj.parameters{2} == Inf %Only min dose
                cDoseJacob(:,1) = exp( (min(dose)-dose)/obj.epsilon );
                cDoseJacob(:,1) = cDoseJacob(:,1)/sum(cDoseJacob(:,1));
            elseif obj.parameters{1} <= 0 %Only max dose
                cDoseJacob(:,1) = exp( (dose-max(dose))/obj.epsilon );
                cDoseJacob(:,1) = cDoseJacob(:,1)/sum(cDoseJacob(:,1));
            else %both are set sensible
                cDoseJacob(:,1) = exp( (min(dose)-dose)/obj.epsilon );
                cDoseJacob(:,1) = cDoseJacob(:,1)/sum(cDoseJacob(:,1));

                cDoseJacob(:,2) = exp( (dose-max(dose))/obj.epsilon );
                cDoseJacob(:,2) = cDoseJacob(:,2)/sum(cDoseJacob(:,2));
            end

        end

        %Exact voxel-wise
        function cDose = computeDoseConstraintFunctionVoxelwise(obj,dose)
            cDose = dose;
        end
        function cDoseJacob  = computeDoseConstraintJacobianVoxelwise(obj,dose)
            cDoseJacob = speye(numel(dose),numel(dose));
        end
    end

end


filename='Bridge_quad_coarse';
 ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'full';
cost = {'compliance'};
weights = [1, 0.1];
constraint = {'volumeConstraint'};
optimizer = 'PROJECTED GRADIENT'; incrementFactor = 1;
filterType = 'P1';

nsteps = 1;
Vfrac_final = 0.2;
Perimeter_target = 1;
optimality_final = 1e-3;
constr_final =1e-3;

Vfrac_initial = 1;
optimality_initial = 1e-3;
constr_initial = 1e-3;
TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;
TOL.nu_plus = 1/3;
TOL.nu_minus = 1/3;


function cS = cordierite

cs_Crd = crystalSymmetry('mmm',[0.568 1 0.549]);
N = Miller({1,0,0},{0,1,0},{0,0,1},{1,1,0},{1,1,1},{1,3,0},{1,1,2},{0,1,1},cs_Crd);
dist = [2.1, 1.05, 3.5, 2.25, 5.3, 3.65, 8.7, 4.45];
cS = crystalShape(N./dist);


function [iT] =  inverse_field(T)
    % inverse displacement field
    % size(T) = [N, M, 2] or
    % size(T) = [N, M, K, 3]
    %
    sz = size(T);
    if ndims(T) == 3
        T(:,:, 1) = imgaussfilt(T(:,:,1), 1.3);
        T(:,:, 2) = imgaussfilt(T(:,:,2), 1.3);

        [n1, n2] = ndgrid(1:sz(1), 1:sz(2));
        fB1 = griddata(T(:,:,1) + n1, T(:,:,2) + n2, n1, n1, n2, 'cubic') - n1;
        fB2 = griddata(T(:,:,1) + n1, T(:,:,2) + n2, n2, n1, n2, 'cubic') - n2;
        iT = cat(3, fB1, fB2);

%         [n1, n2] = ndgrid(1:sz(1), 1:sz(2));
%         F = scatteredInterpolant(fl(T(:,:,1) + n1), fl(T(:,:,2) + n2), fl(n1), 'natural', 'nearest');
%         fB1 = F(n1, n2) - n1;
%         F = scatteredInterpolant(fl(T(:,:,1) + n1), fl(T(:,:,2) + n2), fl(n2), 'natural', 'nearest');
%         fB2 = F(n1, n2) - n2;
%         iT = cat(3, fB1, fB2);
    elseif false%ndims(T) == 4 && size(T,4) == 3 && isa(T, 'double')
        sgm = 1.3;
%         sgm = 0.5;
        T = cat(4, imgaussfilt3(T(:,:,:, 1), sgm), imgaussfilt3(T(:,:,:, 2), sgm), imgaussfilt3(T(:,:,:, 3), sgm));
        iT = mex_inverse_3d_displacements_double(T, 1);
    elseif ndims(T) == 4
        fB = cell(3, 1);
        n = cell(3, 1);
        [n{1}, n{2}, n{3}] = ndgrid(1:sz(1), 1:sz(2), 1:sz(3));
        parfor i = 1:3
%             tic
%             F = scatteredInterpolant(fl(T(:,:,:,1) + n{1}), fl(T(:,:,:,2) + n{2}), fl(T(:,:,:,3) + n{3}), fl(n{i}));
%             tmp = F({1:sz(1), 1:sz(2), 1:sz(3)}) - n{i};
%             toc
%             imagesc(tmp(:,:, 4)); pause;
%             tic
            fB{i} = griddata(T(:,:,:,1) + n{1}, T(:,:,:,2) + n{2}, T(:,:,:,3) + n{3}, ...
                n{i}, n{1}, n{2}, n{3}, 'linear') - n{i};
%             toc
%             imagesc(fB{i}(:,:,4)); pause;
%             imagesc(abs(fB{i}(:,:,4) - tmp(:,:,4))); colorbar; pause;
        end

%         fB1 = griddata(T(:,:,:,1) + n1, T(:,:,:,2) + n2, T(:,:,:,3) + n3, ...
%             n1, n1, n2, n3, 'linear') - n1;
%         fB2 = griddata(T(:,:,:,1) + n1, T(:,:,:,2) + n2, T(:,:,:,3) + n3, ...
%             n2, n1, n2, n3, 'linear') - n2;
%         fB3 = griddata(T(:,:,:,1) + n1, T(:,:,:,2) + n2, T(:,:,:,3) + n3, ...
%             n3, n1, n2, n3, 'linear') - n3;
        iT = cat(4, fB{1}, fB{2}, fB{3});
    end
    iT(isnan(iT))=0;
end


function [data,units] = compute_wing_lengthr_mm(trx,n)

flies = trx.exp2flies{n};
nflies = numel(flies);
data = cell(1,nflies);
for i = 1:nflies,
  fly = flies(i);

  data{i} = trx(fly).wing_lengthr ./ trx.pxpermm;

end
units = parseunits('mm');


% This demo is for classification problem that has parameter(s) to
% optimize. If more parameters to be optimized, more inner LOOCV runs
% (additional for-loop) should be used. All networks corresponding to
% different combinations of parameters should be prepared beforehand.
% Note that this function uses the LOOCV.

%
% Input:
%     result_dir: the directory you want to store all the results in;
%     meth_Net: the brain network construction method;
%     BOLD: time courses extracted using a template;
%     label: the label for each subject; e.g., -1 for normal controls and 1 for patients;
%     para_test_flag: whether or not to perform parameter sensitivity test.
%     varargin: the different parameters for different brain network construction method;
%
% Output:
%     opt_paramt: the best parameter combination in the parameter sensitivity test;
%     opt_t: the selected parameter combination in each parameter optimization fold;
%     AUC,SEN,SPE,F1,Acc,Youden,BalanceAccuracy: model performance;
%     w: weight of each selected features;
%     varargout: the feature selection index for the following finding features section.

% Written by Zhen Zhou, zzstefan@email.unc.edu
% IDEA lab, https://www.med.unc.edu/bric/ideagroup
% Department of Radiology and BRIC, University of North Carolina at Chapel Hill

function [opt_paramt,AUC,SEN,SPE,F1,Acc,opt_t,ttest_p,midw_lasso,w,plot_ROC]=param_select_demo(result_dir,meth_Net,BOLD,label,para_test_flag,varargin)
switch meth_Net
    case {'SR','WSR','GSR'}
        lambda_1=varargin{1};
        lambda_lasso=varargin{2};
    case {'SLR','SGR','WSGR','SSGSR'}
        lambda_1=varargin{1};
        lambda_2=varargin{2};
        lambda_lasso=varargin{3};
    case 'dHOFC'
        W=varargin{1};
        s=varargin{2};
        C=varargin{3};
        lambda_lasso=varargin{4};
end
%clear; close all;
%meth_Net='WSR'
root=pwd;
addpath(genpath([root '/Function']));
addpath(genpath([root '/Toolbox']));

%% Load BOLD signals
%load('demo_param_select_toydata.mat');    % This is just an example data including 10 subjects only
%load('demo_framwk_toydata.mat');
% You can replace this by your own dataset
% BOLD: A cell array, each matrix includes BOLD signals (137 volumes x 116 ROIs) of one subject
% label: class labels, 1 for patient and -1 for healthy controls

[~,nROI]=size(BOLD{1});
nSubj=length(BOLD);

% Construct FC networks under different parameters
% mkdir ./Generated_BrainNet_test
% dir=['./Generated_BrainNet_test/'];

fprintf('Begin network construction\n');
switch meth_Net
    case 'SR'       % Sparse representation
        lambda=lambda_1; % parameter for sparsity
        parfor i=1:length(lambda)
            BrainNet{i}=SR(BOLD,lambda(i));
        end
        %save (char(strcat(dir,meth_Net,'_net.mat')),'BrainNet','-v7.3');
    case 'WSR'      % PC weighted SR
        lambda=lambda_1; % parameter for sparsity
        parfor i=1:length(lambda)
            BrainNet{i}=WSR(BOLD,lambda(i));
        end
        %save (char(strcat(dir,meth_Net,'_net.mat')),'BrainNet','-v7.3');

    case 'SLR'      % Sparse low-rank representation
        lambda1=lambda_1;
        lambda2=lambda_2;
        num_lambda1=length(lambda1);
        num_lambda2=length(lambda2);
        parfor i=1:num_lambda1
            for j=1:num_lambda2
                BrainNet{i,j}=SLR(BOLD,lambda1(i),lambda2(j));
            end
        end
        BrainNet=reshape(BrainNet,1,num_lambda1*num_lambda2);
        %save (char(strcat(dir,meth_Net,'_net.mat')),'BrainNet','-v7.3');

    case 'SGR'      % Sparse group representation
        lambda1=lambda_1; % parameter for sparsity
        lambda2=lambda_2; % parameter for group sparsity
        num_lambda1=length(lambda1);
        num_lambda2=length(lambda2);
        parfor i=1:num_lambda1
            for j=1:num_lambda2
                BrainNet{i,j}=SGR(BOLD,lambda1(i),lambda2(j));
            end
        end
        BrainNet=reshape(BrainNet,1,num_lambda1*num_lambda2);
        save (char(strcat(result_dir,meth_Net,'_net.mat')),'BrainNet','-v7.3');

    case 'WSGR'     % PC weighted SGR
        lambda1=lambda_1; % parameter for sparsity
        lambda2=lambda_2; % parameter for group sparsity
        num_lambda1=length(lambda1);
        num_lambda2=length(lambda2);
        parfor i=1:num_lambda1
            for j=1:num_lambda2
                BrainNet{i,j}=WSGR(BOLD,lambda1(i),lambda2(j));
            end
        end
        BrainNet=reshape(BrainNet,1,num_lambda1*num_lambda2);
        %save (char(strcat(dir,meth_Net,'_net.mat')),'BrainNet','-v7.3');

    case 'GSR'      % Group sparse representation
        lambda=lambda_1;
        parfor i=1:length(lambda)
            BrainNet{i}=GSR(BOLD,lambda(i));
        end
        %save (char(strcat(dir,meth_Net,'_net.mat')),'BrainNet','-v7.3');

    case 'SSGSR'    % Strength and Similarity guided GSR
        lambda1=lambda_1; % parameter for group sparsity
        lambda2=lambda_2; % parameter for inter-subject LOFC-pattern similarity
        num_lambda1=length(lambda1);
        num_lambda2=length(lambda2);
        parfor i=1:num_lambda1
            for j=1:num_lambda2
                BrainNet{i,j}=SSGSR(BOLD,lambda1(i),lambda2(j));
            end
        end
        BrainNet=reshape(BrainNet,1,num_lambda1*num_lambda2);
        %save (char(strcat(dir,meth_Net,'_net.mat')),'BrainNet','-v7.3');

    case 'dHOFC'    % Dynamic high-order FC
        num_C=length(C);
        num_W=length(W);
        parfor i=1:num_W % number of clusters
            for j=1:num_C
                [BrainNet{i,j},IDX{i,j}]=dHOFC(BOLD,W(i),s,C(j));
            end
        end
        BrainNet=reshape(BrainNet,1,num_W*num_C);
        %save (char(strcat(dir,meth_Net,'_net.mat')),'BrainNet','-v7.3');
end
fprintf('Network construction finished\n');

% Note, usually, multiple networks with different parameters will be
% established beforehand so that the results can be stored and called
% during parameter selection to save computational time

% Extract features from FC networks under different parameters
if ~strcmpi(meth_Net,'dHOFC')
    idxtu=triu(ones(nROI,nROI));
    for i=1:length(BrainNet)
        Feat=zeros(nSubj,nROI*(nROI-1)/2);  % choose FC strengths as features
        for j=1:nSubj
            tempNet=BrainNet{i}(:,:,j);
            %tempA=tempNet(idxtu~=0);
            Feat(j,:)=tempNet(idxtu==0); % only use the upper trangle coefficients since
            % brain network has been symmetric
        end
        All_Feat{i} = Feat;
    end

else
    %idxtu=triu(ones(nROI,nROI),1);
    for i=1:length(BrainNet)
        temp=ceil(i/length(W));
        Feat=zeros(nSubj,C(temp));
        flag=2;
        for j=1:nSubj
            Feat(j,:)=wlcc(BrainNet{i}(:,:,j),flag);
        end
        All_Feat{i} = Feat;
    end
end

e = 1:nSubj;
indx = floor(nSubj*[1:10]/10);
cpred = zeros(nSubj,1);
acc = zeros(nSubj,1);
score = zeros(nSubj,1);

% LOOCV for testing
for i=1:nSubj
    ind = find(indx == i);
    if ~isempty(ind)
        fprintf(1,'Begin process %d%%...\n',ind*10);
    end

    Tst_ind = i;
    telabel = label(i);
    Trn_ind = e;
    Trn_ind(i) = [];
    trlabel = label;
    trlabel(i) = [];

    % Nested LOOCV on Train data for Model selection
    max_acc = 0;
    for t = 1:length(All_Feat)
        % Feature generation
        Feat = All_Feat{t};
        tmpTestCorr = zeros(length(trlabel),1);
        for j =1:length(trlabel)
            % LOOCV on Training Set
            Tst1_ind = Trn_ind(j);
            telabel1 = trlabel(j);
            Trn1_ind = Trn_ind;
            Trn1_ind(j) = [];
            trlabel1 = trlabel;
            trlabel1(j) = [];

            trFe = Feat(Trn1_ind,:);
            teFe = Feat(Tst1_ind,:);

            % Feature selection using t-test
            if ~strcmpi(meth_Net,'dHOFC')
                pval=0.05;  % generally use pval<0.05 as a threshold for feature selection
                [~,p]=ttest2(trFe(trlabel1==-1,:),trFe(trlabel1==1,:));
                trFe=trFe(:,p<pval);
                teFe=teFe(:,p<pval);

                midw=lasso(trFe,trlabel1,'Lambda',lambda_lasso);  % parameter lambda for sparsity
                trFe=trFe(:,midw~=0);
                teFe=teFe(:,midw~=0);
            else
                midw=lasso(trFe,trlabel1,'Lambda',lambda_lasso);  % parameter lambda for sparsity
                trFe=trFe(:,midw~=0);
                teFe=teFe(:,midw~=0);
            end

            % Feature normalization
            Mtr=mean(trFe);
            Str=std(trFe);
            trFe=trFe-repmat(Mtr,size(trFe,1),1);
            trFe=trFe./repmat(Str,size(trFe,1),1);
            teFe=teFe-Mtr;
            teFe=teFe./Str;

            % train SVM model
            classmodel=svmtrain(trlabel1,trFe,'-t 0 -c 1 -q'); % linear SVM (require LIBSVM toolbox)
            % classify
            [~,acc,~]=svmpredict(telabel1,teFe,classmodel,'-q');
            tmpTestCorr(j,1) = acc(1);
        end
        mTestCorr(t) = sum(tmpTestCorr)/length(tmpTestCorr);
        if mTestCorr(t)>max_acc
            max_acc = mTestCorr(t);
            opt_t(i) = t;
        end
    end
    % Feature generation
    Feat = All_Feat{opt_t(i)};
    trFe = Feat(Trn_ind,:);
    teFe = Feat(Tst_ind,:);

    % Feature selection ag
    if ~strcmpi(meth_Net,'dHOFC')
        pval=0.05;  % generally use pval<0.05 as a threshold for feature selection
        [~,p]=ttest2(trFe(trlabel==-1,:),trFe(trlabel==1,:));
        trFe=trFe(:,p<pval);
        teFe=teFe(:,p<pval);
        ttest_p{i}=p;

        midw=lasso(trFe,trlabel,'Lambda',lambda_lasso);  % parameter lambda for sparsity
        trFe=trFe(:,midw~=0);
        teFe=teFe(:,midw~=0);
        midw_lasso{i}=midw;
    else
        midw=lasso(trFe,trlabel,'Lambda',lambda_lasso);  % parameter lambda for sparsity
        trFe=trFe(:,midw~=0);
        teFe=teFe(:,midw~=0);
        midw_lasso{i}=midw;
        ttest_p{i}=midw;

    end

    % Feature normalization ag
    Mtr=mean(trFe);
    Str=std(trFe);
    trFe=trFe-repmat(Mtr,size(trFe,1),1);
    trFe=trFe./repmat(Str,size(trFe,1),1);
    teFe=teFe-Mtr;
    teFe=teFe./Str;

    % train SVM model ag
    classmodel=svmtrain(trlabel,trFe,'-t 0 -c 1 -q'); % linear SVM (require LIBSVM toolbox)
    % classify ag
    w{i}=classmodel.SVs'*classmodel.sv_coef;
    [cpred(i),~,score(i)]=svmpredict(telabel,teFe,classmodel,'-q');
end

Acc=100*sum(cpred==label)/nSubj;
[AUC,SEN,SPE,F1,Youden,BalanceAccuracy,plot_ROC]=perfeval(label,cpred,score,result_dir);

if para_test_flag==1
    fprintf('Begin parameter sensitivity test\n');
    for i=1:length(All_Feat)
        Acc_para(i)=parameter_sensitivity_test_loocv(All_Feat{i},nSubj,label,meth_Net,lambda_lasso);
    end
    save (char(strcat(result_dir,'/Acc_para.mat')),'Acc_para');
      switch meth_Net
            case {'SR','WSR','GSR'}
                [opt_paramt]=select_para(meth_Net,Acc_para,lambda);
                save_model(BrainNet,meth_Net,label,result_dir,opt_paramt,Acc_para,lambda_lasso);
                x=lambda;
                for j=1:length(x)
                    x_label{j}=num2str(x(j));
                end
                ind=1:length(x);
                y=Acc_para;
                figure('visible','off');
                bar(ind,y);

                ylim([0,100]);
                set(gca,'XTickLabel',x_label);
                xlabel(sprintf('\x3bb_1'));
                ylabel('Accuracy');
                title('Parameter sensitivity test');
                print(gcf,'-r1000','-dtiff',char(strcat(result_dir,'/para_sensitivity.tiff')));
                %print(gcf,'-depsc',char(strcat(result_dir,'/para_sensitivity.eps')));
             case {'SLR','SGR','WSGR','SSGSR'}
                 [opt_paramt]=select_para(meth_Net,Acc_para,lambda1,lambda2);
                 save_model(BrainNet,meth_Net,label,result_dir,opt_paramt,Acc_para,lambda_lasso);
                 x=lambda2;
                 y=lambda1;
                 for i=1:length(x)
                    x_label{i}=num2str(x(i));
                 end
                 for j=1:length(y)
                    y_label{j}=num2str(y(j));
                 end
                 z=reshape(Acc_para,num_lambda1,num_lambda2);
                 figure('visible','off');
                 Bar1=bar3(z);
                 for Element = 1:length(Bar1)
                    ZData = get(Bar1(Element),'ZData');
                    set(Bar1(Element), 'CData', ZData,...
                        'FaceColor', 'interp');
                 end
                 colorbar
                 zlim([0,100]);
                 xlabel(sprintf('\x3bb_2'));
                 ylabel(sprintf('\x3bb_1'));
                 zlabel(sprintf('Accuracy'));
                 if length(x)>=8
                     ind_x=1:2:length(x);
                     set(gca,'XTick',ind_x,'XTickLabel',x_label(1:2:end));
                 else
                     ind_x=1:length(x);
                     set(gca,'XTick',ind_x,'XTickLabel',x_label);
                 end
                 if length(y)>=8
                     ind_y=1:2:length(y);
                     set(gca,'YTick',ind_y,'YTickLabel',y_label(1:2:end));
                 else
                     ind_y=1:length(y);
                     set(gca,'YTick',ind_y,'YTickLabel',y_label);
                 end
                 title('Parameter sensitivity test');
                 print(gcf,'-r1000','-dtiff',char(strcat(result_dir,'/para_sensitivity.tiff')));
                 %print(gcf,'-depsc',char(strcat(result_dir,'/para_sensitivity.eps')));
             case 'dHOFC'
                 [opt_paramt]=select_para(meth_Net,Acc_para,W,C);
                 save_model(BrainNet,meth_Net,label,result_dir,opt_paramt,Acc_para,lambda_lasso);
                 x=C;
                 y=W;
                 for i=1:length(x)
                    x_label{i}=num2str(x(i));
                 end
                 for j=1:length(y)
                    y_label{j}=num2str(y(j));
                 end
                 z=reshape(Acc_para,length(W),length(C));
                 figure('visible','off');
                 Bar1=bar3(z);
                 for Element = 1:length(Bar1)
                    ZData = get(Bar1(Element),'ZData');
                    set(Bar1(Element), 'CData', ZData,...
                        'FaceColor', 'interp');
                 end
                 colorbar
                 zlim([0,100]);
                 xlabel(sprintf('Number of Clusters'));
                 ylabel(sprintf('Window Length'));
                 zlabel(sprintf('Accuracy'));
                 if length(x)>=8
                     ind_x=1:2:length(x);
                     set(gca,'XTick',ind_x,'XTickLabel',x_label(1:2:end));
                 else
                     ind_x=1:length(x);
                     set(gca,'XTick',ind_x,'XTickLabel',x_label);
                 end
                 if length(y)>=8
                     ind_y=1:2:length(y);
                     set(gca,'YTick',ind_y,'YTickLabel',y_label(1:2:end));
                 else
                     ind_y=1:length(y);
                     set(gca,'YTick',ind_y,'YTickLabel',y_label);
                 end
                 title('Parameter sensitivity test');
                 print(gcf,'-r1000','-dtiff',char(strcat(result_dir,'/para_sensitivity.tiff')));
      end
      fprintf('End parameter sensitivity test\n');
end

k_times=10;
switch meth_Net
        case {'SR','WSR','GSR'}
            [result_features]=back_find_low_node_para(result_dir,nSubj,k_times,nROI,w,'loocv',ttest_p,midw_lasso);
            write_log(result_dir,meth_Net,'loocv',AUC,SEN,SPE,F1,Acc,Youden,BalanceAccuracy,lambda_1,lambda_lasso,opt_paramt,k_times,opt_t);
        case {'SGR','WSGR','SSGSR','SLR'}
            [result_features]=back_find_low_node_para(result_dir,nSubj,k_times,nROI,w,'loocv',ttest_p,midw_lasso);
            write_log(result_dir,meth_Net,'loocv',AUC,SEN,SPE,F1,Acc,Youden,BalanceAccuracy,lambda_1,lambda_2,lambda_lasso,opt_paramt,k_times,opt_t);
        case 'dHOFC'
            [result_features]=back_find_high_node(W,C,nROI,w,midw_lasso,IDX,opt_t);
            write_log(result_dir,meth_Net,'loocv',AUC,SEN,SPE,F1,Acc,Youden,BalanceAccuracy,W,s,C,lambda_lasso,opt_paramt,k_times,opt_t);
end

save (char(strcat(result_dir,'/result_features.mat')),'result_features');


function [positions, time] = tracker_ransac(video_path, img_files, pos, target_sz, ...
	padding, kernel, lambda, output_sigma_factor, interp_factor, cell_size, ...
	features, show_visualization)
%TRACKER Kernelized/Dual Correlation Filter (KCF/DCF) tracking.
%   This function implements the pipeline for tracking with the KCF (by
%   choosing a non-linear kernel) and DCF (by choosing a linear kernel).
%
%   It is meant to be called by the interface function RUN_TRACKER, which
%   sets up the parameters and loads the video information.
%
%   Parameters:
%     VIDEO_PATH is the location of the image files (must end with a slash
%      '/' or '\').
%     IMG_FILES is a cell array of image file names.
%     POS and TARGET_SZ are the initial position and size of the target
%      (both in format [rows, columns]).
%     PADDING is the additional tracked region, for context, relative to
%      the target size.
%     KERNEL is a struct describing the kernel. The field TYPE must be one
%      of 'gaussian', 'polynomial' or 'linear'. The optional fields SIGMA,
%      POLY_A and POLY_B are the parameters for the Gaussian and Polynomial
%      kernels.
%     OUTPUT_SIGMA_FACTOR is the spatial bandwidth of the regression
%      target, relative to the target size.
%     INTERP_FACTOR is the adaptation rate of the tracker.
%     CELL_SIZE is the number of pixels per cell (must be 1 if using raw
%      pixels).
%     FEATURES is a struct describing the used features (see GET_FEATURES).
%     SHOW_VISUALIZATION will show an interactive video if set to true.
%
%   Outputs:
%    POSITIONS is an Nx2 matrix of target positions over time (in the
%     format [rows, columns]).
%    TIME is the tracker execution time, without video loading/rendering.
%
%   Joao F. Henriques, 2014

	%if the target is large, lower the resolution, we don't need that much
	%detail
	resize_image = (sqrt(prod(target_sz)) >= 100);  %diagonal size >= threshold
	if resize_image,
		pos = floor(pos / 2);
		target_sz = floor(target_sz / 2);
	end

	%window size, taking padding into account
	window_sz = floor(target_sz * (1 + padding));

% 	%we could choose a size that is a power of two, for better FFT
% 	%performance. in practice it is slower, due to the larger window size.
% 	window_sz = 2 .^ nextpow2(window_sz);

	%create regression labels, gaussian shaped, with a bandwidth
	%proportional to target size
	output_sigma = sqrt(prod(target_sz)) * output_sigma_factor / cell_size;
	yf = fft2(gaussian_shaped_labels(output_sigma, floor(window_sz / cell_size)));

	%store pre-computed cosine window
	cos_window = hann(size(yf,1)) * hann(size(yf,2))';

	if show_visualization,  %create video interface
		update_visualization = show_video(img_files, video_path, resize_image);
	end

	%note: variables ending with 'f' are in the Fourier domain.

	time = 0;  %to calculate FPS
	positions = zeros(numel(img_files), 2);  %to calculate precision

	for frame = 1:numel(img_files),
		%load image
		im = imread([video_path img_files{frame}]);
		if size(im,3) > 1,
			im = rgb2gray(im);
		end
		if resize_image,
			im = imresize(im, 0.5);
		end

		tic()

		if frame == 1
			camera_feat.detector = cv.FeatureDetector('SURF');
			camera_feat.extractor = cv.DescriptorExtractor('SURF');
			camera_feat.matcher = cv.DescriptorMatcher('FlannBased');
			camera_feat.last_keypoints = camera_feat.detector.detect(im);
			camera_feat.last_descriptors = camera_feat.extractor.compute(im, camera_feat.last_keypoints);
		end

		if frame > 1,
			[camera_feat, camera_H] = find_homography(camera_feat, im, pos, target_sz);
			pos = project_t(pos([2, 1]), camera_H);
            pos = pos([2, 1]);
            pos = min([size(im,1),size(im,2)], pos);
            pos = max([0,0], pos);
			%obtain a subwindow for detection at the position from last
			%frame, and convert to Fourier domain (its size is unchanged)
			patch = get_subwindow(im, pos, window_sz);
			zf = fft2(get_features(patch, features, cell_size, cos_window));

			%calculate response of the classifier at all shifts
			switch kernel.type
			case 'gaussian',
				kzf = gaussian_correlation(zf, model_xf, kernel.sigma);
			case 'polynomial',
				kzf = polynomial_correlation(zf, model_xf, kernel.poly_a, kernel.poly_b);
			case 'linear',
				kzf = linear_correlation(zf, model_xf);
			end
			response = real(ifft2(model_alphaf .* kzf));  %equation for fast detection

			%target location is at the maximum response. we must take into
			%account the fact that, if the target doesn't move, the peak
			%will appear at the top-left corner, not at the center (this is
			%discussed in the paper). the responses wrap around cyclically.
			[vert_delta, horiz_delta] = find(response == max(response(:)), 1);
			if vert_delta > size(zf,1) / 2,  %wrap around to negative half-space of vertical axis
				vert_delta = vert_delta - size(zf,1);
			end
			if horiz_delta > size(zf,2) / 2,  %same for horizontal axis
				horiz_delta = horiz_delta - size(zf,2);
			end
			pos = pos + cell_size * [vert_delta - 1, horiz_delta - 1];
		end

		%obtain a subwindow for training at newly estimated target position
		patch = get_subwindow(im, pos, window_sz);
		xf = fft2(get_features(patch, features, cell_size, cos_window));

		%Kernel Ridge Regression, calculate alphas (in Fourier domain)
		switch kernel.type
		case 'gaussian',
			kf = gaussian_correlation(xf, xf, kernel.sigma);
		case 'polynomial',
			kf = polynomial_correlation(xf, xf, kernel.poly_a, kernel.poly_b);
		case 'linear',
			kf = linear_correlation(xf, xf);
		end
		alphaf = yf ./ (kf + lambda);   %equation for fast training

		if frame == 1,  %first frame, train with a single image
			model_alphaf = alphaf;
			model_xf = xf;
		else
			%subsequent frames, interpolate model
			model_alphaf = (1 - interp_factor) * model_alphaf + interp_factor * alphaf;
			model_xf = (1 - interp_factor) * model_xf + interp_factor * xf;
		end

		%save position and timing
		positions(frame,:) = pos;
		time = time + toc();

		%visualization
		if show_visualization,
			box = [pos([2,1]) - target_sz([2,1])/2, target_sz([2,1])];
			stop = update_visualization(frame, box);
			if stop, break, end  %user pressed Esc, stop early

			drawnow
% 			pause(0.05)  %uncomment to run slower
		end

	end

	if resize_image,
		positions = positions * 2;
	end
end


function ID = spm_data_id(varargin)
% generates a specific real number in a deterministic way
% from any data structure
% FORMAT ID = spm_data_id(X);
% X  - numeric, character, cell or stucture array[s]
% ID - specific ID
%__________________________________________________________________________
% Copyright (C) 2009 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak (based on Karl's spm_vec)
% $Id: spm_data_id.m 6712 2016-02-04 15:12:25Z peter $

X     = varargin;

if length(X) == 1
    X = X{1};
end

ID = 0;

if ischar(X) % For now strings are not taken into account
    ID = 0;
elseif isnumeric(X)
    Y = double(X(:));
    ID = sum(abs(Y(~isnan(Y) & ~isinf(Y))));
elseif isstruct(X) || isobject(X)
    X = struct(X);
    f = fieldnames(X);
    X = X(:);
    ID = 0;
    for i = 1:length(f)
        ID = ID + spm_data_id({X.(f{i})});
    end
elseif iscell(X)
    X     = X(:);
    ID = 0;
    for i = 1:length(X)
        ID = ID + spm_data_id(X{i});
    end
end

if ID > 0
    ID = 10^-(floor(log10(ID))-2)*ID;
end


function g = gpsimLogLikeGradients(model)

% GPSIMLOGLIKEGRADIENTS Compute the gradients of the log likelihood of a GPSIM model.
% FORMAT
% DESC computes the gradients of the log likelihood of the given
% Gaussian process for use in a single input motif protein network.
% ARG model : the model for which the log likelihood is computed.
% RETURN g : the gradients of the parameters of the model.
%
% SEEALSO : gpsimCreate, gpsimLogLikelihood, gpsimGradient
%
% COPYRIGHT : Neil D. Lawrence, 2006
%
% MODIFIED : Pei Gao, 2008

% SHEFFIELDML

covGrad = -model.invK + model.invK*model.m*model.m'*model.invK;
covGrad = 0.5*covGrad;
if isfield(model, 'proteinPrior') && ~isempty(model.proteinPrior)
  g = kernGradient(model.kern, model.timesCell, covGrad);
else
  g = kernGradient(model.kern, model.t, covGrad);
end

% In case we need priors in.
% Add contribution of any priors
if isfield(model, 'bprior'),
  g = g + kernPriorGradient(model.kern);
end

gmuFull = model.m'*model.invK;

if isfield(model, 'proteinPrior') && ~isempty(model.proteinPrior)
  if model.includeNoise
    ind = model.kern.comp{1}.diagBlockDim{1} + (1:model.kern.comp{1}.diagBlockDim{2});
    gmu = zeros(size(1, model.numGenes));

    for i = 1:model.numGenes
      gmu(i) = sum(gmuFull(ind));
      ind = ind + model.kern.comp{1}.diagBlockDim{i+1};
    end
  else
    ind = model.kern.diagBlockDim{1} + (1:model.kern.diagBlockDim{2});
    gmu = zeros(size(1, model.numGenes));

    for i = 1:model.numGenes
      gmu(i) = sum(gmuFull(ind));
      ind = ind + model.kern.diagBlockDim{i+1};
    end
  end

else
  numData = size(model.t, 1);
  ind = 1:numData;
  gmu = zeros(size(1, model.numGenes));
  for i = 1:model.numGenes
    gmu(i) = sum(gmuFull(ind));
    ind = ind + numData;
  end
end

gb = gmu./model.D;
fhandle = str2func([model.bTransform 'Transform']);
% In case we need priors in.
% Add prior on B if it exists.
if isfield(model, 'bprior');
  gb = gb + priorGradient(model.bprior, model.B);
end

gb = gb.*fhandle(model.B, 'gradfact');

% This is a nasty hack to add the influence of the D in the mean to
% the gradient already computed for the kernel. This is all very
% clunky and sensitive to changes that take place elsewhere in the
% code ...
gd = -gmu.*model.B./(model.D.*model.D);
if model.kern.numBlocks == 1
  decayIndices = 1;
elseif model.kern.numBlocks>1
  if isfield(model, 'proteinPrior') && ~isempty(model.proteinPrior)
    decayIndices = [3];
    for i = 3:model.kern.numBlocks
      decayIndices(end+1) = decayIndices(end) + 2;
    end
  else
    decayIndices = [1 4];
    for i = 3:model.kern.numBlocks
      decayIndices(end+1) = decayIndices(end) + 2;
    end
  end
end

% Account for decay in mean.
g(decayIndices) = g(decayIndices) ...
    + gd.*expTransform(model.D, 'gradfact');

g = [g gb];

if isfield(model, 'fix')
  for i = 1:length(model.fix)
    g(model.fix(i).index) = 0;
  end
end


function rf=lpcao2rf(ao)
%LPCAO2RF LPC: Convert area ratios to reflection coefficients RF=(AO)

%      Copyright (C) Mike Brookes 1998
%      Version: $Id: lpcao2rf.m,v 1.4 2007/05/04 07:01:38 dmb Exp $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

rf = (1-ao)./(1+ao);


function fiber_r=dtiFiberResample(fiber, value, flag)
%Resamples a fiber forcing a given number of nodes or a given step length.
%
% function fiber_r=dtiFiberResample(fiber, value, [flag = 'N'])
%
% Input: flag=='N'
%        Will resample the fiber to the number of points specified by
%        variable 'value' flag=='L' Will resample the fiber to the
%        intervals of length specified by variable 'value'
% Resampling is performed using interpolation with splines.
%
% Example:
%     fiber=fg.fibers{1}; fiber_r=dtiFiberResample(fiber, 10, 'N');
%     plot3(fiber_r(1,:),fiber_r(2,:),fiber_r(3,:),'bx-', ...
%     fiber(1,:),fiber(2,:),fiber(3,:),'ro--');
%     legend('Resampled', 'Original');
%
% See Also: dtiResampleFiberGroup
%
% (c) Vistalab

% HISTORY:
%  2007 ER wrote it
%  2010 ER fixed a bug: resampling of a fiber with
%  seriously unevenly spaced out breakpoints will now return a fiber with
%  evenly spaced ones.

if ~exist('flag', 'var') || isempty(flag)
    flag='N';
end

fiberNoNan=fiber(~isnan(fiber(:, :)));
sizeI=3; sizeJ=size(fiberNoNan, 1)/3;
fiberNoNan=reshape(fiberNoNan, sizeI, sizeJ);

%This block deals with issues a) all NaNs b) oNly one point is not NaN c)
%npoints=1 TODO: revise this block
if(strcmp(flag, 'N') && value==1)||(sizeJ==0) || (sizeJ==1)
    %fiber_r=mean(fiberNoNan, 2);
    error('All NANs, only one point is not NAN, or npoints==1');
end

%Regularize the nodes: Renumerate the nodes by distance from 1st
node2nodedist = squareform(pdist(fiber'));
archcumdist = cumsum(diag(node2nodedist, 1));

F = spline([0 archcumdist'], fiberNoNan);

switch flag
    case 'N'
        % Trajectory
        stepP = archcumdist(end)/(value-1);

    case 'L'
        stepP = value;
    otherwise
        error('Flag should be either L or N');
end

t = 0:stepP:archcumdist(end);
fiber_r=ppval(F,t);
return


function [finalVectors] = detMinSpan(model, params, vectors)
% Calculates the MinSpan vectors for a COBRA model. The
% algorithm determines a set of linearly independent basis vectors that
% span the nullspace that meet the criteria of the flux bounds of the
% network and minimizes the number of reactions used. The algorithm
% operates in an interative manner and checkes for convergence after each
% iteration. Parameters may be provided to skip convergence and terminate
% the problem when models are large. See Bordbar et al. Mol Syst Biol 2014
% for more details. This algorithm has only been tested and requires Gurobi
% as MILP solver.
%
% INPUTS:
%    model:             COBRA model structure (requires S, lb, ub)
%                       Note: MinSpan calculations are done w/o biomass
%                       reaction and all reactions must be able to carry a
%                       flux = 0 for the trivial solution to be feasible.
%                       model is auto corrected by bounds but biomass
%                       must be removed manually
%
% OPTIONAL INPUTS:
%    params:            Optional parameters to calculate MinSpan.
%                       Determining the MinSpan is a NP hard calculation.
%                       For large models, the algorithm may not converge
%                       and parameters must be provided to stop the
%                       algorithm to provide an approximate solution.
%
%                       * .coverage - Number of iterations to run the algorithm, if not
%                       converge (Default = 10)
%                       * .timeLimit - Time to spend on each MinSpan calculation (sec),
%                       (Default = 30)
%                       * .saveIntV - Save intermediate vectors in order to restart from
%                       latest iteration (Default = 0)
%                       * .cores - Number of cores to use (Default = 1)
%
%    vectors:           Set of intermediate MinSpan vectors that may
%                       have not yet reached convergence, allowing to
%                       pickup calculation from last spot.
%
% OUTPUTS:
%    finalVectors:      MinSpan vectors for COBRA model
%
% .. Author: Aarash Bordbar 05/15/2017
%            Ronan Fleming, nullspace computation with LUSOL

global CBT_MILP_SOLVER
global CBT_LP_SOLVER
global CBT_QP_SOLVER

if ~strcmp(CBT_MILP_SOLVER, 'gurobi') || ~strcmp(CBT_LP_SOLVER, 'gurobi') || ~strcmp(CBT_QP_SOLVER, 'gurobi')
    error('detMinSpan only runs with Gurobi.\nTry to run `changeCobraSolver(''gurobi'', ''MILP'')` to use Gurobi.');
end

% Ensure model has correct bounds
origModel = model;
model.lb(model.lb < 0) = -1000;
model.ub(model.ub > 0) = 1000;
model.lb(model.lb > 0) = 0;
model.ub(model.ub < 0) = 0;

% Reduce model to just reactions that can carry a flux
[minF, maxF] = fluxVariability(model, 0);
minF(abs(minF) < 1e-8) = 0;
maxF(abs(maxF) < 1e-8) = 0;
remRxns = model.rxns(minF == 0 & maxF == 0);
model = removeRxns(model, remRxns);

% Setup MILP and solving parameters
if ~exist('params', 'var')
    params.coverage = 10;
    params.timeLimit = 30;
    params.saveIntV = 0;
    params.cores = 1;
    params.nullAlg = 'matlab';
else
    if ~isfield(params, 'coverage')
        params.coverage = 10;
    end
    if ~isfield(params, 'timeLimit')
        params.timeLimit = 30;
    end
    if ~isfield(params, 'saveIntV')
        params.saveIntV = 1;
    end
    if ~isfield(params, 'cores')
        params.cores = 1;
    end
    if ~isfield(params, 'nullAlg')
        params.nullAlg = 'matlab';
    end
end

MILPparams.TimeLimit = params.timeLimit;
MILPparams.outputFlag = 1;
MILPparams.Presolve = 2;
MILPparams.Threads = params.cores;
MILPparams.DisplayInterval = 10;

if ~exist('vectors', 'var')
    if strcmp('params.nullAlg','lusol')
        error('nearly but not quite implemented yet')
        [vectors, ~] = getNullSpace(model.S, 0);
    else
        vectors = null(full(model.S));
    end
end

% Prepratory steps for MinSpan determination
rng('shuffle');

if strcmp('params.nullAlg','lusol')
    [N, ~] = getNullSpace(S, 0);
else
    N = null(full(model.S));
end

[m, n] = size(model.S);

locRev = find(model.lb < 0);
lengthRev = length(locRev);
revConstraintMat = zeros(lengthRev, n);
for i = 1:lengthRev
    revConstraintMat(i, locRev(i)) = 1;
end

% Run MinSpan
tmpNvProd = [];
totalNNZ = [];
for k = 1:params.coverage

    numToCheck = randperm(size(N, 2));
    prevNNZ = nnz(vectors);

    for i = 1:length(numToCheck)
        tic;
        oldPath = vectors(:, numToCheck(i));
        pathLength = nnz(vectors(:, numToCheck(i)));
        vectors(:, numToCheck(i)) = zeros(n, 1);

        sizeN = 1;
        theta = N \ vectors;

        if strcmp('params.nullAlg','lusol')
            [Z, ~] = getNullSpace(theta', 0);
            tmpN = sparse(N * Z);
        else
            tmpN = sparse(N * null(theta'));
        end

        tmptmpNprod = tmpN' * oldPath;
        tmpN = tmpN * (1 / tmptmpNprod);

        % Model Formulation: A, b, csense, lb, ub, vartype, c
        MILPproblem.A = [model.S, sparse(m, n + 2 * sizeN);  % S. v = 0
                         revConstraintMat, 1e4 * revConstraintMat, sparse(lengthRev, 2 * sizeN);  % v >= -10000*b
                         speye(n), -1e4 * speye(n), sparse(n, 2 * sizeN);  % v <= 10000*b
                         tmpN', sparse(sizeN, n), (-1001) * speye(sizeN), sparse(sizeN, sizeN);  % N.v >= 1001*fi+ - 1000
                         -tmpN', sparse(sizeN, n), sparse(sizeN, sizeN), (-1001) * speye(sizeN);  % -N.v >= 1001*fi- - 1000
                         sparse(1, 2 * n), ones(1, 2 * sizeN);  % sum(fi+, fi-) >= 1
                         ];

        MILPproblem.b = [zeros(m, 1);  % S. v = 0
                         zeros(lengthRev, 1);  % v >= -10000*b
                         zeros(n, 1);  % v <= 10000*b
                         -1000 * ones(sizeN, 1);  % N.v >= 1000*fi+ - 1000
                         -1000 * ones(sizeN, 1);  % -N.v >= 1000*fi+ - 1000
                         1  % sum(vi+, vi-) >= 1
                         ];

        MILPproblem.csense = '';
        for l = 1:m
            MILPproblem.csense(end + 1, 1) = 'E';  % S.v = 0
        end
        for l = 1:lengthRev
            MILPproblem.csense(end + 1, 1) = 'G';  % v >= -10000*b
        end
        for l = 1:n
            MILPproblem.csense(end + 1, 1) = 'L';  % v <= 10000*b
        end
        for l = 1:sizeN
            MILPproblem.csense(end + 1, 1) = 'G';  % N.v >= 1000*fi+ - 1000
        end
        for l = 1:sizeN
            MILPproblem.csense(end + 1, 1) = 'G';  % -N.v >= 1000*fi+ - 1000
        end
        MILPproblem.csense(end + 1, 1) = 'G';  % sum(vi+, vi-) > 1

        MILPproblem.lb = [model.lb;  % v
                          zeros(n, 1);  % a
                          zeros(2 * sizeN, 1)];  % fi+, fi-

        MILPproblem.ub = [model.ub;  % v
                          ones(n, 1);  % a
                          ones(2 * sizeN, 1)];  % k+, k-

        MILPproblem.vartype = '';
        for l = 1:n
            MILPproblem.vartype(end + 1, 1) = 'C';  % v
        end
        for l = 1:n
            MILPproblem.vartype(end + 1, 1) = 'B';  % b
        end
        for l = 1:2 * sizeN
            MILPproblem.vartype(end + 1, 1) = 'B';  % fi+, fi-
        end

        MILPproblem.c = [zeros(n, 1);  % v
                         ones(n, 1);  % b
                         zeros(2 * sizeN, 1);  % fi+, fi-
                         ];

        MILPproblem.osense = 1;  % minimize

        % Setup initial solution
        binOldPath = zeros(length(oldPath), 1);
        binOldPath(find(oldPath)) = 1;
        MILPproblem.x0 = [oldPath; binOldPath; 1e101; 1e101];

        MILPsolution = solveCobraMILP(MILPproblem, MILPparams);

        % Check solution
        % If unable to find solution, break iteration
        if length(MILPsolution.cont) < n
            break
        end

        % If solution found, normalize and replace vector in intermediate
        % matrix
        vector = MILPsolution.full(1:n);
        vector(abs(vector) < 1e-6) = 0;

        if strcmp('params.nullAlg','lusol')
            [Z, ~] = getNullSpace((N \ [vectors, vector])', 0);
            tmpNullCheck = N * Z;
        else
            tmpNullCheck = N * null((N \ [vectors, vector])');
        end

        if nnz(vector) > 0 && isempty(tmpNullCheck)
            vector = vector / norm(vector);
            vectors(:, numToCheck(i)) = vector;
        else
            vectors(:, numToCheck(i)) = oldPath;
            vector = oldPath;
        end
        tmpNvProd = [tmpNvProd; tmpN' * vector];
        totalNNZ = [totalNNZ; nnz(vectors)];

        time(i, 1) = toc;

        % Save intermediate matrices (within iteration)
        if params.saveIntV == 1
            filename = strcat('save_', num2str(k), '_', num2str(i));
            save(filename, 'MILPproblem', 'MILPsolution', 'vectors', ...
                 'time', 'tmpNvProd', 'totalNNZ', 'numToCheck');
        end

        clear mex
    end

    newNum = nnz(vectors);

    % Save intermediate matrices (after a completed iteration)
    if params.saveIntV == 1
        filename = strcat('save_finalround_', num2str(k));
        save(filename, 'vectors', 'time');
    end

    % If MinSpan solution has converged (same NNZ as previous iteration)
    if newNum == prevNNZ
        break
    end
end

clear x
for i = 1:size(vectors, 2)
    x(i, 1) = nnz(vectors(:, i));
end

completedPaths = find(x < n & x > 0);
vectors = vectors(:, completedPaths);

% Normalize vectors such that smallest flux value in vector is 1
for i = 1:size(vectors, 2)
    loc = find(vectors(:, i));
    tmp = min(abs(vectors(loc, i)));
    vectors(:, i) = vectors(:, i) / tmp;
end

% Cast vectors from reduce model size to full model size
finalVectors = zeros(length(origModel.rxns), size(vectors, 2));
loc = find(ismember(origModel.rxns, model.rxns));
for i = 1:size(vectors, 2)
    finalVectors(loc, i) = vectors(:, i);
end


function plot_McBwtime(catalog, sPar)
    % plot Mc and b as a function of time using the bootstrap approach
    % Uses the result matrix from calc_McBwtime
    % updated: 14.02.2005
    % J. Woessner
    % turned into function by Celso G Reyes 2017

    ZG = ZmapGlobal.Data; % used by get_zmap_globals

    % Get input

    % Initial values
    nSampleSize = 500;
    nOverlap    = 4;
    methodChoice = 1;
    nBstSample  = 200;
    minEventCount = 50;
    fBinning    = 0.1;
    nWindowSize = 5;
    fMcCorr     = 0;
    default_method       = McMethods.MaxCurvature; % default method
    figure_w_normalized_uicontrolunits(...
        'Name'          , 'Mc Input Parameter',...
        'NumberTitle'   , 'off',...
        'NextPlot'      , 'new',...
        'units'         , 'points',...
        'Visible','off' , ...
        'Position', [ 200 200 500 200]);
    axis off

    % Input parameters

    zdlg = ZmapDialog();
    zdlg.AddMcMethodDropdown('methodChoice', default_method);
    zdlg.AddEdit('nSampleSize'   , 'Sample window size' , nSampleSize   , 'number of events in each window');
    zdlg.AddEdit('minEventCount' , 'Min. # of events'   , minEventCount , 'minimum number of events in order to calc. window');
    zdlg.AddEdit('nOverlap'      , 'Window overlap (%)'     , nOverlap      , 'Samplesize/nOverlap determines overlap of moving windows');
    zdlg.AddEdit('nBstSample'    , 'Bootstraps'         , nBstSample    , 'Number of samples in bootstrap(?)');
    zdlg.AddEdit('fMcCorr'       , 'Mc correction'      , fMcCorr       , 'correction for the magnitude of completeness');
    zdlg.AddEdit('fBinning'      , 'Magnitude Binning'  , fBinning      , 'size of magnitude bins');
    zdlg.AddEdit('windowSize'    , 'Smooth plot'        , nWindowSize   , 'smooth plot');
    [zans,okPressed] = zdlg.Create('Name', 'Mc Input Parameter');

    if ~okPressed
        return
    end

    %% calculate  time series
    windowSize = zans.windowSize;
    catalog.sort('Date');

    [mResult] = calc_McBwtime(catalog, zans.nSampleSize, zans.nOverlap, zans.methodChoice, zans.nBstSample, zans.minEventCount, zans.fBinning, zans.fMcCorr);

    errbarParams = {'LineStyle', '-.', 'Linewidth', 2, 'Color', [0.5 0.5 0.5]};

    % Plot Mc time series
    if sPar == "mc"
        fig = figure('tag','Mc time series', 'visible','on', 'Name','Mc time series');
        resultCol   = [mResult.mcMeanWithTime];
        stdevcol    = [mResult.mcStdDevBoot];
        DisplayName = 'min Mag. Completeness (Mc)';
        errNames    = {'Mc - std', 'Mc + std'};
        myYLabel    = 'Mc';
        myLegend    = {'Mc','\delta Mc'};
    else
        % plot B-value
        fig     = figure('tag','b-value time series', 'visible','on', 'Name','b-value time series');
        resultCol   = [mResult.bMeanWithTime];
        stdevcol    = [mResult.bStdDevBoot];
        DisplayName = 'b-value';
        errNames    = {'b - std', 'b + std'};
        myYLabel    = 'b-value';
        myLegend    = {'b-value','\delta b'};
    end

    y    = filter(ones(1,windowSize)/windowSize, 1, resultCol(:)); %was mMc or mB
    yStd = filter(ones(1,windowSize)/windowSize, 1, stdevcol(:)); % was mMcstd1 or mBstd1

    if length(resultCol) > windowSize
        y(1:windowSize, 1)    = resultCol(1:windowSize);
        yStd(1:windowSize, 1) = stdevcol(1:windowSize);
    end

    x = [mResult.meanSampleTime];

    %% plot
    ax = axes(fig);
    plot(ax, x, y, '-', 'Linewidth', 2, 'Color', [0.2 0.2 0.2], 'DisplayName', DisplayName);
    ax.NextPlot = 'add';
    plot(ax, x, y-yStd, errbarParams{:}, 'DisplayName', errNames{1});
    plot(ax, x, y+yStd, errbarParams{:}, 'DisplayName', errNames{2});
    ax.NextPlot = 'replace';

    xlim(ax, bounds2(x))
    %y_bounds = [floor(min(y-yStd)), ceil(max(y+yStd))];
    %if ~any(ismissing(y_bounds))
    %    ylim(ax, [floor(min(y-yStd)), ceil(max(y+yStd))]);
    %end
    l1 = legend(ax,myLegend{:});
    set(l1, 'Fontweight', 'bold')
    set(ax, 'Fontweight', 'bold', 'FontSize', 10, 'Linewidth', 2, 'Tickdir', 'out')
    xlabel(ax, 'Time / [dec. year]', 'Fontweight', 'bold', 'FontSize',12)
    ylabel(ax, myYLabel, 'Fontweight', 'bold', 'FontSize', 12);

end


function varargout = plotcoeffs(varargin)
%PLOTCOEFFS   Display the PLOTCOEFFS of the column and row slices.
%   PLOTCOEFFS(F) plots the coefficients on a semilogy scale of the
%   underlying basis used in constructing the one-dimensional slices that
%   form F. It returns two figures one for the row slices and one for the
%   column slices.
%
%   PLOTCOEFFS(F, S) allows further plotting options, such as linestyle,
%   linecolor, etc. If S contains a string 'LOGLOG', the coefficients will be
%   displayed on a log-log scale.
%
% See also DISKFUN/PLOTCOEFFS2 and DISKFUN/COEFFS2.

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

[varargout{1:nargout}] = plotcoeffs@separableApprox(varargin{:});

end


function vl_test_ttlayers(gpu, tests)
% VL_TEST_TTLAYERS Test the TT-layer with numeric differentiation
%    VL_TEST_TTLAYERS(0) Test the CPU implementation.
%    VL_TEST_TTLAYERS(1) Test the GPU implementation.

range = 100;

if nargin < 1, gpu = false ; end
if gpu
  grandn = @(varargin) range * gpuArray.randn(varargin{:});
  grand = @(varargin) range * gpuArray.rand(varargin{:});
else
  grandn = @(varargin) range * randn(varargin{:});
  grand = @(varargin) range * rand(varargin{:});
end

switch gpu
  case 0,
    fprintf('testing the CPU code\n');
  case 1
    fprintf('testing the GPU code\n');
end

rng(1);

if nargin < 2
  tests = 1:3;
end

function y = vl_nntt_forward_weights(layer, in, out, iGroup, values)
  layer.weights{iGroup} = values;
  outIn = vl_nntt_forward(layer, in, out);
  y = outIn.x;
end

function y = vl_nntt_forward_x(layer, in, out, x)
  in.x = x;
  outIn = vl_nntt_forward(layer, in, out);
  y = outIn.x;
end

for l = tests
  fprintf('test number %d\n', l)
  % resets random number generator to obtain reproducible results
  if gpu
    parallel.gpu.rng(0, 'combRecursive');
  else
    rng(0, 'combRecursive');
  end
  switch l
    case 1
      disp('Testing vl_nntt_* with the identity TT-matrix.');

      in.x = grandn(8, 32, 3, 4, 'single');
      W = tt_ones([4, 4, 4, 4, 3]);
      W.core = single(W.core);
      W = diag(W);
      layer.W = W;
      layer.weights{1} = W.core;
      if gpu
        layer.weights{1} = gpuArray(layer.weights{1});
      end
      layer.outHeight = 8;
      layer.outWidth = 32;
      layer.outChannels = 3;
      layer.weights{2} = grandn(8 * 32 * 3, 1, 'single');
      out = [];
      out = vl_nntt_forward(layer, in, out);
      y = out.x;
      out.dzdx = grandn(size(y), 'single');
      in = vl_nntt_backward(layer, in, out);
      for iGroup = 1:numel(layer.weights)
          vl_testder(@(w) vl_nntt_forward_weights(layer, in, out, iGroup, w), layer.weights{iGroup}, out.dzdx, in.dzdw{iGroup}, range * 1e-2);
      end
      vl_testder(@(x) vl_nntt_forward_x(layer, in, out, x), in.x, out.dzdx, in.dzdx, range * 1e-2);

    case 2
      disp('Testing vl_nntt_* with a random square TT-matrix.');
      % Shape for the input and output tensors.
      tensorShape = [4, 4, 4, 4, 3];
      batchSize = 10;
      ranks = [1, 4, 6, 10, 5, 1];
      W = tt_rand(tensorShape.^2, 5, ranks);
      W.core = single(W.core);
      W = tt_matrix(W, tensorShape, tensorShape);
      layer.W = W;
      layer.weights{1} = W.core;
      if gpu
        layer.weights{1} = gpuArray(layer.weights{1});
      end
      layer.outHeight = 8;
      layer.outWidth = 32;
      layer.outChannels = 3;
      in.x = grandn(8, 32, 3, batchSize, 'single');
      layer.weights{2} = grandn(8 * 32 * 3, 1, 'single');
      out = [];
      out = vl_nntt_forward(layer, in, out);
      y = out.x;
      exactY = full(W) * reshape(in.x, [], batchSize);
      exactY = bsxfun(@plus, exactY, layer.weights{2});
      vl_testsim(y, reshape(exactY, 8, 32, 3, batchSize));
      out.dzdx = grandn(size(y), 'single');
      in = vl_nntt_backward(layer, in, out);
      for iGroup = 1:numel(layer.weights)
          vl_testder(@(w) vl_nntt_forward_weights(layer, in, out, iGroup, w), layer.weights{iGroup}, out.dzdx, in.dzdw{iGroup}, range * 1e-2);
      end
      vl_testder(@(x) vl_nntt_forward_x(layer, in, out, x), in.x, out.dzdx, in.dzdx, range * 1e-2);

    case 3
      disp('Testing vl_nntt_* with random rectangular TT-matrices.');
      for bias = [false true]
        for batchSize = [1 3]
          inputTensorShape = [3, 6, 4, 5];
          outputTensorShape = [4, 11, 7, 13];
          layer.outHeight = 2 * 11;
          layer.outWidth = 7 * 13;
          layer.outChannels = 2;
          ranks = [1, 5, 9, 5, 1];
          W = tt_rand(outputTensorShape .* inputTensorShape, length(inputTensorShape), ranks, []);
          W.core = single(W.core);
          W = tt_matrix(W, outputTensorShape, inputTensorShape);
          layer.W = W;
          layer.weights{1} = W.core;
          if gpu
            layer.weights{1} = gpuArray(layer.weights{1});
          end
          if bias
            layer.weights{2} = grandn(prod(outputTensorShape), 1, 'single');
          else
            layer.weights{2} = [];
          end
          in.x = grandn(9, 8, 5, batchSize, 'single');
          out = [];
          out = vl_nntt_forward(layer, in, out);
          y = out.x;
          exactY = full(W) * reshape(in.x, [], batchSize);
          if bias
            exactY = bsxfun(@plus, exactY, layer.weights{2});
          end
          vl_testsim(y, reshape(exactY, layer.outHeight, layer.outWidth, layer.outChannels, batchSize));
          out.dzdx = grandn(size(y), 'single');
          in = vl_nntt_backward(layer, in, out);
          for iGroup = 1:numel(layer.weights)
              vl_testder(@(w) vl_nntt_forward_weights(layer, in, out, iGroup, w), layer.weights{iGroup}, out.dzdx, in.dzdw{iGroup}, range * 1e-2);
          end
          vl_testder(@(x) vl_nntt_forward_x(layer, in, out, x), in.x, out.dzdx, in.dzdx, range * 1e-2);
        end
      end
    end
  end
end


% gravity_demo.m

% Copyright 2003-2010 The MathWorks, Inc.

clear, close all, clc
get_video_data, disp('press any key to select region'), pause
select_region, disp('press any key to remove background'), pause
remove_background, disp('press any key to segment balls'), pause
segment_by_threshold, disp('press any key to suppress noise'), pause
suppress_noise, disp('press any key to locate ball positions'), pause
locate_ball_positions, disp('press any key to fit circle'), pause
fit_circle, disp('press any key to transform XY points to polar'), pause
%transform_to_polar, disp('press any key to fit damped sinusoid'), pause
%fit_damped_sinusoid, disp('press any key to calibrate pixel size'), pause
transform_to_polar, disp('press any key to model system'), pause
edit model_system
model_system, disp('press any key to calibrate pixel size'), pause
calibrate_resolution, disp('press any key to calculate gravity'), pause
edit calculate_gravity
calculate_gravity


function s = delta_function_from_parfile(parName,tr,nFrames)
% s = delta_function_from_parfile(parName,[tr],[nFrames])
%
% Given the name of a parfile, reads in the info
% and produces a matrix s that has as rows frames
% and as columns conditions (stimulus types). Each
% column is a delta function of onsets.
%
% (If a cell-of-strings is provided for parName,
% will load a list of parfiles, adding each run
% as the 3rd dimension.)
%
% 11/04 ras.
if notDefined('tr')
    tr = [];
end

if notDefined('nFrames')
    nFrames = [];
end

s = [];

if iscell(parName)
	% recursively get delta functions for each file, returning a
	% 3D matrix (slices = runs, deals w/ different-length runs)
	onsets = [];  conds = [];  offset = 0;
    for p = 1:length(parName)
		s_sub = delta_function_from_parfile(parName{p}, tr, nFrames);
		if p==1
			s = s_sub;
		elseif size(s, 1)==size(s_sub, 1)
			s(:,:,p) = s_sub;
		elseif size(s, 1) > size(s_sub, 1)
			s(1:size(s_sub, 1),:,p) = s_sub;
		elseif size(s, 1) < size(s_sub, 1)
			s(size(s_sub, 1),end,p-1) = 0;
			s(:,:,p) = s_sub;
		end
	end
	return
else
	[onsets conds] = readParFile(parName);
end

% 'shifting' parfile onsets, e.g. to correct for variations in
% when the scan started, may produce negative onsets, which we
% don't need:
ok = find(onsets>=0);
onsets = onsets(ok);
conds = conds(ok);
if isempty(tr)
    % estimate from parfile
    tr = onsets(2) - onsets(1);
end
whichConds = unique(conds);
nConds = length(whichConds);
if isempty(nFrames)
    nFrames = ceil(onsets(end) ./ tr);
end

% initialize s
s = zeros(nFrames, nConds);

% insert 1s at onset frames
for c = 1:nConds
    trials = onsets(conds==whichConds(c)) / tr;
    s(trials+1,c) = 1;
end

% truncate if it goes over
s = s(1:nFrames,:);

return


function [ y2, m2, d2, f2 ] = yjf_to_ymdf_julian ( y1, j1, f1 )

%*****************************************************************************80
%
%% YJF_TO_YMDF_JULIAN converts a YJF to YMDF date, both in the Julian calendar.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%   13 March 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer Y1, J1, real F1, the YJF date.
%
%    Output, integer Y2, M2, D2, real F2,
%    the YMDF date.
%

%
%  Copy the input.
%
  y2 = y1;
  j2 = j1;
  f2 = f1;
%
%  Check the input.
%
  [ y2, j2, ierror ] = yj_check_julian ( y2, j2 );

  if ( ierror ~= 0 )
    y2 = 0;
    m2 = 0;
    d2 = 0;
    f2 = 0.0;
    return
  end
%
%  Convert the input.
%
  m2 = 1;
  d2 = j2;

  [ y2, m2, d2 ] = day_borrow_julian ( y2, m2, d2 );

  [ y2, m2, d2 ] = day_carry_julian ( y2, m2, d2 );

  return
end


function str = time2human(t)
% time2human(t)
% t = seconds
% str = output

if t >= 2
  strs = {'sec', 'min', 'hr', 'days', 'weeks', 'months', 'years'};
  divs = [1, 60, 60*60, 60*60*24, 60*60*24*7, 60*60*24*30, 60*60*24*365];

  n = t ./ divs;
  idx = find(n >= 1.5, 1, 'last');
  if isempty(idx)
    idx = 1;
  end
  str = [num2str(n(idx), '%0.3f'), ' ', strs{idx}];
else
  str = [num2str(t*1000, '%0.3f'), ' ms'];
end


% function [res loc] = maxkmex(list, k)
%
% Matlab C-Mex
% Purpose: Same as MAXK, i.e.,
% Return in RES the K largest elements of LIST
% LOC is Location of the largest values: RES=LIST(LOC)
% This MEX works on double only, and output RES is unsorted
% Algorithm according to http://en.wikipedia.org/wiki/Selection_algorithm
% Compilation: mex -O -v maxkmex.c
% Author Bruno Luong <brunoluong@yahoo.com>
% Last update: 07/April/2009
%

error('Mex file not yet compiled. Action: mex -O -v maxkmex.c');


function [time,data,nEpochs] = readBESAsb(filename)

% readBESAsb reads information from a *.dat, i.e. a simple binary data file
%
% This function requires a file with the same basename as the data name but
% suffix '.generic' or '.gen' to be located in the same folder. This file is
% generated automatically by BESA during file export.
%
% Use as
%   [time,data,nEpochs] = readBESAsb(filename)
%
% The following output is generated:
%   time: a vector containing the time points corresponding to the data
%         points. Negative times are prestimulus
%   data: The data matrix with dimension [nChannels x nEpochs x nSamples],
%         where nChannels is the number of Channels and nSamples the number
%         of samples within one epoch
%   nEpochs (optional): The number of epochs contained in the file

% Modified February 21, 2007 Karsten Hoechstetter
% Modified April 24, 2007 Robert Oostenveld
% Modified September 24, 2009 Karsten Hoechstetter

if isempty(findstr(filename,'.dat'))
  filename = [filename,'.dat'];
end

fid=fopen([filename(1:end-4),'.generic'],'r');
if fid==-1
  fid=fopen([filename(1:end-4),'.gen'],'r');
end

fscanf(fid,'BESA Generic Data\n');
nChannels = fscanf(fid,'nChannels=%i\n');
sRate = fscanf(fid,'sRate=%f\n');
nSamples = fscanf(fid,'nSamples=%i\n');
format = fscanf(fid,'format=%s');
file = fscanf(fid,'\nfile=%s');
prestimulus = fscanf(fid,'prestimulus=%f\n');   if isempty(prestimulus),prestimulus=0;end
epochs = fscanf(fid,'epochs=%i\n');             if isempty(epochs),epochs=1;end
fclose(fid);

time=[-prestimulus:1/sRate*1000:(nSamples/epochs-1)*1000/sRate-prestimulus];

fid=fopen(filename, 'r', 'ieee-le');
xdata=fread(fid,[nChannels,nSamples],'float32');
fclose(fid);

data=zeros(nChannels,epochs,nSamples/epochs);
for i=1:epochs
  data(:,i,:)=xdata(:,1+(i-1)*nSamples/epochs:i*nSamples/epochs);
end
nEpochs=epochs;


%% Clear, close
clear; close; clc;

%% Data load
size.subject = 9;
size.trial = 288;
size.class = 4;
size.chan = 22;
size.sr = 250;

for i = 1:size.subject
    [train(i).s, train(i).h] = sload(char("C:\Users\KHJ-work\Documents\MATLAB\BCICIV_2a_gdf\A0" + int2str(i) + "T.gdf"));
    [eval(i).s, eval(i).h] = sload(char("C:\Users\KHJ-work\Documents\MATLAB\BCICIV_2a_gdf\A0" + int2str(i) + "E.gdf"));
    train(i).event_typ = find(train(i).h.EVENT.TYP >= 769 & train(i).h.EVENT.TYP <= 772 );
    eval(i).event_typ = find(eval(i).h.EVENT.TYP == 783);
    train(i).h.Classlabel = load(char("C:\Users\KHJ-work\Documents\MATLAB\BCICIV_2a_gdf\A0" + int2str(i) + "T.mat"));
    eval(i).h.Classlabel = load(char("C:\Users\KHJ-work\Documents\MATLAB\BCICIV_2a_gdf\A0" + int2str(i) + "E.mat"));
end

%% Make Segment
for i = 1:size.subject
    for j = 1:size.trial
        train(i).samp_seg(:, 1:size.chan, j) = train(i).s(train(i).h.TRIG(j) + 626:train(i).h.TRIG(j) + 1125, 1:size.chan);
        eval(i).samp_seg(:, 1:size.chan, j) = eval(i).s(eval(i).h.TRIG(j) + 626:eval(i).h.TRIG(j) + 1125, 1:size.chan);
        if j < size.trial
            train(i).ref_seg(:, 1:size.chan, j) = train(i).s(train(i).h.TRIG(j) + 1626:train(i).h.TRIG(j) + 2000, 1:size.chan);
            eval(i).ref_seg(:, 1:size.chan, j) = eval(i).s(eval(i).h.TRIG(j) + 1626:eval(i).h.TRIG(j) + 2000, 1:size.chan);
        end
    end
end

%% Remove NaN value trial
for i = 1:size.subject
    for j = 1:size.trial
        if find(isnan(train(i).samp_seg(:, :, j)))
            train(i).samp_seg(:, :, j) = zeros;
            train(i).samp_remain(j) = 0;
        else
            train(i).samp_remain(j) = 1;
        end

        if find(isnan(eval(i).samp_seg(:, :, j)))
            eval(i).samp_seg(:, :, j) = zeros;
            eval(i).samp_remain(j) = 0;
        else
            eval(i).samp_remain(j) = 1;
        end

        if j < size.trial
            if find(isnan(train(i).ref_seg(:, :, j)))
                train(i).ref_seg(:, :, j) = zeros;
                train(i).ref_remain(j) = 0;
            else
                train(i).ref_remain(j) = 1;
            end

            if find(isnan(eval(i).ref_seg(:, :, j)))
                eval(i).ref_seg(:, :, j) = zeros;
                eval(i).ref_remain(j) = 0;
            else
                eval(i).ref_remain(j) = 1;
            end
        end
    end
end

%% Bandpass filtering
for i = 1:size.subject
    train(i).samp_segF = reshape(bandpass(reshape(train(i).samp_seg, [500 * size.trial size.chan]), [8 30], size.sr), [500, size.chan, size.trial]);
    eval(i).samp_segF = reshape(bandpass(reshape(eval(i).samp_seg, [500 * size.trial size.chan]), [8 30], size.sr), [500, size.chan, size.trial]);
    train(i).ref_segF = reshape(bandpass(reshape(train(i).ref_seg, [375 * (size.trial - 1) size.chan]), [8 30], size.sr), [375, size.chan, (size.trial - 1)]);
    eval(i).ref_segF = reshape(bandpass(reshape(eval(i).ref_seg, [375 * (size.trial - 1) size.chan]), [8 30], size.sr), [375, size.chan, (size.trial - 1)]);
end

%% Covariance matrix
for i = 1:size.subject
    for j = 1:size.trial
        train(i).samp_cov(:, :, j) = (1 / (length(find(train(i).samp_remain)) - 1)) * (train(i).samp_segF(:, :, j)' * train(i).samp_segF(:, :, j));
        eval(i).samp_cov(:, :, j) = (1 / (length(find(eval(i).samp_remain)) - 1)) * (eval(i).samp_segF(:, :, j)' * eval(i).samp_segF(:, :, j));
        if j < size.trial
            train(i).ref_cov(:, :, j) = (1 / (length(find(train(i).ref_remain)) - 1)) * (train(i).ref_segF(:, :, j)' * train(i).ref_segF(:, :, j));
            eval(i).ref_cov(:, :, j) = (1 / (length(find(eval(i).ref_remain)) - 1)) * (eval(i).ref_segF(:, :, j)' * eval(i).ref_segF(:, :, j));
        end
    end
end

%% Riemannian mean of whole sample and refference
for i = 1:size.subject
    train_samp_tmp = train(i).samp_cov;
    train_samp_tmp(:, :, train(i).samp_remain == 0) = [];
    eval_samp_tmp = eval(i).samp_cov;
    eval_samp_tmp(:, :, eval(i).samp_remain == 0) = [];
    train(i).samp_Rmean = mean(train_samp_tmp, 3);
    eval(i).samp_Rmean = mean(eval_samp_tmp, 3);

    train_ref_tmp = train(i).ref_cov;
    train_ref_tmp(:, :, train(i).ref_remain == 0) = [];
    eval_ref_tmp = eval(i).ref_cov;
    eval_ref_tmp(:, :, eval(i).ref_remain == 0) = [];
    train(i).ref_Rmean = mean(train_ref_tmp, 3);
    eval(i).ref_Rmean = mean(eval_ref_tmp, 3);

    for j = 1:5
        Tsamp = tangentspace(train_samp_tmp, train(i).samp_Rmean);
        Tmean = mean(Tsamp, 3);
        train(i).samp_Rmean = untangentspace(Tmean, train(i).samp_Rmean);

        Tsamp = tangentspace(eval_samp_tmp, eval(i).samp_Rmean);
        Tmean = mean(Tsamp, 3);
        eval(i).samp_Rmean = untangentspace(Tmean, eval(i).samp_Rmean);

        Tsamp = tangentspace(train_samp_tmp, train(i).ref_Rmean);
        Tmean = mean(Tsamp, 3);
        train(i).ref_Rmean = untangentspace(Tmean, train(i).ref_Rmean);

        Tsamp = tangentspace(eval_samp_tmp, eval(i).ref_Rmean);
        Tmean = mean(Tsamp, 3);
        eval(i).ref_Rmean = untangentspace(Tmean, eval(i).ref_Rmean);
    end
end

%% Riemannian mean of each class
for i = 1:size.subject
    for j = 1:size.class
        train_samp_tmp = train(i).samp_cov;
        train_samp_tmp = train_samp_tmp(:, :, train(i).h.Classlabel.classlabel == j & train(i).samp_remain');
        eval_samp_tmp = eval(i).samp_cov;
        eval_samp_tmp = eval_samp_tmp(:, :, eval(i).h.Classlabel.classlabel == j & eval(i).samp_remain');

        train(i).class_Rmean(:, :, j) = mean(train_samp_tmp, 3);
        eval(i).class_Rmean(:, :, j) = mean(eval_samp_tmp, 3);

        for k = 1:5
            Tsamp = tangentspace(train_samp_tmp, train(i).class_Rmean(:, :, j));
            Tmean = mean(Tsamp, 3);
            train(i).class_Rmean(:, :, j) = untangentspace(Tmean, train(i).class_Rmean(:, :, j));

            Tsamp = tangentspace(eval_samp_tmp, eval(i).class_Rmean(:, :, j));
            Tmean = mean(Tsamp, 3);
            eval(i).class_Rmean(:, :, j) = untangentspace(Tmean, eval(i).class_Rmean(:, :, j));
        end
    end
end

%% Rmdm classification
for i = 1:size.subject
    tmp_res = Rmdm(eval(i).samp_cov(:, :, find(eval(i).samp_remain)), train(i).class_Rmean);
    acc1(i) = length(find(tmp_res == eval(i).h.Classlabel.classlabel(find(eval(i).samp_remain))')) / length(eval(i).samp_remain);
    tmp_res = Rmdm(train(i).samp_cov(:, :, find(train(i).samp_remain)), eval(i).class_Rmean);
    acc2(i) = length(find(tmp_res == train(i).h.Classlabel.classlabel(find(train(i).samp_remain))')) / length(train(i).samp_remain);
    def_acc(i) = (acc1(i) + acc2(i)) / 2;
end

%% Covariance matrix using affine transform
for i = 1:size.subject
    for j = 1:size.trial
        train(i).aff_cov(:, :, j) = (train(i).ref_Rmean ^ (-1 / 2)) * train(i).samp_cov(:, :, j) * ((train(i).ref_Rmean) ^ (-1 / 2));
        eval(i).aff_cov(:, :, j) = (eval(i).ref_Rmean ^ (-1 / 2)) * eval(i).samp_cov(:, :, j) * ((eval(i).ref_Rmean) ^ (-1 / 2));
    end
end

%% Riemannian mean of each class of affine transformed samples
for i = 1:size.subject
    for j = 1:size.class
        train_aff_tmp = train(i).aff_cov;
        train_aff_tmp = train_aff_tmp(:, :, train(i).h.Classlabel.classlabel == j & train(i).samp_remain');
        eval_aff_tmp = eval(i).aff_cov;
        eval_aff_tmp = eval_aff_tmp(:, :, eval(i).h.Classlabel.classlabel == j & eval(i).samp_remain');

        train(i).aff_class_Rmean(:, :, j) = mean(train_aff_tmp, 3);
        eval(i).aff_class_Rmean(:, :, j) = mean(eval_aff_tmp, 3);

        for k = 1:5
            Tsamp = tangentspace(train_aff_tmp, train(i).aff_class_Rmean(:, :, j));
            Tmean = mean(Tsamp, 3);
            train(i).aff_class_Rmean(:, :, j) = untangentspace(Tmean, train(i).aff_class_Rmean(:, :, j));

            Tsamp = tangentspace(eval_aff_tmp, eval(i).aff_class_Rmean(:, :, j));
            Tmean = mean(Tsamp, 3);
            eval(i).aff_class_Rmean(:, :, j) = untangentspace(Tmean, eval(i).aff_class_Rmean(:, :, j));
        end
    end
end

%% Rmdm classification of affine transformed samples
for i = 1:size.subject
    tmp_res = Rmdm(eval(i).aff_cov(:, :, find(eval(i).samp_remain)), train(i).aff_class_Rmean);
    acc1(i) = length(find(tmp_res == eval(i).h.Classlabel.classlabel(find(eval(i).samp_remain))')) / length(eval(i).samp_remain);
    tmp_res = Rmdm(train(i).aff_cov(:, :, find(train(i).samp_remain)), eval(i).aff_class_Rmean);
    acc2(i) = length(find(tmp_res == train(i).h.Classlabel.classlabel(find(train(i).samp_remain))')) / length(train(i).samp_remain);
    aff_acc(i) = (acc1(i) + acc2(i)) / 2;
end

%% MINE
for i = 1:size.subject
    for j = 1:size.subject
        for k = 1:size.class
            for l = find(train(j).h.Classlabel.classlabel' == k & train(j).samp_remain)
                tmp_samp(:, :, l) = (train(i).aff_class_Rmean(:, :, k) ^ (-1 / 2)) * train(j).aff_cov(:, :, l) * (train(i).aff_class_Rmean(:, :, k) ^ (-1 / 2));
            end
        end

        if i == 1 && j == 1
            train(i).transfer_sample = tmp_samp;
            continue
        end

        train(i).transfer_sample = cat(3, train(i).transfer_sample, tmp_samp);
    end
end

%%
for i = 1:size.subject
    if i == 1
        train_remain = train(i).samp_remain;
        train_class = train(i).h.Classlabel.classlabel;

    else
        train_remain = cat(2, train_remain, train(i).samp_remain);
        train_class = cat(1, train_class, train(i).h.Classlabel.classlabel);
    end
end

%%
for i = 1:size.subject
    for j = 1:size.class
        train_mine_tmp = train(i).transfer_sample;
        train_mine_tmp = train_mine_tmp(:, :, train_class == j & train_remain');

        train(i).mine_class_Rmean(:, :, j) = mean(train_mine_tmp, 3);

        for k = 1:5
            Tsamp = tangentspace(train_mine_tmp, train(i).mine_class_Rmean(:, :, j));
            Tmean = mean(Tsamp, 3);
            train(i).mine_class_Rmean(:, :, j) = untangentspace(Tmean, train(i).mine_class_Rmean(:, :, j));
        end
    end
end

%%
for i = 1:size.subject
    for j = 1:size.class
        for k = find(eval(j).h.Classlabel.classlabel' == j & eval(j).samp_remain)
            tmp_samp(:, :, k) = (train(i).aff_class_Rmean(:, :, j) ^ (-1 / 2)) * eval(i).aff_cov(:, :, k) * (train(i).aff_class_Rmean(:, :, j) ^ (-1 / 2));
        end
    end

    tmp_res = Rmdm(eval(i).aff_cov(:, :, find(eval(i).samp_remain)), train(i).mine_class_Rmean);
    acc1(i) = length(find(tmp_res == eval(i).h.Classlabel.classlabel(find(eval(i).samp_remain))')) / length(eval(i).samp_remain);
end


function res = vg_method(args)

% Variational Garrote: performs linear regression with L0-norm penalty (Spike and Slab model)
%   See file test_vg.m for an example of use
%
% required parameters (n input dimension, p samples)
%   x     : n x p (training set, input)
%   y     : 1 x s (training set, output)
%   xv    : n x p (validation set, input)
%   yv    : 1 x s (validation set, output)
%
% optional parameters (default)
%   method      : method for optimization 'dual' or 'regression' for fixed gamma ('dual')
%   maxiter     : maximum number of iterations for optimization for fixed gamma (1e4)
%   max_sum_m   : increases gamma values until sum(m)=max_sum_m  (n/2)
%   beta_max    : increases gamma values until beta=beta_max (1e3)
%   n_gamma     : number of gamma values to scan (50)
%   dmmin       : convergence threshold for mean field error (1e-12)

%----------------
% REQUIRED PARAMS
ok = true;
if ~isfield(args, 'x') disp('train input x not provided'); ok = false; else x=args.x; end
if ~isfield(args, 'y') disp('train output y not provided'); ok = false; else y=args.y; end
if ~isfield(args, 'xv') disp('val set input xv not provided'); ok = false; else xv=args.xv; end
if ~isfield(args, 'yv') disp('val set output yv not provided'); ok = false; else yv=args.yv; end
if isfield(args, 'xt') && isfield(args, 'yt')
    xt=args.xt;
    yt=args.yt;
    pt = size(xt,2);
else
    pt = 0;
end

if ~ok
    return;
end

n = size(x,1);
p = size(x,2);
pv = size(xv,2);

%----------------
% OPTIONAL PARAMS

% method for optimization {dual or regression} for fixed gamma
if ~isfield(args, 'method') method='dual'; else method=args.method; end

% maximum number of iterations for optimization for fixed gamma
if ~isfield(args, 'maxiter') maxiter=1e4; else maxiter=args.maxiter; end

% increases gamma values until sum(m)=max_sum_m
if ~isfield(args, 'max_sum_m') max_sum_m=n/2; else max_sum_m=args.max_sum_m; end

% increases gamma values until beta=beta_max
if ~isfield(args, 'beta_max') beta_max=1e3; else beta_max=args.beta_max; end

% number of gamma values to scan
if ~isfield(args, 'n_gamma') n_gamma=50; else n_gamma=args.n_gamma; end

% convergence threshold for mean field error
if ~isfield(args, 'dmmin') dmmin=1e-12; else dmmin=args.dmmin; end

%----------------
% compute garrote solution for range of gammas
% first from gamma_min to gamma_max and then in
% a second pass from gamma_max to gamma_min.

% C is input data covariance matrix.
if strcmp(method, 'regression')
    if n<=1500,
        C=x*x'/p;
    end;
end

% b is input output covariance
b=x*y'/p;

% sigma is output variance
sigmay=y*y'/p;

% set gamma range (min, max and step size)
delta=1e-8;
[b2sort,isort]=sort(b.^2,'descend');
bsort=b(isort);
gamma_min=log(delta*sigmay/p/max(abs(b)));
eps_gamma=0.001;
gamma_max=eps_gamma*gamma_min;
gamma_all =linspace(gamma_min,gamma_max,n_gamma);

% initial step size of mean field update
eta0=1; %e-2;
% initial step size for change in w in dual.m
eta_w0=0.02;

% input data variance
chi_ii=1/p*sum(x.^2,2);
if sum(abs(chi_ii-1)>1e-10),
    fprintf('input design matrix is not normalized\n');
    pause
end;

lg=n_gamma;
kl_all=inf(lg,2);
v_all=inf(lg,2,n);
m_all=inf(lg,2,n);
beta_all=inf(lg,2);
v_mf_all=inf(lg,n);
m_mf_all=inf(lg,n);
iter_all=inf(lg,2);
beta_mf_all=inf(1,lg);
error_mf_all=inf(1,lg);
errorv_mf_all=inf(1,lg);
errort_mf_all=inf(1,lg);
m=zeros(1,n);

% the estimated inverse noise variance beta is initialized as the
% output variance
beta=1/sigmay;
i=0;

% for gamma is gamma_min to gamma_max, or when some criteria are
% satisfied
while (beta<beta_max)&&(i<n_gamma)&&(sum(m)<max_sum_m),
	i=i+1;
	gamma=gamma_all(i);
    eval(method);
	v_all(i,1,:)=v;
	m_all(i,1,:)=m;
	beta_all(i,1)=beta;
	iter_all(i,1)=iter;
	kl_all(i,1)=kl1;
	fprintf('gamma = %f beta = %f sum(m) = %f iter = %d kl = %f\n',gamma,beta,sum(m),iter,kl1);
end;

if beta>=beta_max
 fprintf('-----------------------------------------------------------\n');
 fprintf('beta > beta_max (%.3f > %.3f)\n', beta, beta_max);
 if i>1
    m = squeeze(m_all(i-1,1,:))';
 end
end
if sum(m)>=max_sum_m
 fprintf('-----------------------------------------------------------\n');
 fprintf('sum(m) > max_sum_m (%.3f > %.3f)\n', sum(m), max_sum_m);
end

% for gamma is current gamma decreasing to gamma_min
imax=i-1;
for i=imax:-1:1,
	gamma=gamma_all(i);
    eval(method);
	v_all(i,2,:)=v;
	m_all(i,2,:)=m;
	beta_all(i,2)=beta;
	iter_all(i,2)=iter;
	kl_all(i,2)=kl1;
	fprintf('gamma = %f beta = %f sum(m) = %f iter = %d kl = %f\n',gamma,beta,sum(m),iter,kl1);
end;

% select for each gamma from these two solutions the one with lowest KL
[klmin, imin]=min(kl_all,[],2);
for i=1:imax,
	v_mf_all(i,:)=squeeze(v_all(i,imin(i),:))';
	m_mf_all(i,:)=squeeze(m_all(i,imin(i),:))';
	beta_mf_all(i)=beta_all(i,imin(i));
	error_mf_all(i)=1/p*sum((y-v_mf_all(i,:)*x).^2,2);
	errorv_mf_all(i)=1/pv*sum((yv-v_mf_all(i,:)*xv).^2,2);
	if pt>0,
		errort_mf_all(i)=1/pt*sum((yt-v_mf_all(i,:)*xt).^2,2);
	end;
end;

% select the gamma that optimizes the validation error (errorv_mf_all)
[minerrorv i]=min(errorv_mf_all(1:imax));

res.gamma_mf=gamma_all(i);
res.v_mf=v_mf_all(i,:);
res.m_mf=m_mf_all(i,:);
res.n_mf1=sum(res.m_mf>0.5);

res.error_mf=error_mf_all(i);
res.errorv_mf=errorv_mf_all(i);
res.errort_mf=errort_mf_all(i);
res.beta_mf=beta_mf_all(i);

if (res.beta_mf==beta_max)
	fprintf('beta_max too small: beta_mf %6.4f, beta_max %6.4f\n', beta_mf(iruns),beta_max);
	pause
end;
if (res.gamma_mf==gamma_min)
	fprintf('gamma at minimum range boundary\n');
end;
if (res.gamma_mf==gamma_max)
	fprintf('gamma at maxium range boundary\n');
end;