function Offspring = Operator(Problem,Particle,Pbest,Gbest,W)
% The particle swarm optimization in dMOPSO

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

    %% Parameter setting
    if nargin < 5
        W = 0.4;
    end
    ParticleDec = Particle.decs;
    PbestDec    = Pbest.decs;
    GbestDec    = Gbest.decs;
    [N,D]       = size(ParticleDec);
    ParticleVel = Particle.adds(zeros(N,D));

    %% Particle swarm optimization
    r1     = repmat(rand(N,1),1,D);
    r2     = repmat(rand(N,1),1,D);
    OffVel = W.*ParticleVel + r1.*(PbestDec-ParticleDec) + r2.*(GbestDec-ParticleDec);
    OffDec = ParticleDec + OffVel;

    %% Deterministic back
    repair = OffDec < repmat(Problem.lower,N,1) | OffDec > repmat(Problem.upper,N,1);
    OffVel(repair) = -OffVel(repair);
    Offspring = Problem.Evaluation(OffDec,OffVel);
end


function [SGP4Elements,TTEpoch1,TTEpoch2,otherInfo,checksumIsBad]=TLE2SGP4OrbEls(TLELine1,TLELine2)
%%TLE2SGP4ORBELS Convert a North American Aerospace Defense Command (NORAD)
%                two-line element (TLE) satellite ephemerides into a format
%                that can be used with the propagateOrbitSGP4 function for
%                determining the position and velocity of the satellite at
%                different times using the Simplified General
%                Perturbations 4 (SGP4) model/ the Simplified Deep Space
%                Perturbations 4 (SDP4) model for distant satellites.
%                TLEs are how the Air Force Space Command (AFSPC) has
%                publicly released information on satellite orbits for
%                years.
%
%INPUTS: TLELine1, TLELine2 The character strings for each of the two lines
%                           that make up the TLE ephemeride, including all
%                           spaces as the positions of the characters are
%                           important. With checksums, these should both be
%                           69 characters long, without checksums, 68
%                           characters long.
%
%OUTPUTS: SGP4Elements The 7X1 vector of orbital elements that can be given
%                      to the propagateOrbitSGP4 function along with the
%                      epoch time to predict the location of the satellite
%                      at various times. They are similar, but not
%                      identical to, Keplerian orbital elements of the same
%                      name. If either of the TLE strings is too short,
%                      this is an empty matrix. The elements of
%                      SGP4Elements are
%                      1) eccentricity
%                      2) inclination  (radians)
%                      3) argument of perigee (radians)
%                      4) right ascension of the ascending node (radians)
%                      5) mean anomaly (radians)
%                      6) mean motion (radians per second [TT])
%                      7) BSTAR drag term. This pseudo ballistic
%                        coefficient has units of inverse Earth radii.
%                        Normally, a ballistic coefficient BC is mass per
%                        unit area divided by a drag coefficient. The BSTAR
%                        drag term is a scaled version of the normal
%                        ballistic coefficient. That is,
%                        BC=Re*rho_0/(2*BSTAR) where Re is the radius of
%                        the Earth in meters, and rho=2.461e-5 kg/m^2.
%   TTEpoch1, TTEpoch2 The epoch time of the SGP4Elements given in
%                      terrestrial time (TT) as a two-part Julian date.
%                      This will be incorrect from 2057 onward, since the
%                      TLE data only provides the final two digits of the
%                      year starting in 1957 and the century must be
%                      guessed. If either of the TLE strings is too short,
%                      these are empty matrices.
%            otherInfo A structure holding the other information present in
%                      the TLE. If either of the TLE strings is too short,
%                      this is an empty matrix. The fields of this
%                      structure are
%                      line1Number The number starting the first TLE line.
%                                  This should be 1.
%                      line2Number The number starting the second TLE line.
%                                  This should be 2.
%                      satelliteNumber1 The NORAD catalog number of the
%                                  satellite as given by the first line of
%                                  the TLE.
%                      satelliteNumber2 The NORAD catalog number of the
%                                  satellite as given by the second line of
%                                  the TLE. This should be the same as
%                                  satelliteNumber1
%                      classification A character indicating the
%                                  classification level of the satellite.
%                                  'U'=unclassified.
%                      IDLaunchYear The last two digits of the launch year
%                                  of the satellite.
%                      IDLaunchNumber The number of the launch in in the
%                                  launch year that put up the satellite.
%                      IDPieceOfLaunch A string indicating which piece of
%                                  the launch the satellite is.
%                      firstDerivMeanMotion The first derivative of the
%                                  mean motion in radians per second
%                                  squared. This is useful with the older
%                                  orbital propagators.
%                      secondDerivMeanMotion The second derivative of the
%                                  mean motion in radians per second cubed.
%                      ephemerisType Originally, this was a number from
%                                  1-5 indicating the type of orbital
%                                  propagator used to generate the
%                                  ephemeris with 1=SGP, 2=SGP4, 3=SDP4,
%                                  4=SGP8, and 5=SDP8. However, it is
%                                  always set to zero in TLEs that are
%                                  publicly released and is thus
%                                  meaningless.
%                      elementNumber A number indicating which TLE set this
%                                  TLE is from. The number is supposed to
%                                  be incremented everytime a new set comes
%                                  out. However, in practice, it is not.
%                      revolutionNumberAtEpoch The number of orbits the
%                                  satellite has made since its launch.
%        checksumIsBad A 2X1 boolean vector indicating whether the checksum
%                      value for each of the strings is bad.
%                      checksumIsBad(1) is true if the checksum of TLELine1
%                      is invalid and checksumIsBad(2) is true if the
%                      checksum of TLELine2 is invalid. If a checksums is
%                      omitted then the value will be true. If iether of
%                      the strings is too short, then this will be an empty
%                      matrix.
%
%Note that parts of the input strings that cannot be read will be filled
%with NaN values.
%
%Information of the format of the TLE sets can be found at [1]. The
%documentation discussing how the element sets are used is in [2] and [3].
%The decimal point parsing part of this function is loosely based on David
%Vallado's public-domain code for the SGP4 propagator that was downloaded
%from http://www.centerforspace.com/downloads/
%
%A sample TLE that accompanies Vallado's code is:
%TLELine1='1 11801U          80230.29629788  .01431103  00000-0  14311-1      13'
%TLELine2='2 11801  46.7916 230.4354 7318036  47.4722  10.4117  2.28537848    13'
%
%REFERENCES:
%[1] T. C. for Space Standards and Innovation. (2012, 27 Sep.) NORAD two-
%    line element sets. [Online].
%    Available: http://www.celestrak.com/NORAD/elements/
%[2] F. R. Hoots and R. L. Roehrich, "Spacetrack report no. 3: Models for
%    propagation of NORAD element sets," Department of Defense, Tech. Rep.,
%    31 Dec. 1988. [Online].
%    Available: http://www.amsat.org/amsat/ftp/docs/spacetrk.pdf
%[3] D. A. Vallado, P. Crawford, R. Hujsak, and T. S. Kelso, "Revisiting
%    spacetrack report # 3: Rev 2," in Proceedings of the AIAA/AAS
%    Astrodynamics Specialist Conference and Exhibit, Keystone, CO, 21-24
%    Aug. 2006. [Online].
%    Available: http://celestrak.com/publications/AIAA/2006-6753/AIAA-2006-6753.pdf
%
%December 2014 David F. Crouse, Naval Research Laboratory, Washington D.C.*/
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

%Multiplication coefficient to convert from degrees to radians.
deg2Rad=pi/180;

%If either of the strings is too short.
if(length(TLELine1)<68||length(TLELine2)<68)
    SGP4Elements=[];
    TTEpoch1=[];
    TTEpoch2=[];
    otherInfo=[];
    checksumIsBad=[];
    return;
end

%If the strings have no checksums at the end, then just mark the checksums
%as bad.
if(length(TLELine1)<69)
    checksumIsBad(1)=true;
else
    checksumIsBad(1)=~validateTLEChecksum(TLELine1);
end

if(length(TLELine2)<69)
    checksumIsBad(2)=true;
else
    checksumIsBad(2)=~validateTLEChecksum(TLELine2);
end

%Set the implied decimal points to help deal with bad values when doing a
%formatted read.
for j=11:16
    if(TLELine1(j)==' ')
        TLELine1(j)='_';
    end
end

if(TLELine1(45)~=' ')
    TLELine1(44)=TLELine1(45);
end
TLELine1(45)='.';

if(TLELine1(8)==' ')
    TLELine1(8)='U';
end

if(TLELine1(10)==' ')
    TLELine1(10)='.';
end

for j=46:50
    if (TLELine1(j)==' ')
        TLELine1(j)='0';
    end
end

if(TLELine1(52)==' ')
    TLELine1(52)='0';
end

if(TLELine1(54)~=' ')
    TLELine1(53)=TLELine1(54);
end
TLELine1(54)='.';
TLELine2(26)='.';

for j=27:33
    if(TLELine2(j)==' ')
        TLELine2(j)='0';
    end
end

if(TLELine1(63)==' ')
    TLELine1(63)='0';
end

if((length(TLELine1)<68)||(TLELine1(68)==' '))
    TLELine1(68)='0';
end

%Parse the stuff that most folks do not care about.
otherInfo.line1Number = str2double(TLELine1(1));
otherInfo.line2Number = str2double(TLELine2(1));
otherInfo.satelliteNumber1 = str2double(TLELine1(3:7));
otherInfo.satelliteNumber2 = str2double(TLELine2(3:7));

otherInfo.classification = TLELine1(8);
otherInfo.IDLaunchYear = str2double(TLELine1(10:11));
otherInfo.IDLaunchNumber= str2double(TLELine1(12:14));
otherInfo.IDPieceOfLaunch= TLELine1(15:17);

%Convert revolutions per day squared into radians per second squared,
%with 86400 seconds per TT Julian day.
otherInfo.firstDerivMeanMotion=str2double(TLELine1(34:43))*(2*pi/86400^2);
%Convert revolutions per day cubed into radians per second cubed,
%with 86400 seconds per TT Julian day.
otherInfo.secondDerivMeanMotion=str2double(TLELine1(44:50))*10.0^str2double(TLELine1(51:52))*(2*pi/86400^3);
otherInfo.ephemerisType = str2double(TLELine1(63));
otherInfo.elementNumber = str2double(TLELine1(65:68));
otherInfo.revolutionNumberAtEpoch=str2double(TLELine2(64:68));

%Parse the stuff that most folks care about
inclination = str2double(TLELine2(8:16))*deg2Rad;
RAAscendingNode = str2double(TLELine2(17:25))*deg2Rad;
eccentricity = str2double(TLELine2(26:33));
argumentOfPerigee = str2double(TLELine2(34:42))*deg2Rad;
meanAnomaly = str2double(TLELine2(43:51))*deg2Rad;
%Convert from revolutions per day to radians per second, with 86400
%seconds per TT Julian day.
meanMotion=str2double(TLELine2(52:63))*(2*pi/86400);
BSTARDrag= str2double(TLELine1(53:59))*10.0^str2double(TLELine1(60:61));

%Get the time of the orbital elements.
epochYear = str2double(TLELine1(19:20));
epochDays = str2double(TLELine1(21:32));

%Assume that the years only run from 1957->2057 and find the actual
%epoch year.
if (epochYear < 57)
    year=epochYear+2000;
else
    year=epochYear+1900;
end
%Convert into a two-part Julian date in TT.
[month,dayOfMonth]=dayOfYear2MonthDay(year,fix(epochDays));
dayFrac=epochDays-fix(epochDays);
[hour,minute,second]=fracDayOfMonth2HourMinSec(year,month,dayOfMonth,dayFrac);
[TTEpoch1,TTEpoch2]=Cal2TT(year,month,dayOfMonth,hour,minute,second);

SGP4Elements=zeros(7,1);
SGP4Elements(1)=eccentricity;
SGP4Elements(2)=inclination;
SGP4Elements(3)=argumentOfPerigee;
SGP4Elements(4)=RAAscendingNode;
SGP4Elements(5)=meanAnomaly;
SGP4Elements(6)=meanMotion;
SGP4Elements(7)=BSTARDrag;
end

function isValid=validateTLEChecksum(theTLELine)
%The validation comes from the explanation of how the checksum is formed
%from http://www.celestrak.com/NORAD/elements/ It is the last digit of the
%sum of all of the digits in the string plus an extra 1 for each '-'.
    theSum=0;
    for curCharIdx=1:68
        curChar=theTLELine(curCharIdx);
        if(curChar=='-')
            theSum=theSum+1;
        elseif(curChar>='0'&&curChar<='9')
            theSum=theSum+str2double(curChar);
        end
    end

    %Get the last digit of the sum.
    sumStr=num2str(theSum);
    isValid=(sumStr(end)==theTLELine(69));
end

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


% Change to your downloaded location
clear
addpath('C:\liblinear\matlab')
addpath('../training_code/');
addpath('../utilities/');
addpath('../../data extraction/');
%% load shared definitions and AU data
shared_defs;

% Set up the hyperparameters to be validated
hyperparams.c = 10.^(-7:0.5:1);
hyperparams.e = 10.^(-3);

hyperparams.validate_params = {'c', 'e'};

% Set the training function
svm_train = @svm_train_linear;

% Set the test function (the first output will be used for validation)
svm_test = @svm_test_linear;

pca_loc = '../../pca_generation/generic_face_rigid.mat';

hog_data_dir_BP4D = hog_data_dir;

aus = [1, 2, 4, 6, 7, 10, 12, 14, 15, 17, 23];
%%
for a=1:numel(aus)

    au = aus(a);

    rest_aus = setdiff(all_aus, au);

    % load the training and testing data for the current fold
    [train_samples, train_labels, valid_samples, valid_labels, ~, PC, means, scaling] = Prepare_HOG_AU_data_generic(train_recs, devel_recs, au, BP4D_dir, hog_data_dir_BP4D);

    train_samples = sparse(train_samples);
    valid_samples = sparse(valid_samples);

    %% Cross-validate here
    [ best_params, ~ ] = validate_grid_search_no_par(svm_train, svm_test, false, train_samples, train_labels, valid_samples, valid_labels, hyperparams);
    model = svm_train(train_labels, train_samples, best_params);

    [~, predictions_all] = svm_test(valid_labels, valid_samples, model);

    name = sprintf('results_BP4D_devel/AU_%d_static.mat', au);

    [ accuracies, F1s, corrs, ccc, rms, classes ] = evaluate_regression_results( predictions_all, valid_labels );

    save(name, 'model', 'F1s', 'accuracies', 'predictions_all', 'valid_labels');

    % Write out the model
    name = sprintf('models/AU_%d_static.dat', au);

    pos_lbl = model.Label(1);
    neg_lbl = model.Label(2);

    w = model.w(1:end-1)';
    b = model.w(end);

    svs = bsxfun(@times, PC, 1./scaling') * w;

    write_lin_svm(name, means, svs, b, pos_lbl, neg_lbl);
end


function [mustUU, pos_mustUU, mustUU_linear, pos_mustUU_linear] = findMustUUWithGAMS(model, minFluxesW, maxFluxesW, constrOpt, excludedRxns, mustSetFirstOrder, solverName, runID, outputFolder, outputFileName, printExcel, printText, printReport, keepInputs, keepGamsOutputs, verbose)
% This function runs the second step of `optForce`, that is to solve a
% bilevel mixed integer linear programming  problem to find a second order
% `MustUU` set.
%
% USAGE:
%
%    [mustUU, pos_mustUU, mustUU_linear, pos_mustUU_linear] = findMustUUWithGAMS(model, minFluxesW, maxFluxesW, varargin)
%
% INPUTS:
%    model:                      (structure) a metabolic model with at
%                                least the following fields:
%
%                                  * .rxns - Reaction IDs in the model
%                                  * .mets - Metabolite IDs in the model
%                                  * .S -    Stoichiometric matrix (sparse)
%                                  * .b -    RHS of `Sv = b` (usually zeros)
%                                  * .c -    Objective coefficients
%                                  * .lb -   Lower bounds for fluxes
%                                  * .ub -   Upper bounds for fluxes
%    minFluxesW:                 (double array of size `n_rxns x 1`) minimum
%                                fluxes for each reaction in the model for
%                                wild-type strain. This can be obtained by
%                                running the function `FVAOptForce`. E.g.:
%                                `minFluxesW = [-90; -56];`
%    maxFluxesW:                 (double array of size `n_rxns x 1`) maximum
%                                fluxes for each reaction in the model for
%                                wild-type strain. This can be obtained by
%                                running the function `FVAOptForce`. E.g.:
%                                `maxFluxesW = [90; 56];`
%
% OPTIONAL INPUTS:
%    constrOpt:                  (Structure) structure containing
%                                additional contraints. Include here only
%                                reactions whose flux is fixed, i.e.,
%                                reactions whose lower and upper bounds
%                                have the same value. Do not include here
%                                reactions whose lower and upper bounds
%                                have different values. Such contraints
%                                should be defined in the lower and upper
%                                bounds of the model. The structure has the
%                                following fields:
%
%                                  * .rxnList - Reaction list (cell array)
%                                  * .values -  Values for constrained
%                                    reactions (double array)
%                                    E.g.: `struct('rxnList', {{'EX_gluc', 'R75', 'EX_suc'}}, 'values', [-100, 0, 155.5]');`
%    excludedRxns:               (cell array) Reactions to be excluded to
%                                the `MustUU` set. This could be used to
%                                avoid finding transporters or exchange
%                                reactions in the set. Default = empty.
%    mustSetFirstOrder:          (cell array) Reactions that belong to
%                                `MustU` and `MustL` (first order sets).
%                                Default = empty.
%    solverName:                 (string) Name of the solver used in
%                                GAMS. Default = 'cplex'.
%    runID:                      (string) ID for identifying this run.
%                                Default = ['run' date hour].
%    outputFolder:               (string) name for folder in which
%                                results will be stored. Default =
%                                'OutputsFindMustUU'.
%    outputFileName:             (string) name for files in which
%                                results. will be stored Default =
%                                'MustUUSet'.
%    printExcel:                 (double) boolean to describe wheter
%                                data must be printed in an excel file or
%                                not. Default = 1
%    printText:                  (double) boolean to describe wheter
%                                data must be printed in an plaint text
%                                file or not. Default = 1
%    printReport:                (double) 1 to generate a report in a
%                                plain text file. 0 otherwise. Default = 1
%    keepInputs:                 (double) 1 to mantain folder with
%                                inputs to run `findMustUU.gms`. 0 otherwise.
%                                Default = 1
%    keepGamsOutputs:            (double) 1 to mantain files returned by
%                                `findMustUU.gms`. 0 otherwise. Default = 1
%    verbose:                    (double) 1 to print results in console.
%                                0 otherwise. Default = 0
%
% OUTPUTS:
%    mustUU:                     (cell array of size number of sets found X
%                                2) Cell array containing the reactions IDs
%                                which belong to the `MustUU` set. Each row
%                                contain a couple of reactions that must
%                                decrease their flux.
%    pos_mustUU:                 (double array of size number of sets found
%                                X 2) double array containing the positions
%                                of each reaction in `mustUU` with regard to
%                                `model.rxns`
%    mustUU_linear:              (cell array of size number of unique
%                                reactions found X 1) Cell array containing
%                                the unique reactions ID which belong to
%                                the `MustUU` Set
%    pos_mustUU_linear:          (double array of size number of unique
%                                reactions found X 1) double array
%                                containing positions for reactions in
%                                `mustUU_linear`. with regard to `model.rxns`
%    outputFileName.xls:        (file) File containing one column
%                                array with identifiers for reactions in
%                                MustUU. This file will only be generated
%                                if the user entered `printExcel = 1`. Note
%                                that the user can choose the name of this
%                                file entering the input `outputFileName = 'PutYourOwnFileNameHere';`
%    outputFileName.txt:         (file) File containing one column
%                                array with identifiers for reactions in
%                                MustUU. This file will only be generated
%                                if the user entered `printText = 1`. Note
%                                that the user can choose the name of this
%                                file entering the input `outputFileName = 'PutYourOwnFileNameHere';`
%    outputFileName_Info.xls:    (file) File containing one column
%                                array. In each row the user will find a
%                                couple of reactions. Each couple of
%                                reaction was found in one iteration of
%                                `FindMustUU.gms`. This file will only be
%                                generated if the user entered `printExcel = 1`.
%                                Note that the user can choose the name
%                                of this file entering the input
%                                `outputFileName = 'PutYourOwnFileNameHere';`
%    outputFileName_Info.txt:    (file) File containing one column
%                                array. In each row the user will find a
%                                couple of reactions. Each couple of
%                                reaction was found in one iteration of
%                                `FindMustUU.gms`. This file will only be
%                                generated if the user entered `printText = 1`.
%                                Note that the user can choose the name
%                                of this file entering the input
%                                `outputFileName = 'PutYourOwnFileNameHere';`
%    findMustUU.lst:             (file) file autogenerated by GAMS. It
%                                contains information about equations,
%                                variables, parameters as well as
%                                information about the running (values at
%                                each iteration). This file only will be
%                                saved in the output folder is the user
%                                entered `keepGamsOutputs = 1`
%    GtoMUU.gdx:                 (file) file containing values for
%                                variables, parameters, etc. which were
%                                found by GAMS when solving `findMustUU.gms`.
%                                This file only will be saved in the output
%                                folder is the user entered `keepInputs = 1`
%
% NOTE:
%
%    This function is based in the GAMS files written by Sridhar
%    Ranganathan which were provided by the research group of Costas D.
%    Maranas. For a detailed description of the `optForce` procedure, please
%    see: `Ranganathan S, Suthers PF, Maranas CD (2010) OptForce: An
%    Optimization Procedure for Identifying All Genetic Manipulations
%    Leading to Targeted Overproductions. PLOS Computational Biology 6(4):
%    e1000744`. https://doi.org/10.1371/journal.pcbi.1000744
%
% .. Author: - Sebastian Mendoza, May 30th 2017, Center for Mathematical Modeling, University of Chile, snmendoz@uc.cl

optionalParameters = {'constrOpt', 'excludedRxns', 'mustSetFirstOrder', 'solverName', 'runID', 'outputFolder', 'outputFileName',  ...
    'printExcel', 'printText', 'printReport', 'keepInputs', 'keepGamsOutputs', 'verbose'};

if (numel(varargin) > 0 && (~ischar(varargin{1}) || ~any(ismember(varargin{1},optionalParameters))))

    tempargin = cell(1,2*(numel(varargin)));
    for i = 1:numel(varargin)

        tempargin{2*(i-1)+1} = optionalParameters{i};
        tempargin{2*(i-1)+2} = varargin{i};
    end
    varargin = tempargin;

end

parser = inputParser();
parser.addRequired('model', @(x) isstruct(x) && isfield(x, 'S') && isfield(model, 'rxns')...
    && isfield(model, 'mets') && isfield(model, 'lb') && isfield(model, 'ub') && isfield(model, 'b')...
    && isfield(model, 'c'))
parser.addRequired('minFluxesW', @isnumeric)
parser.addRequired('maxFluxesW', @isnumeric)
parser.addParamValue('constrOpt', struct('rxnList', {{}}, 'values', []),@ (x) isstruct(x) && isfield(x, 'rxnList') && isfield(x, 'values') ...
    && length(x.rxnList) == length(x.values) && length(intersect(x.rxnList, model.rxns)) == length(x.rxnList))
parser.addParamValue('excludedRxns', {}, @(x) iscell(x) && length(intersect(x, model.rxns)) == length(x))
parser.addParamValue('mustSetFirstOrder', {}, @(x) iscell(x) && length(intersect(x, model.rxns)) == length(x))
solvers = checkGAMSSolvers('MIP');
if isempty(solvers)
    error('there is no GAMS solvers available to solve Mixed Integer Programming problems') ;
else
    if ismember('cplex', lower(solvers))
        defaultSolverName = 'cplex';
    else
        defaultSolverName = lower(solvers(1));
    end
end

parser.addParamValue('solverName', defaultSolverName, @(x) ischar(x))
hour = clock; defaultRunID = ['run-' date '-' num2str(hour(4)) 'h' '-' num2str(hour(5)) 'm'];
parser.addParamValue('runID', defaultRunID, @(x) ischar(x))
parser.addParamValue('outputFolder', 'OutputsFindMustUU', @(x) ischar(x))
parser.addParamValue('outputFileName', 'MustUUSet', @(x) ischar(x))
parser.addParamValue('printExcel', 1, @(x) isnumeric(x) || islogical(x));
parser.addParamValue('printText', 1, @(x) isnumeric(x) || islogical(x));
parser.addParamValue('printReport', 1, @(x) isnumeric(x) || islogical(x));
parser.addParamValue('keepInputs', 1, @(x) isnumeric(x) || islogical(x));
parser.addParamValue('keepGamsOutputs', 1, @(x) isnumeric(x) || islogical(x));
parser.addParamValue('verbose', 1, @(x) isnumeric(x) || islogical(x));

parser.parse(model, minFluxesW, maxFluxesW, varargin{:})
model = parser.Results.model;
minFluxesW = parser.Results.minFluxesW;
maxFluxesW = parser.Results.maxFluxesW;
constrOpt= parser.Results.constrOpt;
excludedRxns= parser.Results.excludedRxns;
mustSetFirstOrder = parser.Results.mustSetFirstOrder;
solverName = parser.Results.solverName;
runID = parser.Results.runID;
outputFolder = parser.Results.outputFolder;
outputFileName = parser.Results.outputFileName;
printExcel = parser.Results.printExcel;
printText = parser.Results.printText;
printReport = parser.Results.printReport;
keepInputs = parser.Results.keepInputs;
keepGamsOutputs = parser.Results.keepGamsOutputs;
verbose = parser.Results.verbose;

% correct size of constrOpt
if ~isempty(constrOpt.rxnList)
    if size(constrOpt.rxnList, 1) > size(constrOpt.rxnList,2); constrOpt.rxnList = constrOpt.rxnList'; end;
    if size(constrOpt.values, 1) > size(constrOpt.values,2); constrOpt.values = constrOpt.values'; end;
end

% first, verify that GAMS is installed in your system
gamsPath = which('gams');
if isempty(gamsPath); error('OptForce: GAMS is not installed in your system. Please install GAMS.'); end;

%name of the function to solve the optimization problem in GAMS
gamsMustUUFunction = 'findMustUU.gms';
%path of that function
pathGamsFunction = which(gamsMustUUFunction);
if isempty(pathGamsFunction); error(['OptForce: ' gamsMustUUFunction ' not in MATLAB path.']); end;
%current path
workingPath = pwd;
%go to the path associate to the ID for this run.
if ~isdir(runID); mkdir(runID); end; cd(runID);

% if the user wants to generate a report.
if printReport
    %create name for file.
    hour = clock;
    reportFileName = ['report-' date '-' num2str(hour(4)) 'h' '-' num2str(hour(5)) 'm.txt'];
    freport = fopen(reportFileName, 'w');
    reportClosed = 0;
    % print date of running.
    fprintf(freport, ['findMustUUWithGAMS.m executed on ' date ' at ' num2str(hour(4)) ':' num2str(hour(5)) '\n\n']);
    % print matlab version.
    fprintf(freport, ['MATLAB: Release R' version('-release') '\n']);
    % print gams version.
    fprintf(freport, ['GAMS: ' regexprep(gamsPath, '\\', '\\\') '\n']);
    % print solver used in GAMS to solve optForce.
    fprintf(freport, ['GAMS solver: ' solverName '\n']);

    %print each of the inputs used in this running.
    fprintf(freport, '\nThe following inputs were used to run OptForce: \n');
    fprintf(freport, '\n------INPUTS------\n');
    %print model.
    fprintf(freport, '\nModel:\n');
    for i = 1:length(model.rxns)
        rxn = printRxnFormula(model, model.rxns{i}, false);
        fprintf(freport, [model.rxns{i} ': ' rxn{1} '\n']);
    end
    %print lower and upper bounds, minimum and maximum values for each of
    %the reactions in wild-type and mutant strain
    fprintf(freport, '\nLB\tUB\tMin_WT\tMax_WT\n');
    for i = 1:length(model.rxns)
        fprintf(freport, '%6.4f\t%6.4f\t%6.4f\t%6.4f\n', model.lb(i), model.ub(i), minFluxesW(i), maxFluxesW(i));
    end

    %print constraints
    fprintf(freport,'\nConstrained reactions:\n');
    for i = 1:length(constrOpt.rxnList)
        fprintf(freport,'%s: fixed in %6.4f\n',constrOpt.rxnList{i},constrOpt.values(i));
    end

    fprintf(freport, '\nExcluded Reactions:\n');
    for i = 1:length(excludedRxns)
        rxn = printRxnFormula(model, excludedRxns{i}, false);
        fprintf(freport, [excludedRxns{i} ': ' rxn{1} '\n']);
    end

    fprintf(freport, '\nReactions from first order sets(MustU and MustL):\n');
    for i = 1:length(mustSetFirstOrder)
        rxn = printRxnFormula(model, mustSetFirstOrder{i}, false);
        fprintf(freport, [mustSetFirstOrder{i} ': ' rxn{1} '\n']);
    end

    fprintf(freport,'\nrunID(Main Folder): %s \n\noutputFolder: %s \n\noutputFileName: %s \n',...
        runID, outputFolder, outputFileName);

    fprintf(freport,'\nprintExcel: %1.0f \n\nprintText: %1.0f \n\nprintReport: %1.0f \n\nkeepInputs: %1.0f  \n\nkeepGamsOutputs: %1.0f \n\nverbose: %1.0f \n',...
        printExcel,printText,printReport,keepInputs,keepGamsOutputs,verbose);

end

copyfile(pathGamsFunction);

% export inputs for running the optimization problem in GAMS to find the
% MustUU Set
inputFolder = 'InputsMustUU';
exportInputsMustOrder2ToGAMS(model, 'UU', minFluxesW, maxFluxesW, constrOpt, excludedRxns, mustSetFirstOrder, inputFolder)

% create a directory to save results if this don't exist
if ~exist(outputFolder, 'dir')
    mkdir(outputFolder);
end

%run
if verbose
    run = system(['gams ' gamsMustUUFunction ' lo=3 --myroot=' inputFolder '/ --solverName=' solverName ' gdx=GtoMUU']);
else
    run=system(['gams ' gamsMustUUFunction ' --myroot=' inputFolder '/ --solverName=' solverName ' gdx=GtoMUU']);
end

if printReport; fprintf(freport, '\n------RESULTS------\n'); end;

%if user decide not to show inputs files for findMustUU.gms
if ~keepInputs; rmdir(inputFolder,'s'); end;

%if findMustUU.gms was executed correctly "run" should be 0
if run == 0

    if printReport; fprintf(freport,'\nGAMS was executed correctly\n'); end;
    if verbose; fprintf('GAMS was executed correctly\nSummary of information exported by GAMS:\n'); end;
    %show GAMS report in MATLAB console
    if verbose; gdxWhos GtoMUU; end;
    try
        findMustUU.name = 'findMustUU';
        rgdx('GtoMUU',findMustUU); %if do not exist the variable findMustUU in GtoMUU, an error will ocurr.
        if printReport; fprintf(freport,'\nGAMS variables were read by MATLAB correctly\n'); end;
        if verbose; fprintf('GAMS variables were read by MATLAB correctly\n'); end;

        %Using GDXMRW to read solutions found by findMustUU.gms
        %extract matrix 1 found by findMustII.gms. This matrix contains the
        %first reaction in each couple of reactions
        m1.name = 'matrix1';
        m1.compress = 'true';
        m1 = rgdx('GtoMUU',m1);
        uels_m1 = m1.uels{2};

        if ~isempty(uels_m1)
            %if the uel array for m1 is not empty, at least 1 couple of reations was found.
            if printReport; fprintf(freport,'\na MustUU set was found\n'); end;
            if verbose; fprintf('a MustUU set was found\n'); end;

            %find values for matrix 1
            val_m1 = m1.val;
            m1_full = full(sparse(val_m1(:,1),val_m1(:,2:end-1),val_m1(:,3)));

            %find values for matrix 2
            m2.name = 'matrix2';
            m2.compress = 'true';
            m2 = rgdx('GtoMUU',m2);
            uels_m2 = m2.uels{2};
            val_m2 = m2.val;
            m2_full = full(sparse(val_m2(:,1),val_m2(:,2:end-1),val_m2(:,3)));

            %initialize empty array for storing
            n_mustSet = size(m1_full,1);
            mustUU = cell(n_mustSet,2);
            pos_mustUU = zeros(size(mustUU));
            mustUU_linear = {};

            %write each couple of reactions.
            for i = 1:n_mustSet
                rxn1 = uels_m1(m1_full(i,:) == 1);
                rxn2 = uels_m2(m2_full(i,:) == 1);
                mustUU(i,1) = rxn1;
                mustUU(i,2) = rxn2;
                pos_mustUU(i,1) = find(strcmp(model.rxns,rxn1));
                pos_mustUU(i,2) = find(strcmp(model.rxns,rxn2));
                mustUU_linear = union(mustUU_linear,[rxn1;rxn2]);
            end
            pos_mustUU_linear = cell2mat(arrayfun(@(x)find(strcmp(x,model.rxns)),mustUU_linear,'UniformOutput', false))';
        else
            %if the uel array for m1 is empty, no couple of reations was found.
            if printReport; fprintf(freport,'\na MustUU set was not found\n'); end;
            if verbose; fprintf('a MustUU set was not found\n'); end;

            %initialize arrays to be returned by this function
            mustUU = {};
            pos_mustUU = [];
            mustUU_linear = {};
            pos_mustUU_linear = [];
        end

        % print info into an excel file if required by the user
        if printExcel
            if  ~isempty(uels_m1)
                currentFolder = pwd;
                cd(outputFolder);
                must = cell(size(mustUU,1),1);
                for i = 1:size(mustUU,1)
                    must{i} = strjoin(mustUU(i,:),' or ');
                end
                xlswrite([outputFileName '_Info'],[{'Reactions'};must]);
                xlswrite(outputFileName,mustUU_linear);
                cd(currentFolder);
                if verbose
                    fprintf(['MustUU set was printed in ' outputFileName '.xls  \n']);
                    fprintf(['MustUU set was also printed in ' outputFileName '_Info.xls  \n']);
                end
                if printReport
                    fprintf(freport,['\nMustUU set was printed in ' outputFileName '.xls  \n']);
                    fprintf(freport,['\nMustUU set was printed in ' outputFileName '_Info.xls  \n']);
                end
            else
                if verbose; fprintf('No mustUU set was found. Therefore, no excel file was generated\n'); end;
                if printReport; fprintf(freport, '\nNo mustUU set was found. Therefore, no excel file was generated\n'); end;
            end
        end

        % print info into a plain text file if required by the user
        if printText
            if ~isempty(uels_m1)
                currentFolder = pwd;
                cd(outputFolder);
                f = fopen([outputFileName '_Info.txt'],'w');
                fprintf(f,'Reactions\n');
                for i = 1:size(mustUU,1)
                    fprintf(f,'%s or %s\n',mustUU{i,1},mustUU{i,2});
                end
                fclose(f);

                f = fopen([outputFileName '.txt'],'w');
                for i = 1:length(mustUU_linear)
                    fprintf(f,'%s\n',mustUU_linear{i});
                end
                fclose(f);

                cd(currentFolder);
                if verbose
                    fprintf(['MustUU set was printed in ' outputFileName '.txt  \n']);
                    fprintf(['MustUU set was also printed in ' outputFileName '_Info.txt  \n']);
                end
                if printReport
                    fprintf(freport,['\nMustUU set was printed in ' outputFileName '.txt  \n']);
                    fprintf(freport,['\nMustUU set was printed in ' outputFileName '_Info.txt  \n']);
                end

            else
                if verbose; fprintf('No mustUU set was found. Therefore, no plain text file was generated\n'); end;
                if printReport; fprintf(freport, '\nNo mustUU set was found. Therefore, no plain text file was generated\n'); end;
            end
        end

        %close file for saving report
        if printReport; fclose(freport); reportClosed = 1; end;
        if printReport; movefile(reportFileName,outputFolder); end;
        delete(gamsMustUUFunction);

        %remove or move additional files that were generated during running
        if keepGamsOutputs
            if ~isdir(outputFolder); mkdir(outputFolder); end;
            movefile('GtoMUU.gdx',outputFolder);
            movefile(regexprep(gamsMustUUFunction,'gms','lst'),outputFolder);
        else
            delete('GtoMUU.gdx');
            delete(regexprep(gamsMustUUFunction,'gms','lst'));
        end

        %go back to the original path
        cd(workingPath);
    catch
        %GAMS variables were not read correctly by MATLAB
        if verbose; fprintf('GAMS variables were not read by MATLAB corretly\n'); end;
        if printReport && ~reportClosed; fprintf(freport, '\nGAMS variables were not read by MATLAB corretly\n'); fclose(freport); end;
        cd(workingPath);
        error('OptForce: GAMS variables were not read by MATLAB corretly');

    end

    %if findMustUU.gms was not executed correctly "run" should be different from 0
else
    %if GAMS was not executed correcttly
    if printReport && ~reportClosed; fprintf(freport, '\nGAMS was not executed correctly\n'); fclose(freport); end;
    if verbose; fprintf('GAMS was not executed correctly\n'); end;
    cd(workingPath);
    error('OptForce: GAMS was not executed correctly');

end

end


function test_bug2265

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_convert_units ft_prepare_sourcemodel

clear all
close all

load(dccnpath('/home/common/matlab/fieldtrip/template/headmodel/standard_bem.mat'));
load(dccnpath('/home/common/matlab/fieldtrip/template/headmodel/standard_mri.mat'));
elecs = ft_read_sens(dccnpath('/home/common/matlab/fieldtrip/template/electrode/standard_1020.elc'));

%%
CMMM = 'cm'; scale=1;
CMMM = 'mm'; scale=10; % prepare_leadfield, or another method does not work with mm (a bugg)

vol = ft_convert_units(vol, CMMM); % Convert the vol to cm, or mm

% construct the dipole grid in the template brain coordinates
% the source units are in cm
% the negative inwardshift means an outward shift of the brain surface for inside/outside detection
cfg = [];
cfg.xgrid = scale*[-20:1:20];
cfg.ygrid = scale*[-20:1:20];
cfg.zgrid = scale*[-20:1:20];
cfg.unit = CMMM;
cfg.tight = 'yes';
cfg.inwardshift = -scale*0;
cfg.headmodel = vol;
template_grid = ft_prepare_sourcemodel(cfg);

assert(strcmp(vol.unit, CMMM));
assert(strcmp(template_grid.unit, CMMM));

%% make a figure with the template head model and dipole grid
figure
hold on
ft_plot_headmodel(vol, 'facecolor', 'cortex', 'edgecolor', 'none');alpha 0.5;
camlight;
ft_plot_mesh(template_grid.pos(template_grid.inside,:));

elecs = ft_convert_units(elecs, CMMM);

[vol, elecs] = ft_prepare_vol_sens(vol, elecs);

ft_plot_mesh(elecs.elecpos,'vertexcolor',[1 .3 .3]);

data = [];
cfg.sourcemodel = template_grid;
cfg.headmodel = vol;
cfg.elec = elecs;
cfg.unit = CMMM;
[grid] = ft_prepare_leadfield(cfg, data);

grid = ft_convert_units(grid, CMMM); %% does not really functional!!

%% Dipole simulation
% note that beamformer scanning will be done with a 1cm grid, so you should
% not put the dipole on a position that will not be covered by a grid
% location later
cfg = [];
cfg.headmodel = vol;
cfg.elec = elecs;
cfg.dip.pos = scale*[
  3 -3 6 % dipole 1
  ];
cfg.dip.mom = [ 1 0 0 ]';

cfg.dip.frequency = [10]*1;
cfg.dip.phase=pi/4*[1];
cfg.dip.amplitude=[10];
cfg.relnoise = .1;
cfg.ntrials = 20;
data = ft_dipolesimulation(cfg);

%% compute the data covariance matrix, which will capture the activity of
% the simulated dipole
cfg = [];
cfg.covariance = 'yes';
cfg.covariancewindow = [data.time{1}(1) data.time{1}(end)];
timelock = ft_timelockanalysis(cfg, data);

%% source analysis
cfg = [];
METHOD = 'lcmv'; % 'lcmv' 'rv' 'mne'
cfg.method = METHOD;
cfg.sourcemodel = grid;

cfg.headmodel = vol;
cfg.elec = elecs;
cfg.snr = 10;
source = ft_sourceanalysis(cfg, timelock);

%% interpolate onto the anatomical MRI

cfg = [];
cfg.downsample = 2;
if strcmp(METHOD,'lcmv')
  cfg.parameter = 'avg.pow';
elseif strcmp(METHOD,'rv')
  cfg.parameter = 'avg.rv';
else
  cfg.parameter = 'avg.pow';
end
source = ft_sourceinterpolate(cfg, source , mri); % Note: this function crashes if mne method is used

%% plot the source reconstruction

cfg = [];
if strcmp(METHOD,'lcmv')
  try, source=rmfield(source,'time'); end
  cfg.funparameter = 'avg.pow';
elseif strcmp(METHOD,'rv')
  try, source=rmfield(source,'time'); end
  cfg.funparameter = 'avg.rv';
else
  cfg.funparameter = 'avg.pow';
end

cfg.method = 'ortho';
ft_sourceplot(cfg, source);


%CONVERTTO  Converts an array to another data type with optional scaling
%
%     dst = cv.convertTo(src)
%     dst = cv.convertTo(src, 'OptionName', optionValue, ...)
%
% ## Input
% * __src__ Input matrix.
%
% ## Output
% * __dst__ Output image of the same size as `src`, and the specified type.
%
% ## Options
% * __RType__ desired output matrix type (`uint8`, `int32`, `double`, etc.),
%   or rather the depth since the number of channels are the same as the input
%   has; if it is negative, the output matrix will have the same type as the
%   input. Default -1
% * __Alpha__ optional scale factor. default 1.0
% * __Beta__ optional delta added to the scaled values. default 0.0
%
% The method converts source pixel values to the target data type.
% Saturation is applied at the end to avoid possible overflows:
%
%     dst = cast(src*alpha + beta, RType);
%
% See also: cv.copyTo, cv.normalize, cast, typecast, im2double, im2uint8,
%  mat2gray
%


function [varargout]=cmaperise(varargin)

% function [Cmapped,indMap]=cmaperise(C,cmap,clim)
%-------------------------------------------------------------------------
% This function creates RGB colors for the data C using the colormap cmap
% and the limits clim.
%
%
% Change log:
% 2019/06/25 Added variable input handling
%-------------------------------------------------------------------------

%% Parse input

switch nargin
    case 1
        C=varargin{1};
        cmap=[];
        clim=[];
    case 2
        C=varargin{1};
        cmap=varargin{2};
        clim=[];
    case 3
        C=varargin{1};
        cmap=varargin{2};
        clim=varargin{3};
end

if isempty(cmap)
    cmap=viridis(250);
end

if isempty(clim)
   clim=[min(C(:)) max(C(:))];
   if diff(clim)<eps(0)
       clim=[min(C(:))-1e-3 max(C(:))+1e-3];
   end
end

%% Use colormap to define RGB values

C=C(:); %Color data as column

p=(C-clim(1))./(clim(2)-clim(1));
p(p<0)=0;
p(p>1)=1;

p(isnan(p))=0; %Force nan data to 0

IND_cmap=round((p*(size(cmap,1)-1))+1);
Cmapped=cmap(IND_cmap,:);

%%
varargout{1}=Cmapped;
if nargout==2
    varargout{2}=IND_cmap;
end

end

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


classdef crossvalidator
% CROSSVALIDATOR crossvalidation class.
%
%   DESCRIPTION
%   The crossvalidator class performs crossvalidation. It uses a
%   particular crossvalidation on a multivariate analysis specified in the
%   property mva.
%
%   One may use 'type' equal to:
%   - 'nfold' : n-fold cross-validation specified by 'folds' (default: 5)
%   - 'split' : data is split into train and test data; amount of training
%               data is given by 'proportion' (default: 0.75)
%   - 'loo'   : leave-one-out cross-validation; takes 1 trial per fold
%   - 'bloo'  : balanced loo cv; takes 1 trial from each class per fold.
%               Assumes that each class has the same nr of trials.
%
%   Alternatively one can specify the cell-arrays 'trainfolds' and
%   'testfolds' to contain for each fold the trial indices that need to be
%   used. If one of these is specified then the other one is automatically
%   filled using the complement of the trials. If these cell-arrays are
%   non-empty then the settings above are ignored.
%
%   In order to balance the occurrence of different classes one may set
%   'resample' equal to true (default: false). Resample will upsample less
%   occurring classes during training and downsample often occurring
%   classes during testing.
%
%   In case of memory problems, use 'compact' equal to true (default:
%   false). This will not store the trained multivariate methods but just
%   the classification outcomes and the parameters that are returned by the
%   model function of the multivariate methods.
%
%   EXAMPLE
%   X = rand(10,20); Y = [1 1 1 1 1 2 2 2 2 2]';
%   m = dml.crossvalidator('mva',dml.svm)
%   m = m.train(X,Y);
%   m.statistic('accuracy')
%
%   DEVELOPER
%   Marcel van Gerven (m.vangerven@donders.ru.nl)

    properties

      mva % multivariate analysis

      result % crossvalidation result

      design % the real outputs

      model % estimated model per fold

      type = 'nfold'; % 'type' : crossvalidation type 'nfold', 'split', 'loo'

      folds = 5; % 'folds' : number of folds when using nfold

      proportion = 0.75; % 'proportion' : proportion of used training data when using split

      resample = false; % 'resample' : whether or not to use resampling to balance classes

      % cell array indicating used trials per training fold
      % for multiple datasets this should be come a cell array of cell
      % arrays, e.g. trainfolds = { {f1 ... fn} {f1 ... fn} }
      trainfolds

      % cell array indicating used trials per test fold
      % for multiple datasets this should be come a cell array of cell
      % arrays, e.g. testfolds = { {f1 ... fn} {f1 ... fn} }
      testfolds

      stat = ''; % test statistic used to quantify performance of this cross-validator

      verbose = false; % generate output when true

      compact = false; % drop mva details when true

    end

    methods

      function obj = crossvalidator(varargin)

        % parse options
        for i=1:2:length(varargin)
          if ismember(varargin{i},fieldnames(obj))
            obj.(varargin{i}) = varargin{i+1};
          else
            error('unrecognized fieldname %s',varargin{i});
          end
        end

        if ~isa(obj.mva,'dml.analysis'), obj.mva = dml.analysis(obj.mva); end

      end

      function obj = train(obj,X,Y)

        % complete the folds when only train or test is specified
        if isempty(obj.trainfolds) && isempty(obj.testfolds)
          [obj.trainfolds,obj.testfolds] = obj.create_folds(Y);
        elseif isempty(obj.trainfolds)
          obj.trainfolds = obj.complement(Y,obj.testfolds);
        else
          obj.testfolds = obj.complement(Y,obj.trainfolds);
        end

        if iscell(Y)
          ndata = length(Y);
        else
          ndata = 1;
        end

        if ndata == 1
          nfolds = length(obj.trainfolds);
        else
          nfolds = length(obj.trainfolds{1});
        end

        obj.result = cell(nfolds,1);
        obj.design = cell(nfolds,1);
        obj.model = cell(nfolds,1);

        if ~iscell(obj.mva)
          obj.mva = repmat({obj.mva},[1 nfolds]);
        end

        for f=1:nfolds % iterate over folds

          if obj.verbose
            if ndata == 1
              fprintf('validating fold %d of %d for %d datasets\n',f,nfolds,ndata);
            else
              fprintf('validating fold %d of %d for %d datasets\n',f,nfolds,ndata);
            end
          end

          % construct X and Y for each fold
          if ndata == 1
            trainX = X(obj.trainfolds{f},:);
            testX = X(obj.testfolds{f},:);
            trainY = Y(obj.trainfolds{f},:);
            testY = Y(obj.testfolds{f},:);
          else
            trainX = cell([length(X) 1]);
            testX = cell([length(X) 1]);
            for c=1:length(X)
              trainX{c} = X{c}(obj.trainfolds{c}{f},:);
              testX{c} = X{c}(obj.testfolds{c}{f},:);
            end
            trainY = cell([length(Y) 1]);
            testY = cell([length(Y) 1]);
            for c=1:length(Y)
              trainY{c} = Y{c}(obj.trainfolds{c}{f},:);
              testY{c} = Y{c}(obj.testfolds{c}{f},:);
            end
          end

          tproc = obj.mva{f}.train(trainX,trainY);
          if ~isempty(testY)
            obj.result{f} = tproc.test(testX);
            obj.design{f} = testY;
          end
          obj.model{f} = tproc.model();

          if ~obj.compact, obj.mva{f} = tproc; end

          clear tproc;
          clear trainX;
          clear testX;
          clear trainY;
          clear testY;

        end

        % return unique model instead of cell array in case of one fold
        if length(obj.model)==1, obj.model = obj.model{1}; end

      end

      function [train,test] = create_folds(obj,Y)
      % get predefined sequence for train and test folds

      if strcmp(obj.type,'loo') || strcmp(obj.type,'bloo')

        if iscell(Y)
          obj.folds = min(cellfun(@(x)(size(x,1)),Y));
          if strcmp(obj.type,'bloo')
            nclasses = max(cellfun(@(x)(max(x)),Y));
            obj.folds = obj.folds/nclasses;
          end
        else
          obj.folds = size(Y,1);
          if strcmp(obj.type,'bloo')
            nclasses = max(Y);
            for k = 1:nclasses
              N(k,1) = sum(Y==k);
            end
            obj.folds = min(N);
            %obj.folds = obj.folds/nclasses;
          end
        end
        obj.type = 'nfold';

      end

      if strcmp(obj.type,'split'), obj.folds = 1; end

      if ~iscell(Y)

        test = create_test_folds(Y);

        train = obj.complement(Y,test);

        if obj.resample
          train = upsample(train,Y);
          test  = downsample(test,Y);
        end

      else

        train = cell(length(Y),1);
        test = cell(length(Y),1);

        for c=1:length(Y)

          test{c} = create_test_folds(Y{c});

          train{c} = obj.complement(Y{c},test{c});

          if obj.resample
            train{c} = upsample(train{c},Y{c});
            test{c}  = downsample(test{c},Y{c});
          end

        end

      end

        function y = create_test_folds(Y)

          % NOTE: Fixing of the random seed has been removed here in the fieldtrip
          % version since the randomseed is dealt with higher up in the code
          % hierarchy (i.e. specify cfg.randomseed in ft_timelockstatistics).

          y = cell(obj.folds,1);

          % determine indices of labeled (non-nan) datapoints
          % nan datapoints should end up in the training set
          labeled = find(any(~isnan(Y(1:size(Y,1),:)),2));
          if obj.verbose && numel(labeled)<size(Y,1)
            fprintf('adding unlabeled samples to training set\n');
          end

          % randomize labeled trials
          nsamples = size(labeled,1);
          idxs = labeled(randperm(nsamples));

          % make sure outcomes are evenly represented whenever possible
          [t,t,idx] = unique(Y,'rows');
          mx = max(idx);

          switch obj.type

            case 'split'

              if obj.verbose, fprintf('creating sample indices using %.0f%% of the data for testing\n',100*(1-obj.proportion)); end

              if mx == nsamples % unique labeled samples

                y{1} = idxs(1:round((1-obj.proportion)*nsamples));

              else

                % take labeled indices
                idx = idx(idxs);
                for j=1:mx
                  iidx = find(idx == j);
                  y{1} = [y{1}; idxs(iidx(1:floor((1-obj.proportion)*numel(iidx))))];
                end

                % add random instances to complete the number
                n = floor((1-obj.proportion) * numel(idxs)) - numel(y{1});
                if n>0
                  x = setdiff(idxs,y{1});
                  x = x(randperm(numel(x)));
                  y{1} = [y{1}; x(1:n)];
                end

              end

            case 'nfold'

              if obj.verbose, fprintf('creating sample indices using %d-fold cross-validation\n',obj.folds); end

              if mx == nsamples % unique samples

                for f=1:obj.folds
                  y{f} = idxs((floor((f-1)*(length(idxs)/obj.folds))+1):floor(f*(length(idxs)/obj.folds)));
                end

              else

                % take labeled indices
                idx = idx(idxs);

                f=1;
                for j=1:mx
                  iidx = find(idx == j);
                  for k=1:length(iidx)
                    y{f} = [y{f}; idxs(iidx(k))];
                    f = f+1; if f > obj.folds, f=1; end
                  end
                end

              end

            otherwise
              error('unrecognized option for type');
          end

        end

        function y = downsample(F,Y)
          % make sure all classes are represented equally in the
          % train samples by sampling with replacement and in the
          % test samples by using the minimum number of trials in a
          % condition. This ensures that training makes most use of
          % the data while testing has no inherent bias in the
          % data. We lose power by removing superfluous trials.

          y = cell(size(F));

          if obj.verbose
            fprintf('balancing test samples by removing superfluous trials\n');
          end

          for f=1:length(F)

            % get unique rows of Y
            [unq,t,idx] = unique(Y,'rows');

            idx = idx(F{f});

            minsmp = min(arrayfun(@(x)(sum(idx == x)),unq));

            if minsmp > 0

              tmp = [];
              for j=1:length(unq)

                iidx = find(idx == unq(j));

                if obj.verbose && length(iidx) - minsmp ~=0
                  fprintf('removing %d superfluous samples for label %d\n',length(iidx) - minsmp,unq(j));
                end

                tmp = [tmp; F{f}(iidx(1:minsmp))];

              end

              y{f} = tmp(randperm(length(tmp)));

            end

          end

        end

        function y = upsample(F,Y)
          % make sure all classes are represented equally in the
          % train samples by sampling with replacement and in the
          % test samples by using the minimum number of trials in a
          % condition. This ensures that training makes most use of
          % the data while testing has no inherent bias in the
          % data. We lose power by removing superfluous trials.

          y = cell(size(F));

          if obj.verbose
            fprintf('balancing training samples by sampling with replacement\n');
          end

          for f=1:length(F)

            % get unique rows of Y
            [unq,t,idx] = unique(Y,'rows');

            idx = idx(F{f});

            maxsmp = max(arrayfun(@(x)(sum(idx == x)),unq));

            tmp = F{f};
            for j=1:length(unq)

              iidx = find(idx == unq(j));

              if obj.verbose && maxsmp - length(iidx) ~= 0
                fprintf('drawing %d additional samples for label %d\n',maxsmp - length(iidx),unq(j));
              end

              % nameclash with fieldtrip_private!
              tmp = [tmp; randsample(F{f}(iidx),maxsmp - length(iidx),true)];

            end

            y{f} = tmp(randperm(length(tmp)));

          end

        end

      end

      function s = statistic(obj,stat)
        % report statistics on a trained crossvalidator object; also see
        % dml.statistic

        if nargin<2, stat = obj.stat; end

        if iscell(obj.design{1}) && iscell(obj.result{1})

          s = zeros(length(obj.design),1);
          for c=1:length(obj.design{1}) % iterate over datasets
            D = [];
            P = [];
            for f=1:length(obj.design) % iterate over folds
              D = cat(1,D,obj.design{f}{c});
              P = cat(1,P,obj.result{f}{c});
            end
            s(c) = dml.statistic(stat,D,P);
          end

        else

          D = cell2mat(obj.design);
          P = cell2mat(obj.result);
          s = dml.statistic(stat,D,P);

        end

      end

    end

    methods(Access=private,Static=true)

      function y = complement(Y,folds)
        % create complement of trials in each of the folds when only training
        % or test folds are specified

        if iscell(Y)
          ndata = length(Y);
        else
          ndata = 1;
        end

        y = cell(size(folds));
        for c=1:length(folds)
          if ndata == 1
            y{c} = setdiff(1:size(Y,1),folds{c})';
          else
            for f=1:length(folds{c})
              y{c}{f} = setdiff(1:size(Y{c},1),folds{c}{f})';
            end
          end
        end

      end

    end

end


%% calculate AUC

for j=1:15
[~,~,~,AUC(j)] = perfcurve(ans_auc(:,j),prop(:,j),0);
end

mean_AUC = mean(AUC);
disp(mean_AUC)


% easy11    Creates a stereographic plot of GPS satellite  orbits
%                from an epehemerides or almanac file. The plot is as
%                seen from the position (phi, lambda). All (parts of)
%                orbits with elevation angle lower than a given
%                cut-off angle (mask) are omitted.
%                As input we use the ephemerides in our basic RINEX
%               navigation file. It only contains nine ephemerides. The
%               result shows two windows with a considerable amount
%               of visible satellites. This is like the actual situation in the
%               early 1990es. Then you could have a window  of about
%               one hour at say 5--6 am and this repeated 12 hours later.
%
%              An additional plot is created showing number
%              of visible satellites and when they are visible.
%              Finally a stem plot depicts the number of
%             satelliets visible for how long
%
%             Alternatively, if you want to include all GPS satellites,
%             we need an almanac file which can be downloaded from
%             http://www.navcen.uscg.gov/?pageName=gpsAlmanacs

%Kai Borre 26-08-2008
%Copyright (c) by Kai Borre
%$Revision: 1.1 $  $Date: 2009/04/05  $
% Total revision January 10, 2016

% RINEX version 3.03

set(0,'DefaultTextFontName','Times');
set(0,'DefaultAxesFontName','Times');
set(0,'DefaultTextFontSize',12);

% If you want to use a RINEX ephemeris file uncomment
% line 37 and comment line 41 out.

% the following five assignments are mandatory
%%rinexe('log_24h.15n','eph.dat');
% in  case you want to include all GPS satellites in the constellation,
% we need an almanac. This is read and converted to the usual
% eph format by the following call
rinexa('current.alm','eph.dat');

ephemerides = 'eph.dat';
mask = 10;
phi = [57 12 43];
lambda = [50 10 39];

%reading ephemerides
fide = fopen(ephemerides,'r');
Eph = fread(fide,inf,'double');
m = length(Eph);
eph = reshape(Eph,21,m/21);

% transformation of given location (phi,lambda,h) to (X,Y,Z)
Phi = dms2rad(phi(1),phi(2),phi(3));
Phi = Phi*180/pi;
Lambda = dms2rad(lambda(1),lambda(2),lambda(3));
Lambda = Lambda*180/pi;
[M(1,1),M(2,1),M(3,1)] = frgeod(6378137,298.257222101,Phi,Lambda,0);

% Computation of (azimuth, elevation) for each satellite
% for each 15 min.s. We use only one ephemeris for each PRN.
% Anyway, the plot is only for visual use
[prns, ind] = unique(eph(1,:));
satrows = length(ind);
 az = ones(satrows,96)*inf; % satrows is number of PRN and 96 quaters of an hour in 24 hours
el = ones(satrows,96)*inf;

start_time = max(eph(21,:));
for sat = ind'
    j = 0;
    for time = start_time:900:start_time+86400
        S = satpos(time,eph(:,sat)); %sat
        j = j+1;
        [azimuth,elevation,distance] = topocent(M,S-M);
        az(sat,j) = azimuth; % sat runs over PRN, j runs over sow
        el(sat,j) = elevation;
    end
end
% We assume that there are satrows PRNs
XX = zeros(satrows,40)*inf; % a matrix of NaNs to store plot data
YY = XX;

figure(1);
% polarhg draws coordinate lines of a polar plot. We add
% circles with radii 30 and 60 degrees
polarhg([30 60])
hold on
for k = ind' % 1:32
    % if az(k,1) == 0, break, end  % continue
    AZ = az(k,:);
    EL = el(k,:);
    % remove data below the cut-off angle
    AZ(find(EL <= mask)) = nan;
    EL(find(EL <= mask)) = nan;
    % conversion from polar to rectangular coordinates
    xx = (90-EL).*cos(AZ*pi/180);
    yy = (90-EL).*sin(AZ*pi/180);
    XX(k,1:length(xx)) = xx;
    YY(k,1:length(yy)) = yy;
end % k
%the first coord. moves text vertically (increasing values up),
% the second coord. moves text horizontally (increasing values right)
text(135,-95,{['Skyplot for the position (\phi, \lambda) = (' ...
    num2str(round(Phi)) '\circ, '  num2str(round(Lambda)) '\circ)']})
text(115,-45,{['Elevation mask  ' num2str(mask) '\circ' ]}) %120
text(-120,-120,['All PRNs except  ' num2str(setdiff(1:32,prns)) ])
plot(XX',YY','linewidth',2)
hold off
set(gca,'Fontsize',9);

print('easy111','-dpdf')

% preparation for visibility plot  %%%

% we choose a resolution of 5 min.s,
% ie. 24 hours times 12 = 288 which becomes the range of j
satsum = zeros(1,288);
visible = zeros(2*(size(prns,2)+1),288);

for sat = ind'
    %Az = [];
    %El = [];
    i = eph(1,sat);
    for j = 1:288
        time = 300*(j-1); % in s, 0<time<86400
        S = satpos(time,eph(:,sat));
        [az,el,d] = topocent(M,S-M);
        if el > mask
 %           Az = [Az az];
  %          El = [El el];
            satsum(j) = satsum(j)+1;
            visible(2*i,j) = 1;
        end
    end
end

figure(2);
set(gca,'Fontsize',16);
area(satsum)
set(gca,'XTick',1:71:288)
set(gca,'XTickLabel',{'0','6','12','18','24'})
xlabel('GPS Time [hours]')
ylabel('# of Visible Satellites')
title(['Elevation Mask ' num2str(mask) '\circ'])
colormap summer

print -dpdf easy112

figure(3);
set(gca,'Fontsize',16);
imagesc(flipud(visible));
colormap(autumn(5))
set(gca,'XTick',1:71:288)
set(gca,'XTickLabel',{'0','6','12','18','24'})
set(gca,'YTick',-3:16:(2*(size(prns,2)+1)))
set(gca,'YTickLabel',{'2','8','16','24','32'});
xlabel('GPS Time [hours]')
ylabel('PRNs')
title('Yellow Lines Indicate Visible Satellites')
colormap winter

print -dpdf easy113

figure(4);
set(gca,'Fontsize',16);
an = sum(visible,1);
% we assume the total # of PRNs always is between 1 and 20
total = zeros(1,20);
for i = 1:288
    j = an(i);
    if j == 0, j = j+1; total(j) = 0.01; continue, end
    total(j) = total(j)+1;
end
% the adder total adds per 5 minutes, division by 12 changes to per hour
bar(1:20,total/12);  % 10-> 32
title('Number of Visible Satellites')
ylabel('Hours')

print -dpdf easy114

%%%%%%%%%%%%%%%%%%%%% end easy11.m %%%%%%%%%%%%%%


function test_suite = test_distancePointLine
%TESTDISTANCEPOINTEDGE  One-line description here, please.
%   output = test_distancePointLine(input)
%
%   Example
%   testDistancePointLine
%
%   See also
%
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2012-10-24,    using Matlab 7.7.0.471 (R2008b)
% Copyright 2009 INRA - Cepia Software Platform.

test_suite = functiontests(localfunctions);

function testBasic(testCase) %#ok<*DEFNU>
point = [0 0];
line = [1 2 1 0];
testCase.assertEqual(2, distancePointLine(point, line), 'AbsTol', .01);

function testHorizontal(testCase)
% an horizontal line, with points all around
line = [2 2 2 0];
testCase.assertEqual(distancePointLine([1 1], line), 1, 'AbsTol', .01);
testCase.assertEqual(distancePointLine([2 1], line), 1, 'AbsTol', .01);
testCase.assertEqual(distancePointLine([3 1], line), 1, 'AbsTol', .01);
testCase.assertEqual(distancePointLine([4 1], line), 1, 'AbsTol', .01);
testCase.assertEqual(distancePointLine([5 1], line), 1, 'AbsTol', .01);
testCase.assertEqual(distancePointLine([5 2], line), 0, 'AbsTol', .01);
testCase.assertEqual(distancePointLine([5 3], line), 1, 'AbsTol', .01);

function testDiagonal(testCase)
% diagonal (slope 2)
line = [1 1 3 6];
testCase.assertEqual(0, distancePointLine([3 5], line));
testCase.assertEqual(sqrt(5), distancePointLine([3 0], line), 'AbsTol', .01);

function testSingleMulti(testCase)
point = [5 5];
lines = [0 0 3 0;10 0 0 3;10 10 -3 0;10 0 3 3];
exp = [5 5 5 5*sqrt(2)];
testCase.assertEqual(exp, distancePointLine(point, lines), 'AbsTol', .01);

function testSingleMultiWithInvalid(testCase)
point = [5 5];
lines = [0 0 3 0;10 0 0 3;10 10 -3 0;10 0 3 3;10 0 0 0];
exp = [5 5 5 5*sqrt(2) 5*sqrt(2)];
testCase.assertEqual(exp, distancePointLine(point, lines), 'AbsTol', .01);

function testMultiSingle(testCase)
line  = [10 10 5 0];
points = [10 10;15 10;20 10;10 0;30 10];
exp = [0; 0; 0; 10; 0];
testCase.assertEqual(exp, distancePointLine(points, line), 'AbsTol', .01);

function testMultiSingleInvalidLine(testCase)
line  = [15 10 0 0];
points = [10 10; 15 10; 20 10; 10 10; 30 10];
exp = [5; 0; 5; 5; 15];
testCase.assertEqual(exp, distancePointLine(points, line), 'AbsTol', .01);

function testMultiMulti(testCase)
lines  = [10 30 10 0; 20 30 0 10;20 40 -10 0;10 40 0 -10];
points = [14 33;15 38];
exp = [3 6 7 4;8 5 2 5];
testCase.assertEqual(exp, distancePointLine(points, lines), 'AbsTol', .01);

function testMultiMultiWithInvalid(testCase)
lines  = [10 30 10 0; 20 30 0 10;20 40 -10 0;10 40 0 -10;10 30 0 0];
points = [14 33;15 38];
exp = [3 6 7 4 5;8 5 2 5 hypot(8, 5)];
testCase.assertEqual(exp, distancePointLine(points, lines), 'AbsTol', .01);


function F = vertcat(varargin)
%VERTCAT   Vertical concatenation of SEPARABLEAPPROX objects.
%
% VERTCAT(F, G) is the vertical concatenation of SEPARABLEAPPROX objects F and G.
% This function returns a CHEBFUN2V object.
%
% [F; G] is equivalent to VERTCAT(F, G).
%
% VERTCAT(F) returns the SEPARABLEAPPROX F.
%
% See also CHEBFUN2V.

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

if ( nargin == 1 )
    % VERTCAT of one argument just returns the same thing back to the user:
    F = varargin{1};
elseif ( nargin > 1 )
    if ( isa(varargin{2}, 'chebfun2v') )
        f = varargin{1};
        F = varargin{2};
        if ( F.nComponents > 2 )
            error('CHEBFUN:SEPARABLEAPPROX:vertcat:tooManyComponents', ...
                'Only CHEBFUN2V objects with 2 or 3 components are valid.');
        else
            Fc = F.components;
            g = Fc{1};
            h = Fc{2};
            F = chebfun2v({f, g, h});
        end
    elseif ( isa(varargin{ 2 }, 'separableApprox' ) )
        % call the CHEBFUN2V constructor.
        F = chebfun2v( varargin{:} );
    end
else
    error('CHEBFUN:SEPARABLEAPPROX:vertcat:tooManyInputs', ...
        'Cannot vertically concatenate more than three SEPARABLEAPPROX objects.');
end

end


function [text, timeStamp] = ReadPraatTextGrid(transFile)
feature('DefaultCharacterSet', 'UTF8');

trans = my_cat(transFile);

for i=1:length(trans)
    if length(trans{i})>4 && strcmp(trans{i}(1:4), 'item')
        break;
    end
end
i = i+ 6;
idx = regexp(trans{i}, '=');
nInterval = str2num(trans{i}(idx+1:end));

i = i + 1;
for cnt = 1:nInterval
    idx = regexp(trans{i+1}, '=');
    timeStamp(1,cnt) = str2num(trans{i+1}(idx+1:end));

    idx = regexp(trans{i+2}, '=');
    timeStamp(2,cnt) = str2num(trans{i+2}(idx+1:end));

    idx = regexp(trans{i+3}, '"');
    text{cnt} = trans{i+3}(idx(1)+1:idx(end)-1);
    i = i+4;

%      fprintf('%2.2f %2.2f %s\n', timeStamp(1,cnt), timeStamp(2,cnt), text{cnt});
end

cnt = 1;
text2 = {};
for j=1:length(text)
    if length(text{j})>0
        text2{cnt} = text{j};
        timeStamp2(:,cnt) = timeStamp(:,j);
        cnt = cnt + 1;
    end
end

text = text2;
timeStamp = timeStamp2;


function params = mrParamsCorAnal(mr);
% Put up a dialog to get params for a coherence analysis.
%
% params = mrParamsCorAnal(mr);
%
% This is an attempt to emulate the style of mrLoadRet end+1.0,
% in which analyses have related GUIs to get params.
% So, corAnal has a corresponding corAnalGUI to get cor anal
% params. This is the equivalent mrVista 2.0 implementation.
%
% Thought on naming conventions: for other analyses, it might
% be good to also start with mrParams -- mr since the params are
% operating on mr objects, and params, because that is the output
% of this dialog.
%
% Note: an mr struct must be entered, since it's needed for
% the default set of frames (all).
%
% ras, 07/05.

%%%%% default params (if omitted from params struct):
nCycles = 6;   % just a guess that many scans use
noiseBand = 0; % use all available spectral bands for analysis
saveDir = fileparts(mr.path);
detrend = 1;

% put up dialog to get params
dlg(1).fieldName = 'nCycles';
dlg(1).style = 'edit';
dlg(1).string = 'Number of Cycles in Time Series';
dlg(1).value = num2str(nCycles);

dlg(end+1).fieldName = 'detrend';
dlg(end).style = 'checkbox';
dlg(end).string = 'Detrend Time Series?';
dlg(end).value = detrend;

dlg(end+1).fieldName = 'noiseBand';
dlg(end).style = 'edit';
dlg(end).string = 'Noise Band Option';
dlg(end).value = num2str(noiseBand);

dlg(end+1).fieldName = 'frames';
dlg(end).style = 'edit';
dlg(end).string = 'Frames to Analyze';
dlg(end).value = sprintf('1:%i',size(mr.data,4));

dlg(end+1).fieldName = 'saveDir';
dlg(end).style = 'edit';
dlg(end).string = 'Save directory';
dlg(end).value = saveDir;

params = generalDialog(dlg,sprintf('Coherence Analysis: %s',mr.name));

% if canceled, exit quietly
if isempty(params), disp('User Aborted corAnal.'); return;   end

% parse params
params.nCycles = str2num(params.nCycles);
params.noiseBand = str2num(params.noiseBand);
params.frames = str2num(params.frames);

return


function h = get_parent_stats(h)

h.dat.stat(1).V = [];
for i = 1:length(h.dat.stat)
    if ~isfield(h.dat.stat(i), 'V') || isempty(h.dat.stat(i).V)
        h.dat.stat(i).V         = sum([h.dat.stat(i).region.V]);
        h.dat.stat(i).mrs = min(h.dat.stat(i).mrs, 1e4);
       % this is a parent region
        h.dat.stat(i).parent    = i;
        h.dat.stat(i).VperPix   = h.dat.stat(i).V/h.dat.stat(i).npix;
        h.dat.stat(i).npix_res  = numel(h.dat.stat(i).ipix);
        h.dat.stat(i).nregions  = numel(h.dat.stat(i).region);
    end
end

nreg = [h.dat.stat.nregions];
npix_res = [h.dat.stat.npix_res];
npix = [h.dat.stat.npix];

VperPix = [h.dat.stat.VperPix];
mrs = [h.dat.stat.mrs]./[h.dat.stat.mrs0];
iparent = [h.dat.stat.parent];

h.dat.cl.nreg       = nreg(iparent);
h.dat.cl.npix_res   = npix_res(iparent);
h.dat.cl.npix_par   = npix(iparent);
h.dat.cl.VperPix    = VperPix(iparent);
h.dat.cl.mrs_parent = mrs(iparent);


function conv2conv()
    global config mem;
    curr_layer_idx = config.misc.current_layer;
    conv_layer_idx = get_conv_layer_idx_from_layer_idx(curr_layer_idx);
    P_reshape = reshape(mem.activations{curr_layer_idx-1}', config.feature_map_sizes{curr_layer_idx-1}(1), config.feature_map_sizes{curr_layer_idx-1}(2)*config.feature_map_sizes{curr_layer_idx-1}(3)*config.batch_size);
    P_expand = config.IM2COL(P_reshape, [config.kernel_size(conv_layer_idx, 1), config.kernel_size(conv_layer_idx, 2)]);
    P_expand(:, mem.conv2conv{curr_layer_idx}{2}) = 0;
    input_size = [0 0];
    input_size(1) = config.kernel_size(conv_layer_idx, 1)*config.kernel_size(conv_layer_idx, 2)*config.feature_map_sizes{curr_layer_idx-1}(3);
    input_size(2) = (config.feature_map_sizes{curr_layer_idx-1}(1)-config.kernel_size(conv_layer_idx, 1)+1)*(config.feature_map_sizes{curr_layer_idx-1}(2)-config.kernel_size(conv_layer_idx, 2)+1)*config.batch_size;
    mem.layer_inputs{curr_layer_idx} = reshape(accumarray(mem.conv2conv{curr_layer_idx}{1}, P_expand(:), [input_size(1)*input_size(2), 1]), input_size(1), input_size(2));
    % memory redundancy, need improve
    mem.orig_activation_size{curr_layer_idx-1} = size(mem.activations{curr_layer_idx-1});
    mem.activations{curr_layer_idx-1} = mem.layer_inputs{curr_layer_idx};
end


function [PowerPhaseRatemap,spikebinIDs] = bz_PowerPhaseRatemap(spikes,filteredLFP,varargin)
%[PowerPhaseRatemap,spikebinIDs] = bz_PowerPhaseRatemap(spikes,filteredLFP,varargin)
%
%INPUTS
%   spikes          structure containing spikes.times from bz_getSpikes
%   filteredLFP     structure containing filteredLFP.timestamps,
%                       filteredLFP.amp, filteredLFP.phase,
%                       filteredLFP.samplingRate. from bz_Filter(lfp).
%
%  (options)
%   'ints'
%   'powernorm'     (default: 'modZ')
%   'ratenorm'      (default: 'none')
%   'numbins'       (default: 20)
%   'metric'        if you would like to calculate average of some other
%                   metric (i.e. not rate) as function of power/phase
%                   should be cell array (similar to spikes) with value of
%                   other metric for each spike
%   'Nspikethresh'  number of spikes threshold to count mean metric
%                   (default: 10)
%
%OUTPUTS
%   PowerPhaseRatemap
%   spikebinIDs
%
%DLevenstein 2018
%% DEV
p = inputParser;
addParameter(p,'ints',[0 Inf],@isnumeric)
addParameter(p,'powernorm','Zlog')
addParameter(p,'metric',[])
addParameter(p,'Nspikethresh',10)

parse(p,varargin{:})
ints = p.Results.ints;
powernorm = p.Results.powernorm;
metric = p.Results.metric;
Nspikethresh = p.Results.Nspikethresh;

%% Find lfp and spikes in the intervals
instatespiketimes = cellfun(@(X) InIntervals(X,ints),...
    spikes.times,'UniformOutput',false);
instateLFPtimes = InIntervals(filteredLFP.timestamps,ints);

%%
numcells = length(spikes.times);
%%

%Normalize Power
switch powernorm
    case 'Zlog'
        filteredLFP.amp = NormToInt(log10(filteredLFP.amp),'Z',ints,filteredLFP.samplingRate);
end

%%

%Get Power/Phase at each spike
spikes.amp = cellfun(@(X) interp1(filteredLFP.timestamps,filteredLFP.amp,X,'nearest'),...
    spikes.times,'uniformoutput',false);
spikes.phase = cellfun(@(X) interp1(filteredLFP.timestamps,filteredLFP.phase,X,'nearest'),...
    spikes.times,'uniformoutput',false);

%%
numbins = 20;

%Power/Phase Bins
phaseedges = linspace(-pi,pi,numbins+1);
PowerPhaseRatemap.phasebins=phaseedges(1:end-1)+0.5.*diff(phaseedges(1:2));
poweredges = linspace(-1.8,1.8,numbins+1);
PowerPhaseRatemap.powerbins=poweredges(1:end-1)+0.5.*diff(poweredges(1:2));
poweredges(1) = -Inf; poweredges(end) = Inf;

%Calculate Power/Phase Spike Histogram
%phaseamphist = cellfun(@(X,Y) hist3([X,Y],{powerbins,phasebins}),spikeamp,spikephase,'UniformOutput',false);

[PowerPhaseRatemap.Nspikes,~,~,spikebinIDs.powerbin,spikebinIDs.phasebin] = ...
    cellfun(@(X,Y,Z) histcounts2(X(Z),Y(Z),poweredges,phaseedges),...
    spikes.amp,spikes.phase,instatespiketimes,...
    'UniformOutput',false);

%Calculate Power/Phase Time Histogram
%phaseamphist_t = hist3([t_amp,t_phase],{powerbins,phasebins});
%phaseamphist_t = phaseamphist_t./sf_LFP;

PowerPhaseRatemap.occupancy = ...
    histcounts2(filteredLFP.amp(instateLFPtimes),...
    filteredLFP.phase(instateLFPtimes),poweredges,phaseedges);
PowerPhaseRatemap.occupancy = ...
    PowerPhaseRatemap.occupancy./filteredLFP.samplingRate;
PowerPhaseRatemap.powerdist = sum(PowerPhaseRatemap.occupancy,2);

%Normalize Rate
%totaltime = sum(diff(ints,1,2));
%meanrate = cellfun(@(X) length(X)./totaltime,spiketimes,'UniformOutput',false);
PowerPhaseRatemap.ratemap = cellfun(@(X) X./PowerPhaseRatemap.occupancy,...
    PowerPhaseRatemap.Nspikes,'UniformOutput',false);
%phaseamprate = cellfun(@(X,Y) X./Y,phaseamprate,meanrate,'UniformOutput',false);

PowerPhaseRatemap.meanrate = nanmean(cat(3,PowerPhaseRatemap.ratemap{:}),3);

if ~isempty(metric)
    for po = 1:length(PowerPhaseRatemap.powerbins)
        for ph = 1:length(PowerPhaseRatemap.phasebins)

            %Find the spikes in the right bin
            inbinspikes = cellfun(@(X,Y,Z) X==po & Y==ph ,...
                spikebinIDs.powerbin,spikebinIDs.phasebin,...
                'UniformOutput',false);

            %Find the metric from spikes in the state
            instatmetric = cellfun(@(X,Y) X(Y),metric,instatespiketimes,...
                'UniformOutput',false);

            %Map for each cell
            for cc = 1:numcells
                PowerPhaseRatemap.metricmap{cc}(po,ph) = ...
                    nanmean(instatmetric{cc}(inbinspikes{cc}));

                 %Threshold.
                if sum(inbinspikes{cc}) < Nspikethresh
                    PowerPhaseRatemap.metricmap{cc}(po,ph) = nan;
                end
            end

        end
    end

	PowerPhaseRatemap.meanmetric = nanmean(cat(3,PowerPhaseRatemap.metricmap{:}),3);

end
%%
%excell = randsample(spikes.numcells,1);
figure
% subplot(2,2,1)
%     imagesc(PowerPhaseRatemap.phasebins,PowerPhaseRatemap.powerbins,...
%         PowerPhaseRatemap.ratemap{excell})
%     hold on
%     imagesc(PowerPhaseRatemap.phasebins+2*pi,PowerPhaseRatemap.powerbins,...
%         PowerPhaseRatemap.ratemap{excell})
%     xlim([-pi 3*pi])
%     axis xy
%     colorbar

subplot(2,2,1)
    imagesc(PowerPhaseRatemap.phasebins,PowerPhaseRatemap.powerbins,...
        PowerPhaseRatemap.meanrate)
    hold on
    imagesc(PowerPhaseRatemap.phasebins+2*pi,PowerPhaseRatemap.powerbins,...
        PowerPhaseRatemap.meanrate)
    plot(linspace(-pi,3*pi,100),cos(linspace(-pi,3*pi,100)),'k')
    xlim([-pi 3*pi])
    axis xy
    colorbar
    xlabel('Phase');
    ylabel('Power (Z(log))')

subplot(2,2,3)
    bar(PowerPhaseRatemap.powerbins,PowerPhaseRatemap.powerdist)
    xlabel('Power (Z(log))');ylabel('Time (s)')
    box off
    axis tight

if ~isempty(metric)
    subplot(2,2,2)
        h = imagesc(PowerPhaseRatemap.phasebins,PowerPhaseRatemap.powerbins,...
            PowerPhaseRatemap.meanmetric);
        hold on
        h2 = imagesc(PowerPhaseRatemap.phasebins+2*pi,PowerPhaseRatemap.powerbins,...
            PowerPhaseRatemap.meanmetric);
        set(h,'AlphaData',~isnan(PowerPhaseRatemap.meanmetric));
        set(h2,'AlphaData',~isnan(PowerPhaseRatemap.meanmetric));
        plot(linspace(-pi,3*pi,100),cos(linspace(-pi,3*pi,100)),'k')
        xlim([-pi 3*pi])
        axis xy
        colorbar
        xlabel('Phase');
        ylabel('Power (Z(log))')
end

end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Spherical Harmonic Modeling and Analysis Toolkit (SPHARM-MAT) is a 3D
% shape modeling and analysis toolkit.
% It is a software package developed at Shenlab in Center for Neuroimaging,
% Indiana University (SpharmMat@gmail.com, http://www.iupui.edu/~shenlab/)
% It is available to the scientific community as copyright freeware
% under the terms of the GNU General Public Licence.
%
% Copyright 2009, 2010, ShenLab, Center for Neuroimaging, Indiana University
%
% This file is part of SPHARM-MAT.
%
% SPHARM-MAT 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.
%
% SPHARM-MAT 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 SPHARM-MAT. If not, see <http://www.gnu.org/licenses/>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%
% match fvec to atlas by rotating the parameterization of fvec
% - object does not transform in the object space
% - alpha, beta, gamma: samples in the rotation space
% - gran = # of alphas to process together
% - res: base res R + step of hierarchy Hs + depth of hierarchy Hd + top N
%

function [best_fvec, best_angl] = match_param_hie(fvec,atlas,A,B,G,gran,res,max_d)

% base resolution R, step of hierarchy Hs, depth of hierarchy Hd, top N
R = res(1); Hs = res(2); Hd = res(3); N = res(4);
disp(sprintf('----- Base Res %d, Step %d, Depth %d -----',R,Hs,Hd));
alpha = A{1}; beta = B{1}; gamma = G{1};
[fvec, Aprm] = match_param(fvec,atlas,alpha,beta,gamma,gran,N,max_d);
fvec = fvec(:,:,1); Aprm = Aprm(1,:); % remove later on
best_angl = Aprm;
for i=1:Hd
    disp(sprintf('----- Res %d -----',R+Hs*i));
    alpha = A{i+1}; beta = B{i+1}; gamma = G{i+1};
    [fvec, Aprm] = match_param(fvec,atlas,alpha,beta,gamma,gran,1,max_d);
    best_angl(i+1,:) = Aprm;
end
best_fvec = fvec;

return;


function allFactors = BuildOCRNetwork (images, imageModel, pairwiseModel, tripletList)
% This function constructs the Markov network for one word by putting
% together the full list of different types of factors.
%
% Input:
%   images: A struct array of the images for each character in the word.
%   imageModel: The provided image model.
%   pairwiseModel: The provided pairwise factor model.
%   tripletList: The provided triplet factor list.
%
% Output:
%   allFactors: An array of factor structs that constitutes the full Markov
%     network.
%
% NOTE:
% The default implementation of each ConstructFactors function returns an
% empty list, so as you implement each of those in succession, more and
% more factors will be added to the resulting network.
%
% You can control which factors are added after you've implemented all of
% the factor functions in the following way:
%
% Pairwise factors: pass in an empty array (ie, []) for the pairwiseModel,
% and no pairwise factors will be added.
%
% Triplet factors: pass in an empty array for the tripletList, and no
% triplet factors will be added.
%
% Similarity factors: if you set imageModel.ignoreSimilarity = 1, then the
% similarity factors will not be added (nb: this is a bit of a kludge.
% Apologies.)
%
% Copyright (C) Daphne Koller, Stanford University, 2012

if (~exist('pairwiseModel', 'var'))
    pairwiseModel = [];
end
if (~exist('tripletList', 'var'))
    tripletList = [];
end

singletonFactors = ComputeSingletonFactors(images, imageModel);

if (~isempty(pairwiseModel))
    %%%%%%%%%%%%%%%%%%%%%%%%%%%
    % FOR STUDENTS:
    % Once you've tested out ComputeEqualPairwiseFactors, as discussed in
    % the assignment handout, you should comment out that line and
    % uncomment the following line to use the "real" pairwise factor
    % implementation (which you must provide.
    %%%%%%%%%%%%%%%%%%%%%%%%%%%

   %pairwiseFactors = ComputeEqualPairwiseFactors(images, imageModel.K);
    pairwiseFactors = ComputePairwiseFactors(images, pairwiseModel, imageModel.K);
else
    pairwiseFactors = [];
end

if (~isempty(tripletList))
    tripletFactors = ComputeTripletFactors(images, tripletList, imageModel.K);
else
    tripletFactors = [];
end

% Your code here:

if (isfield(imageModel, 'ignoreSimilarity') && imageModel.ignoreSimilarity)
    simFactors = [];
else
    allSimFactors = ComputeAllSimilarityFactors(images, imageModel.K);
    %%%%%%%%%%%%%%%%%%%%%%%%%%%
    % FOR STUDENTS:
    % In the provided implementation of ChooseTopSimilarityFactors, all
    % factors are returned, so no selection occurs. Once you try to run
    % inference using all factors (as described in the assignment handout),
    % you should implement the function so that the network contains only
    % the selected factors.
    %%%%%%%%%%%%%%%%%%%%%%%%%%%
    simFactors = ChooseTopSimilarityFactors(allSimFactors, 2);
end

% This mess is necessary since Octave crashes if you try to vertcat onto a
% scalar, and it is possible that tripletFactors is scalar (for length 3
% words).
cellFactors{1} = singletonFactors;
cellFactors{2} = pairwiseFactors;
cellFactors{3} = tripletFactors;
cellFactors{4} = simFactors;
factorsPresent = ~[isempty(singletonFactors) isempty(pairwiseFactors) isempty(tripletFactors) isempty(simFactors)];

allFactors = vertcat(cellFactors{factorsPresent});
end


function F = coeffs2chebfun2v(X, Y)
%COEFFS2DISKFUNV   Convert componentwise matrices of bivariate Chebyshev
%   coefficients to a chebfun2v.
%
%   F = coeffs2chebfun2v(X, Y) returns a chebfun2v object F that has a
%   bivariate Chebyshev matrices of coefficients X, Y, for each component.
%
% See also CHEBFUN2V/COEFFS2.

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

U = chebfun2(X, 'coeffs');
V = chebfun2(Y, 'coeffs');
F = chebfun2v(U, V);
end


% SOM Toolbox
% Version 2.0beta, May 30 2002
%
% Copyright 1997-2000 by
% Esa Alhoniemi, Johan Himberg, Juha Parhankangas and Juha Vesanto
% Contributed files may contain copyrights of their own.
%
% SOM Toolbox comes with ABSOLUTELY NO WARRANTY; for details
% see License.txt in the program package. This is free software,
% and you are welcome to redistribute it under certain conditions;
% see License.txt for details.
%
%
% Demos
%
%            som_demo1   SOM Toolbox demo 1: basic properties
%            som_demo2   SOM Toolbox demo 2: basic usage
%            som_demo3   SOM Toolbox demo 3: visualization
%            som_demo4   SOM Toolbox demo 4: data analysis
%
% Creation of structs
%
%              som_set   create & set (& check) values to structs
%             som_info   print out information on a given struct
%      som_data_struct   create & initialize a data struct
%       som_map_struct   create & initialize a map struct
%     som_topol_struct   create & initialize a topology struct
%     som_train_struct   create & initialize a train struct
%         som_clstruct   create a cluster struct
%            som_clset   set properties in a cluster struct
%            som_clget   get stuff from a cluster struct
%
% Struct conversion and file I/O
%
%           som_vs1to2   converts a version 1.0 struct to version 2.0 struct
%           som_vs2to1   converts a version 2.0 struct to version 1.0 struct
%        som_read_data   reads a (SOM_PAK format) ASCII data file
%       som_write_data   writes a SOM_PAK format codebook file
%        som_write_cod   writes a SOM_PAK format data file
%         som_read_cod   reads a SOM_PAK format codebook file
%
% Data preprocessing
%
%        som_normalize   normalize data set
%      som_denormalize   denormalize data set
%    som_norm_variable   (de)normalize one variable
%           preprocess   preprocessing GUI
%
% Initialization and training functions
%
%             som_make   create, initialize and train a SOM
%         som_randinit   random initialization algorithm
%          som_lininit   linear initialization algorithm
%         som_seqtrain   sequential training algorithm
%       som_batchtrain   batch training algorithm
%              som_gui   SOM initialization and training GUI
%       som_prototrain   a simple version of sequential training: easy to modify
%
% Clustering algorithms
%
%           som_kmeans   k-means algorithm (was earlier kmeans)
%      kmeans_clusters   try and evaluate several k-means clusterings
%           neural_gas   neural gas vector quantization algorithm
%          som_linkage   hierarchical clustering algorithms
%        som_cllinkage   hierarchical clustering of SOM
%       som_dmatminima   local minima from distance (or U-) matrix
%     som_dmatclusters   distance (or U-) matrix based clustering
%         som_clspread   spreads clusters to unassinged map units
%           som_cldist   calculate distances between clusters
%         som_gapindex   gap validity index of clustering
%             db_index   Davies-Bouldin validity index of clustering
%
% Supervised/classification algorithms
%
%       som_supervised   supervised SOM algorithm
%                 lvq1   LVQ1 algorithm
%                 lvq3   LVQ3 algorithm
%                  knn   k-NN classification algorithm
%              knn_old   k-NN classification algorithm (old version)
%
% SOM error measures
%
%          som_quality   quantization and topographic error of SOM
%       som_distortion   SOM distortion measure
%      som_distortion3   elements of the SOM distortion measure
%
% Auxiliary functions
%
%             som_bmus   calculates BMUs for given data vectors
%         som_eucdist2   pairwise squared euclidian distances between vectors
%            som_mdist   calculates pairwise distances between vectors
%           som_divide   extract subsets of data based on map
%            som_label   give labels to map units
%        som_label2num   rcodes string data labels to interger class labels
%        som_autolabel   automatically labels the SOM based on given data
%      som_unit_coords   calculates coordinates in output space for map units
%       som_unit_dists   distances in output space between map units
%      som_unit_neighs   units in 1-neighborhood for each map unit
%     som_neighborhood   calculates neighborhood matrix for the given map
%        som_neighbors   calculates different kinds of neighborhoods
%           som_neighf   calculates neighborhood function values
%           som_select   GUI for manual selection of map units
%     som_estimate_gmm   create Gaussian mixture model on top of SOM
%  som_probability_gmm   evaluate Gaussian mixture model
%          som_ind2sub   from linear index to subscript index
%          som_sub2ind   from subscript index to linear index
%          som_ind2cod   from linear index to SOM_PAK linear index
%          som_cod2ind   from SOM_linear index to SOM_PAK linear index
%             nanstats   mean, std and median which ignore NaNs
%   som_modify_dataset   add, remove, or extract samples and components
%         som_fillnans   fill NaNs in a data set based on given SOM
%            som_stats   statistics of a data set
%           som_drmake   calculate descriptive rules for a cluster
%           som_dreval   evaluate descriptive rules for a cluster
%         som_drsignif   rule significance measures
%
% Using SOM_PAK from Matlab
%
%      som_sompaktrain   uses SOM_PAK to train a map
%           sompak_gui   GUI for using SOM_PAK from Matlab
%          sompak_init   call SOM_PAK's initialization programs from Matlab
%      sompak_init_gui   GUI for using SOM_PAK's initialization from Matlab
%    sompak_rb_control   an auxiliary function for sompak_*_gui functions.
%        sompak_sammon   call SOM_PAK's Sammon program from Matlab
%    sompak_sammon_gui   GUI for using SOM_PAK's Sammon program from Matlab
%         sompak_train   call SOM_PAK's training program from Matlab
%     sompak_train_gui   GUI for using SOM_PAK's training program from Matlab
%
% Visualization
%
%             som_show   basic visualization
%         som_show_add   add labels, hits and trajectories
%       som_show_clear   remove extra markers
%       som_recolorbar   refresh/reconfigure colorbars
%         som_show_gui   GUI for using som_show and associated functions
%             som_grid   visualization of SOM grid
%           som_cplane   component planes and U-matrices
%         som_barplane   bar chart visualization of map
%         som_pieplane   pie chart visualization of map
%        som_plotplane   plot chart visualization of map
%       som_trajectory   launches a GUI for presenting comet-trajectories
%       som_dendrogram   visualization of clustering tree
%       som_plotmatrix   pairwise scatter plots and histograms
%    som_order_cplanes   order and visualize the component planes
%           som_clplot   plots of clusters (based on cluster struct)
% som_projections_plot   projections plots (see som_projections)
%       som_stats_plot   plots of statistics (see som_stats)
%
% Auxiliary functions for visualization
%
%                 hits   calculates hits, or sum of values for each map unit
%             som_hits   calculates the response of data on the map
%             som_umat   calculates the U-matrix
%                  cca   curvilinear component analysis projection algorithm
%              pcaproj   principal component projection algorithm
%               sammon   Sammon's mapping projection algorithm
%       som_connection   connection matrix for map
%       som_vis_coords   map unit coordinates used in visualizations
%        som_colorcode   create color coding for map/2D data
%         som_bmucolor   colors of the BMUs from a given map color code
%        som_normcolor   simulate indexed colormap
%     som_clustercolor   color coding which depends on clustering structure
%      som_kmeanscolor   color coding according to k-means clustering
%     som_kmeanscolor2   a newer version of the som_kmeanscolor function
%       som_fuzzycolor   a fuzzy color coding
%         som_coloring   a SOM-based color coding
%      som_projections   calculates a default set of projections
%
% Report generation stuff
%
%     som_table_struct   creates a table struct
%     som_table_modify   modifies a table struct
%      som_table_print   print a table in various formats
%            rep_utils   various utilities for printing report elements
%      som_stats_table   a table of data set statistics
%     som_stats_report   report on data set statistics
%
% Low level routines used by visualization functions
%
%            vis_patch   defines hexagonal and rectangular patches
%    vis_som_show_data   returns UserData and subplot handles stored by som_show.m
%        vis_valuetype   used for type checks
%         vis_footnote   adds a movable text to the current figure
%          vis_trajgui   the actual GUI started by som_trajectory.m
% vis_PlaneAxisProperties   set axis properties in visualization functions
% vis_footnoteButtonDownFcn   callback function for vis_footnote.m
%     vis_planeGetArgs   converts topol struct to lattice, msize argument pair
%    vis_show_gui_comp   internal function used by som_show_gui.m
%    vis_show_gui_tool   internal function used by som_show_gui.m
%
% Other
%
%           somtoolbox   this file
%            iris.data   IRIS data set (used in demos)
%          License.txt   GNU General Public License
%        Copyright.txt   Copyright notice