function [mcs, mcs_time] = calculateMCS(model_struct, n_mcs, max_len_mcs, varargin)
% Calculate Minimal Cut Sets (MCSs) using the warm-start strategy available
% in CPLEX, namely cplex.populate(), with or without selecting a given
% knockout, among all the reactions included in the model or a given subset
% of them. Tobalina et al., 2016 (Bioinformatics); von Kamp and Klamt, 2014
% (PLoS Computational Biology).
%
% USAGE:
%
%    [mcs, mcs_time] = populateMCS(model_struct, n_mcs, max_len_mcs, options)
%
% INPUTS:
%    model_struct:    Metabolic model structure (COBRA Toolbox format).
%    n_mcs:           Number of MCSs to calculate.
%    max_len_mcs:     Number of reactions in the largest MCS to be calculated.
%
% OPTIONAL INPUT:
% OPTIONAL INPUTS:
%    KO:                 Selected reaction knockout. (default = [])
%    rxn_set:            Cell array containing the set of reactions among which
%                        the MCSs are wanted to be calculated.
%                        taken from model.rxns
%                        (default = [], all reactions)
%    target_b:           Desired activity level of the metabolic task to be
%                        disrupted. (default = 1e-3)
%    forceLength:        1 if the constraint limiting the length of the
%                        MCSs is to be active (recommended for
%                        enumerating low order MCSs), 0 otherwise
%                        (default = 1)
%    timelimit:          Time limit for the calculation of MCSs each time
%                        the solver is called. (default = 1e75)
%    numWorkers:         Integer: is the maximun number of workers used
%                        by Cplex and GPR2models. 0 = automatic,
%                        1 = sequential, > 1 = parallel. (default = 0)
%    printLevel:         Integer. 1 if the process is wanted to be shown
%                        on the screen, 0 otherwise. (default = 1)
%
% OUTPUTS:
%    mcs:         Cell array containing the calculated MCSs.
%    mcs_time:    Calculation times of the different processes in
%                 the algorithm.
%
% EXAMPLE:
%    %With optional values
%    [mcs, mcs_time] = calculateMCS(modelR204, 100, 10, ...
%                                    'KO', 'r1651', ...
%                                    'rxn_set', {'r1652'; 'r1653'; 'r1654'}, ...
%                                    'timelimit', 300, ...
%                                    'target_b', 1e-4, ...
%                                    'forceLength', 0, ...
%                                    'printLevel', 0, ...
%
%    %Without optional values
%    [mcs, mcs_time] = calculateMCS(model, 100, 10)
%
% .. Authors:
%       - Inigo Apaolaza, 30/01/2017, University of Navarra, TECNUN School of Engineering.
%       - Luis V. Valcarcel, 19/11/2017, University of Navarra, TECNUN School of Engineering.
%       - Francisco J. Planes, 20/11/2017, University of Navarra, TECNUN School of Engineering.
% .. Revisions:
%       - Inigo Apaolaza, 10/04/2018, University of Navarra, TECNUN School of Engineering.
%       - Luis V. Valcarcel, 17/04/2018, University of Navarra, TECNUN School of Engineering.
%       - Luis V. Valcarcel, 30/06/2021, University of Navarra, TECNUN School of Engineering.
%       - Luis V. Valcarcel, 16/09/2022, University of Navarra, TECNUN School of Engineering.

% Check the installation of cplex
global SOLVERS;
global CBT_MILP_SOLVER;
if SOLVERS.ibm_cplex.installed && SOLVERS.ibm_cplex.working
    if ~strcmp(CBT_MILP_SOLVER,'ibm_cplex')
        warning('calculateMCS will use IBM CPLEX although it is not selected for MILP')
    end
else
    error('This version calculateMCS only works with IBM CPLEX. Newer versions will include more solvers included in COBRA Toolbox')
end

time_aa = tic;
% Set Parameters
p = inputParser;
% check required arguments
addRequired(p, 'model_struct');
addRequired(p, 'n_mcs', @isnumeric);
addRequired(p, 'max_len_mcs', @isnumeric);
% Add optional name-value pair argument
addParameter(p, 'KO', [], @(x)ischar(x)||isempty(x));
addParameter(p, 'rxn_set', [], @(x)iscell(x)||isempty(x));
addParameter(p, 'target_b', 1e-3, @(x)isnumeric(x)&&isscalar(x));
addParameter(p, 'timelimit', 1e75, @(x)isnumeric(x)&&isscalar(x));
addParameter(p, 'forceLength', true, @(x)islogical(x)||(isnumeric(x)&&isscalar(x)));
addParameter(p, 'numWorkers', 0, @(x)isnumeric(x)&&isscalar(x));
addParameter(p, 'printLevel', 1, @(x)isnumeric(x)&&isscalar(x));
% extract variables from parser
parse(p, model_struct, n_mcs, max_len_mcs, varargin{:});
model_struct = p.Results.model_struct;
n_mcs = p.Results.n_mcs;
max_len_mcs = p.Results.max_len_mcs;
KO = p.Results.KO;
rxn_set = p.Results.rxn_set;
target_b = p.Results.target_b;
timelimit = p.Results.timelimit;
forceLength = p.Results.forceLength;
numWorkers = p.Results.numWorkers;
printLevel = p.Results.printLevel;

integrality_tolerance = 1e-5;
M = 1e3;    % Big Value
alpha = 1;  % used to relate the lower bound of v variables with z variables
c = 1e-3;   % used to activate w variable
b = 1e-3;   % used to activate KnockOut constraint
phi = 1000; % b/c;

% Build the K Matrix
[~, n_ini_rxns] = size(model_struct.S);
K = speye(n_ini_rxns);

% Splitting
S = [model_struct.S -model_struct.S(:, model_struct.lb<0)];
K = [K K(:, model_struct.lb<0)];
K_ind = model_struct.rxns;
n_K_ind = length(K_ind);
[n_mets, n_rxns] = size(S);
nbio = find(model_struct.c);
t = zeros(n_rxns, 1);
t(nbio) = 1;

% Permit only KOs in rxn_set
if ~isempty(rxn_set)
    if ~isempty(KO)
        rxn_set = [rxn_set; {KO}];
    end
    rxn_set = unique(rxn_set);
    tmp_set = cellfun(@ismember, model_struct.rxns, repmat({rxn_set}, n_ini_rxns, 1), 'UniformOutput', false);
    pos_set = find(cell2mat(tmp_set));
    K = K(pos_set, :);
    K_ind = model_struct.rxns(pos_set);
    n_K_ind = length(K_ind);
end

if isempty(KO)
% ENUMERATE MCSs
% Define variables
    var.u = 1:n_mets;
    var.vp = var.u(end)+1:var.u(end)+n_K_ind;
    var.w = var.vp(end)+1:var.vp(end)+1;
    var.zp = var.w(end)+1:var.w(end)+n_K_ind;
    var.zw = var.zp(end)+1:var.zp(end)+1;
    n_vars = var.zw(end);
    var_group.v = [var.vp var.w];
    var_group.z = [var.zp var.zw];

% Define constraints
    cons.Ndual = 1:size(S, 2);
    cons.forceBioCons = cons.Ndual(end)+1:cons.Ndual(end)+1;
    cons.forceLength = cons.forceBioCons(end)+1:cons.forceBioCons(end)+1;
    n_cons = cons.forceLength(end);

% Cplex - A matrix
    A = sparse(zeros(n_cons, n_vars));
    A(cons.Ndual, var.u) = S';
    A(cons.Ndual, var.vp) = K';
    A(cons.Ndual, var.w) = -t;
    A(cons.forceBioCons, var.w) = -target_b;
    if forceLength == 1
        A(cons.forceLength, var.zp) = 1;
    end

% Cplex - rhs and lhs vectors
    rhs = zeros(n_cons, 1);
    rhs(cons.Ndual, 1) = inf;
    rhs(cons.forceBioCons) = -c;
    if forceLength == 1
        rhs(cons.forceLength) = 1;
    end
    lhs = zeros(n_cons, 1);
    lhs(cons.Ndual, 1) = 0;
    lhs(cons.forceBioCons) = -1000;
    if forceLength == 1
        lhs(cons.forceLength) = 1;
    end

% Cplex - ub and lb vectors
    ub(var.u, 1) = inf;
    ub(var.vp) = inf;
    ub(var.w) = inf;
    ub(var.zp) = 1;
    ub(var.zw) = 1;
    lb(var.u, 1) = -inf;
    lb(var.vp) = 0;
    lb(var.w) = 0;
    lb(var.zp) = 0;
    lb(var.zw) = 0;

% Cplex - obj vector
    obj(var.u, 1) = 0;
    obj(var.vp) = 0;
    obj(var.w) = 0;
    obj(var.zp) = 1;
    obj(var.zw) = 0;

% Cplex - ctype vector
    ctype(var.u) = 'C';
    ctype(var.vp) = 'C';
    ctype(var.w) = 'C';
    ctype(var.zp) = 'B';
    ctype(var.zw) = 'B';

% Cplex - sense of the optimization
    sense = 'minimize';

% Cplex - Introduce all data in a Cplex structure
    cplex = Cplex('MCS');
    Model = struct();
    [Model.A, Model.rhs, Model.lhs, Model.ub, Model.lb, Model.obj, Model.ctype, Model.sense] = deal(A, rhs, lhs, ub, lb, obj, ctype, sense);
    cplex.Model = Model;

% Cplex Indicators
    % z = 1  -->  v >= alpha
    for ivar = 1:length(var_group.z)
        a = zeros(n_vars, 1);
        a(var_group.v(ivar)) = 1;
        cplex.addIndicators(var_group.z(ivar), 0, a, 'G', alpha);
    end

% Cplex Indicators
    % z = 0  -->  v <= 0
    for ivar = 1:length(var_group.z)
        a = zeros(n_vars, 1);
        a(var_group.v(ivar)) = 1;
        cplex.addIndicators(var_group.z(ivar), 1, a, 'L', 0);
    end

% Cplex Parameters
    sP = struct();
    [sP.mip.tolerances.integrality, sP.mip.strategy.heuristicfreq, sP.mip.strategy.rinsheur] = deal(integrality_tolerance, 1000, 50);
    [sP.emphasis.mip, sP.output.clonelog, sP.timelimit, sP.threads] = deal(4, -1, max(10, timelimit), numWorkers);
    [sP.preprocessing.aggregator, sP.preprocessing.boundstrength, ...
        sP.preprocessing.coeffreduce, sP.preprocessing.dependency, ...
        sP.preprocessing.dual, sP.preprocessing.fill,...
        sP.preprocessing.linear, sP.preprocessing.numpass, ...
        sP.preprocessing.presolve, sP.preprocessing.reduce,..., ...
        sP.preprocessing.relax, sP.preprocessing.symmetry] = deal(50, 1, 2, 1, 1, 50, 1, 50, 1, 3, 1, 1);
    cplex = setCplexParam(cplex, sP);

    if printLevel == 0
        cplex.DisplayFunc = [];
    end

% Calculation of MCSs
    mcs_time{1, 1} = '------ TIMING ------';
    mcs_time{1, 2} = '--- MCSs ---';
    i = 0;
    k = 0;
    n_time = size(mcs_time, 1);
    mcs_time{n_time+1, 1} = 'Preparation';
    mcs_time{n_time+1, 2} = toc(time_aa);
    mcs = [];
    largest_mcs = 0;
    while largest_mcs <= max_len_mcs && k < n_mcs && cplex.Model.rhs(cons.forceLength) <= max_len_mcs
        ini_mcs_time = toc(time_aa);
        cplex.Param.mip.limits.populate.Cur = 40;
        cplex.Param.mip.pool.relgap.Cur = 0.1;
        cplex.populate();
        n_pool = size(cplex.Solution.pool.solution, 1);
        if n_pool ~= 0
            solution = cplex.Solution.pool.solution;
            for j = 1:n_pool
                k = k+1;
                mcs{k, 1} = K_ind((solution(j).x(var.zp))>0.9);
                n_cons = n_cons+1;
                sol = solution(j).x(var.zp)>0.9;
                cplex.Model.A(n_cons, var.zp) = sparse(double(sol));
                cplex.Model.rhs(n_cons) = sum(sol)-1;
                cplex.Model.lhs(n_cons) = 0;
            end
            i = i+1;
            mcsi_time = toc(time_aa)-ini_mcs_time;
            n_time = size(mcs_time, 1);
            mcs_time{n_time+1, 1} = ['POPULATE_ORDER_' num2str(cplex.Model.rhs(cons.forceLength))];
            mcs_time{n_time+1, 2} = mcsi_time;
        else
            mcsi_time = toc(time_aa)-ini_mcs_time;
            n_time = size(mcs_time, 1);
            mcs_time{n_time+1, 1} = ['POPULATE_ORDER_' num2str(cplex.Model.rhs(cons.forceLength)) 'NF'];
            mcs_time{n_time+1, 2} = mcsi_time;
            if forceLength == 1
                cplex.Model.rhs(cons.forceLength) = cplex.Model.rhs(cons.forceLength)+1;
                cplex.Model.lhs(cons.forceLength) = cplex.Model.lhs(cons.forceLength)+1;
            else
                n_time = size(mcs_time, 1);
                mcs_time{n_time+1, 1} = 'TOTAL MCSs';
                mcs_time{n_time+1, 2} = toc(time_aa);
                return;
            end
        end
        try save('tmp.mat', 'mcs', 'mcs_time'); end
        try largest_mcs = max(cellfun(@length, mcs)); end
    end
else
% CALCULATE MCSs WITH A GIVEN KNOCKOUT
% Select the row(s) in K_ind related to the KO under study
    tmp = repmat({KO}, n_K_ind, 1);
    dp = cellfun(@isequal, K_ind, tmp);

% Define variables
    var.u = 1:n_mets;
    var.vp = var.u(end)+1:var.u(end)+n_K_ind;
    var.w = var.vp(end)+1:var.vp(end)+1;
    var.zp = var.w(end)+1:var.w(end)+n_K_ind;
    var.zw = var.zp(end)+1:var.zp(end)+1;
    var.epsp = var.zw(end)+1:var.zw(end)+n_K_ind;
    var.epsw = var.epsp(end)+1:var.epsp(end)+1;
    var.delp = var.epsw(end)+1:var.epsw(end)+n_K_ind;
    var.delw = var.delp(end)+1:var.delp(end)+1;
    var.x = var.delw(end)+1:var.delw(end)+n_rxns+1;
    n_vars = var.x(end);
    var_group.v = [var.vp var.w];
    var_group.z = [var.zp var.zw];
    var_group.eps = [var.epsp var.epsw];
    var_group.del = [var.delp var.delw];

% Define constraints
    cons.Ndual = 1:size(S, 2);
    cons.forceBioCons = cons.Ndual(end)+1:cons.Ndual(end)+1;
    cons.forceKO = cons.forceBioCons(end)+1:cons.forceBioCons(end)+1;
    cons.linearComb = cons.forceKO(end)+1:cons.forceKO(end)+size(S, 1)+size(K, 1)+size(t, 2);
    cons.forceLength = cons.linearComb(end)+1:cons.linearComb(end)+1;
    n_cons = cons.forceLength(end);

% Cplex - A matrix
    A = sparse(zeros(n_cons, n_vars));
    A(cons.Ndual, var.u) = S';
    A(cons.Ndual, var.vp) = K';
    A(cons.Ndual, var.w) = -t;
    A(cons.forceBioCons, var.w) = -target_b;
    A(cons.forceKO, var.vp) = dp';
    A(cons.linearComb, var.x) = [S sparse(zeros(n_mets, 1)); K sparse(zeros(n_K_ind, 1)); -t' target_b];
    A(cons.linearComb, [var.epsp var.epsw]) = [sparse(zeros(n_mets, length(var.vp)+length(var.w))); -speye(length(var.vp)+length(var.w))];
    A(cons.linearComb, [var.delp var.delw]) = -[sparse(zeros(n_mets, length(var.vp)+length(var.w))); -speye(length(var.vp)+length(var.w))];
    if forceLength == 1
        A(cons.forceLength, var.zp) = 1;
    end

% Cplex - rhs and lhs vectors
    rhs = zeros(n_cons, 1);
    rhs(cons.Ndual, 1) = inf;
    rhs(cons.forceBioCons) = -c;
    rhs(cons.forceKO) = 10000;
    rhs(cons.linearComb) = [sparse(zeros(n_mets, 1)); dp; zeros(size(t, 2), 1)];
    if forceLength == 1
        rhs(cons.forceLength) = 1;
    end
    lhs = zeros(n_cons, 1);
    lhs(cons.Ndual, 1) = 0;
    lhs(cons.forceBioCons) = -1000;
    lhs(cons.forceKO) = b*10;
    lhs(cons.linearComb) = [sparse(zeros(n_mets, 1)); dp; zeros(size(t, 2), 1)];
    if forceLength == 1
        lhs(cons.forceLength) = 1;
    end

% Cplex - ub and lb vectors
    ub(var.u, 1) = inf;
    ub(var.vp) = inf;
    ub(var.w) = inf;
    ub(var.zp) = 1;
    ub(var.zw) = 1;
    ub(var.epsp) = inf;
    ub(var.epsw) = 0;
    ub(var.delp) = inf;
    ub(var.delw) = 0;
    ub(var.x) = inf;
    lb(var.u, 1) = -inf;
    lb(var.vp) = 0;
    lb(var.w) = 0;
    lb(var.zp) = 0;
    lb(var.zw) = 0;
    lb(var.epsp) = 0;
    lb(var.epsw) = 0;
    lb(var.delp) = 0;
    lb(var.delw) = 0;
    lb(var.x) = 0;
    lb(var.x(end)) = phi;

% Cplex - obj vector
    obj(var.u, 1) = 0;
    obj(var.vp) = 0;
    obj(var.w) = 0;
    obj(var.zp) = 1;
    obj(var.zw) = 0;
    obj(var.epsp) = 0;
    obj(var.epsw) = 0;
    obj(var.delp) = 0;
    obj(var.delw) = 0;
    obj(var.x) = 0;

% Cplex - ctype vector
    ctype(var.u) = 'C';
    ctype(var.vp) = 'C';
    ctype(var.w) = 'C';
    ctype(var.zp) = 'B';
    ctype(var.zw) = 'B';
    ctype(var.epsp) = 'C';
    ctype(var.epsw) = 'C';
    ctype(var.delp) = 'C';
    ctype(var.delw) = 'C';
    ctype(var.x) = 'C';

% Cplex - sense of the optimization
    sense = 'minimize';

% Cplex - Introduce all data in a Cplex structure
    cplex = Cplex('MCS');
    Model = struct();
    [Model.A, Model.rhs, Model.lhs, Model.ub, Model.lb, Model.obj, Model.ctype, Model.sense] = deal(A, rhs, lhs, ub, lb, obj, ctype, sense);
    cplex.Model = Model;

% Cplex Indicators
    % z = 1  -->  v >= alpha
    for ivar = 1:length(var_group.z)
        a = zeros(var.x(end), 1);
        a(var_group.v(ivar)) = 1;
        cplex.addIndicators(var_group.z(ivar), 0, a, 'G', alpha);
    end

% Cplex Indicators
    % z = 0  -->  v <= 0
    for ivar = 1:length(var_group.z)
        a = zeros(var.x(end), 1);
        a(var_group.v(ivar)) = 1;
        cplex.addIndicators(var_group.z(ivar), 1, a, 'L', 0);
    end

% Cplex Indicators
    % z = 1  -->  epsilon <= 0
    for ivar = 1:length(var_group.z)
        a = zeros(var.x(end), 1);
        a(var_group.eps(ivar)) = 1;
        cplex.addIndicators(var_group.z(ivar), 0, a, 'L', 0);
    end

% Cplex Indicators
    % z = 0  -->  epsilon <= M
    for ivar = 1:length(var_group.z)
        a = zeros(var.x(end), 1);
        a(var_group.eps(ivar)) = 1;
        cplex.addIndicators(var_group.z(ivar), 1, a, 'L', M);
    end

% Cplex Parameters
    sP = struct();
    [sP.mip.tolerances.integrality, sP.mip.strategy.heuristicfreq, sP.mip.strategy.rinsheur] = deal(integrality_tolerance, 1000, 50);
    [sP.emphasis.mip, sP.output.clonelog, sP.timelimit, sP.threads] = deal(4, -1, max(10, timelimit), numWorkers);
    [sP.preprocessing.aggregator, sP.preprocessing.boundstrength, ...
        sP.preprocessing.coeffreduce, sP.preprocessing.dependency, ...
        sP.preprocessing.dual, sP.preprocessing.fill,...
        sP.preprocessing.linear, sP.preprocessing.numpass, ...
        sP.preprocessing.presolve, sP.preprocessing.reduce,..., ...
        sP.preprocessing.relax, sP.preprocessing.symmetry] = deal(50, 1, 2, 1, 1, 50, 1, 50, 1, 3, 1, 1);
    cplex = setCplexParam(cplex, sP);
    if printLevel == 0
        cplex.DisplayFunc = [];
    end

% Calculation of MCSs
    mcs_time{1, 1} = '------ TIMING ------';
    mcs_time{1, 2} = '--- MCSs ---';
    i = 0;
    k = 0;
    n_time = size(mcs_time, 1);
    mcs_time{n_time+1, 1} = 'Preparation';
    mcs_time{n_time+1, 2} = toc(time_aa);
    mcs = [];
    largest_mcs = 0;
    while largest_mcs <= max_len_mcs && k < n_mcs && cplex.Model.rhs(cons.forceLength) <= max_len_mcs
        ini_mcs_time = toc(time_aa);
        cplex.Param.mip.limits.populate.Cur = 40;
        cplex.Param.mip.pool.relgap.Cur = 0.1;
        cplex.populate();
        n_pool = size(cplex.Solution.pool.solution, 1);
        if n_pool ~= 0
            solution = cplex.Solution.pool.solution;
            for j = 1:n_pool
                k = k+1;
                mcs{k, 1} = K_ind((solution(j).x(var.zp))>0.9);
                n_cons = n_cons+1;
                sol = solution(j).x(var.zp)>0.9;
                cplex.Model.A(n_cons, var.zp) = sparse(double(sol));
                cplex.Model.rhs(n_cons) = sum(sol)-1;
                cplex.Model.lhs(n_cons) = 0;
            end
            i = i+1;
            mcsi_time = toc(time_aa)-ini_mcs_time;
            n_time = size(mcs_time, 1);
            mcs_time{n_time+1, 1} = ['POPULATE_ORDER_' num2str(cplex.Model.rhs(cons.forceLength))];
            mcs_time{n_time+1, 2} = mcsi_time;
        else
            mcsi_time = toc(time_aa)-ini_mcs_time;
            n_time = size(mcs_time, 1);
            mcs_time{n_time+1, 1} = ['POPULATE_ORDER_' num2str(cplex.Model.rhs(cons.forceLength)) 'NF'];
            mcs_time{n_time+1, 2} = mcsi_time;
            if forceLength == 1
                cplex.Model.rhs(cons.forceLength) = cplex.Model.rhs(cons.forceLength)+1;
                cplex.Model.lhs(cons.forceLength) = cplex.Model.lhs(cons.forceLength)+1;
            else
                n_time = size(mcs_time, 1);
                mcs_time{n_time+1, 1} = 'TOTAL MCSs';
                mcs_time{n_time+1, 2} = toc(time_aa);
                return;
            end
        end
        try save('tmp.mat', 'mcs', 'mcs_time'); end
        try largest_mcs = max(cellfun(@length, mcs)); end
    end
end
n_time = size(mcs_time, 1);
mcs_time{n_time+1, 1} = 'TOTAL MCSs';
mcs_time{n_time+1, 2} = toc(time_aa);
end


function [x,y,ind] = spm_MDP_VB_ERP(MDP,FACTOR,T)
% auxiliary routine for hierarchical electrophysiological responses
% FORMAT [x,y] = spm_MDP_VB_ERP(MDP,FACTOR,T)
%
% MDP    - structure (see spm_MDP_VB)
% FACTOR - hidden factors (at high and low level) to plot
% T      - flag to return cell of expectations (at time T; usually 1)
%
% x      - simulated ERPs (high-level) (full lines)
% y      - simulated ERPs (low level)  (dotted lines)
% ind    - indices or bins at the end of each (synchronised) epoch
%
% This routine combines first and second level hidden expectations by
% synchronising them; such that first level updating is followed by an
% epoch of second level updating - during which updating is suspended
% (and expectations are held constant). The ensuing spike rates can be
% regarded as showing delay period activity. In this routine, simulated
% local field potentials are band pass filtered spike rates (between eight
% and 32 Hz).
%
% Graphics are provided for first and second levels, in terms of simulated
% spike rates (posterior expectations), which are then combined to show
% simulated local field potentials for both levels (superimposed).
%
% At the lower level, only expectations about hidden states in the first
% epoch are returned (because the number of epochs can differ from trial
% to trial).
%
% see also: spm_MDP_VB_LFP (for single level belief updating)
%__________________________________________________________________________
% Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_MDP_VB_ERP.m 7656 2019-08-26 14:00:36Z karl $

% defaults: assume the first factor is of interest
%==========================================================================
try, f1 = FACTOR(1); catch, f1 = 1; end
try, f2 = FACTOR(2); catch, f2 = 1; end

% and T = 1
%--------------------------------------------------------------------------
if nargin < 3, T = 1; end

for m = 1:numel(MDP)

    % dimensions
    %----------------------------------------------------------------------
    xn  = MDP(m).xn{f1};      % neuronal responses
    Nb  = size(xn,1);         % number of time bins per epochs
    Nx  = size(xn,2);         % number of states
    Ne  = size(xn,3);         % number of epochs

    % expected hidden states
    %======================================================================
    x     = cell(Ne,Nx);
    y     = cell(Ne);
    for k = 1:Ne
        for j = 1:Nx
            x{k,j} = xn(:,j,T,k);
        end
        if isfield(MDP,'mdp')
            y{k}   = spm_MDP_VB_ERP(MDP(m).mdp(k),f2,1);
        else
            y{k}   = [];
        end
    end

    if nargin > 2, return, end

    % synchronise responses
    %----------------------------------------------------------------------
    u   = {};
    v   = {};
    uu  = spm_cat(x(1,:));
    for k = 1:Ne

        % low-level
        %------------------------------------------------------------------
        v{end + 1,1} = spm_cat(y{k});
        if k > 1
            u{end + 1,1} = ones(size(v{end,:},1),1)*u{end,1}(end,:);
        else
            u{end + 1,1} = ones(size(v{end,:},1),1)*uu(1,:);
        end

        % time bin indices
        %------------------------------------------------------------------
        ind(k) = size(u{end},1);

        % high-level
        %------------------------------------------------------------------
        u{end + 1,1} = spm_cat(x(k,:));
        v{end + 1,1} = ones(size(u{end,:},1),1)*v{end,1}(end,:);

        % time bin indices
        %------------------------------------------------------------------
        ind(k) = ind(k) + size(u{end},1);

    end

    % accumulate over trials
    %----------------------------------------------------------------------
    U{m,1} = u;
    V{m,1} = v;

end

% time bin (seconds)
%--------------------------------------------------------------------------
u  = spm_cat(U);
v  = spm_cat(V);
dt = 1/64;
t  = (1:size(u,1))*dt;

% bandpass filter between 8 and 32 Hz
%--------------------------------------------------------------------------
c  = 1/32;
x  = log(u + c);
y  = log(v + c);
x  = spm_conv(x,2,0) - spm_conv(x,16,0);
y  = spm_conv(y,2,0) - spm_conv(y,16,0);

if nargout > 2, return, end

% simulated firing rates and the local field potentials
%==========================================================================

% higher-level unit responses
%--------------------------------------------------------------------------
factor = MDP(1).label.factor{f1};
name   = MDP(1).label.name{f1};

subplot(4,1,1), image(t,1:(size(u,2)),64*(1 - u')), ylabel('Unit')
title(sprintf('Unit reponses : %s',factor),'FontSize',16)
if numel(name) < 16
    grid on, set(gca,'YTick',1:numel(name))
    set(gca,'YTickLabel',name)
end

% lower-level unit responses
%--------------------------------------------------------------------------
factor = MDP(1).MDP(1).label.factor{f2};
name   = MDP(1).MDP(1).label.name{f2};

subplot(4,1,2), image(t,1:(size(v,2)),64*(1 - v')), ylabel('Unit')
title(sprintf('Unit reponses : %s',factor),'FontSize',16)
if numel(factor) < 16
    grid on, set(gca,'YTick',1:numel(name))
    set(gca,'YTickLabel',name)
end

% event related responses at both levels
%--------------------------------------------------------------------------
subplot(4,1,3), plot(t,x',t,y','-.')
title('Local field potentials','FontSize',16)
ylabel('Depolarisation'),spm_axis tight
grid on, xlabel('time (seconds)')


function [sr_img] = superresolve_ebsr(slidingWindows, magFactor)
%
% LMSSR_GENERATESRUSINGEBSR Performs a Single Image Super-Resolution (SISR) approach according to "Example-based Learning for Single-Image
%                      Super-resolution". Supports GS/Y and RGB.
%    [sr_img] = LMSSR_GENERATESRUSINGEBSR(lr_img, upscaling)
%
% Parameters: lr_img          -   LR RGB or GS/Y image to be superresolved (height,width,dye)
%             upscaling       -   Scalar value containing the upscaling factor for both Y- and X-coordinates
%
% Important note: YUV images are also supported but yield bad results!
%
% Author: Michel Bätz (LMS)
%
% See also: lmsSR_framework
%

lr_img    = slidingWindows.referenceFrame;
upscaling = magFactor;

%Low = lr_ref_img;
%Low(:,:,2) = Low(:,:,1);
%Low(:,:,3) = Low(:,:,1);
%Low = im2uint8(Low);

if size(lr_img,3) == 3, % Color image case
    lr_img = lmsSR_convertYUV2RGB(lr_img);
end

sr_img = SuperresCode(lr_img,upscaling); % EXTERNAL CODE
sr_img = uint8(sr_img); % Required as output contains uint8 values

sr_img = im2double(sr_img);

if size(lr_img,3) == 3, % Color image case
    sr_img = lmsSR_convertRGB2YUV(sr_img);
end


%kvaddm 'Add Image1 to Image2 Pixel by Pixel'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros vaddm.pane file
%
% Parameters:
% InputFile: i1 'Input Image #1', required: 'first input image'
% OutputFile: o 'Output Image ', required: 'resulting output image'
% InputFile: i2 'Input Image #2', optional: 'second input image'
% Integer: c 'Constant Image', default: 0: 'add constant'
%
% Example: o = kvaddm({i1, i2}, {'i1','';'o','';'i2','';'c',0})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% vaddm - Add Image1 to Image2 Pixel by Pixel
%
%  DESCRIPTION
% .I vaddm
% Adds the first input image to the second input image (result = image1 + image2), with an optional operation gating image. The second input image can be entered as a constant, optionally.
% If the sum of two pixel values is more than the maximum value of the image data type, the resultant pixel value will be set to this maximum value.
%
% The two input images must be of the same size and have the same
% number of data bands.  The input
% images may be of the same or different data types.  If the input
% images are of different data types, then all input images will be
% upcast to the highest input image data type.  The output
% image data type will be the same as that of the highest data type
% of the input images.
%
%
%
%  EXAMPLES
% vaddm -i1 input.image1 -i2 input.image2 -o output.image
%
% This subtracts input.image2 from input.image1 stores the results in output.image.
%
%  "SEE ALSO"
% vcast1(1)
%
%  RESTRICTIONS
% .I vaddm
% can be defined for all data types supported by Khoros, but at the moment it has been implemented just for the bit and unsigned char types.
% The structuring elements are subsets of the 3x3 matrix and the origin is always at the center of this matrix.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993-1997 Junior Barrera, Roberto Lotufo.  All rights reserved.
%

function varargout = kvaddm(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kvaddm(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i1', '__input';'o', '__output';'i2', '__input';'c', 0};
maxval={0,0,1,255};
minval={0,0,1,0};
istoggle=[0,0,1,1];
was_set=istoggle * 0;
paramtype={'InputFile','OutputFile','InputFile','Integer'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'vaddm"  '],Inputs,narglist);


%FBA
%
% Author: Jonathan Karr, jkarr@stanford.edu
% Affiliation: Covert Lab, Department of Bioengineering, Stanford University
% Last Updated: 3/24/2011
classdef FBA
    %printing
    methods (Static)
        function run(sim, fileName)
            import edu.stanford.covert.cell.sim.analysis.FBA;
            import edu.stanford.covert.cell.sim.util.PlotUtil;
            import edu.stanford.covert.cell.sim.util.PrintUtil;

            %excel file
            [content, colLabels, indentation] = FBA.printNetworkReduction(sim);
            if nargin == 1
                PrintUtil.printToStdIO(content, colLabels, struct('indentation', indentation));
            else
                PrintUtil.printToFile(content, colLabels, [fileName '.xls'], 'NetworkReduction', struct('indentation', indentation));
            end

            %plots
            if nargin == 1
                FBA.plotNetworkReduction(sim, PlotUtil.newAxesHandle());
            else
                [axesHandle, figHandle] = PlotUtil.newAxesHandle();

                cla(axesHandle);
                FBA.plotNetworkReduction(sim, axesHandle);
                saveas(figHandle, [fileName '-NetworkReduction.pdf']);

                close(figHandle);
            end
        end

        function [content, colLabels, indentation] = printNetworkReduction(sim)
            p = sim.process('Metabolism');

            [subCmpRemoved, rxnRemoved] = p.formulateFBA([], [], true);

            content = cell(0, 6);
            colLabels = {'ID', 'Compartment', 'Reason', 'Iteration-1', 'Iteration-2'};
            reasons = {
                'Disconnected'
                'Substrate cannot be balanced: only appears in single reaction'
                'Substrate cannot be balanced: move in same direction in all reactions in which it appears'
                'Reaction has zero flux in all solutions of S*v = 0: reaction has no non-zero component in null space of S';
                };

            subIDs = p.substrateWholeCellModelIDs;
            cmpIDs = p.compartment.wholeCellModelIDs(p.substrateMetaboliteCompartmentIndexs(1, :));
            content = [content;{
                0 'Substrates' [] [] [] []}];
            for i = 1:size(subCmpRemoved, 1)
                if subCmpRemoved(i, 1) == 0
                    continue;
                end
                [sIdx, cIdx] = ind2sub([size(p.reactionStoichiometryMatrix, 1) size(p.reactionStoichiometryMatrix, 3)], i);
                content = [content;{
                    1 subIDs{sIdx} cmpIDs{cIdx} reasons{subCmpRemoved(i, 3)} subCmpRemoved(i, 1) subCmpRemoved(i, 2)}]; %#ok<AGROW>
            end

            rxnIDs = p.reactionWholeCellModelIDs;
            content = [content;{
                0 'Reactions' [] [] [] []}];
            for i = 1:size(rxnRemoved, 1)
                if rxnRemoved(i, 3) == 0
                    continue;
                end
                content = [content;{
                    1 rxnIDs{i} [] reasons{rxnRemoved(i, 3)} rxnRemoved(i, 1) rxnRemoved(i, 2)}]; %#ok<AGROW>
            end

            %format output
            indentation = cell2mat(content(:, 1));
            content = content(:, 2:end);
        end

        function plotNetworkReduction(sim, axesHandle)
            p = sim.process('Metabolism');

            [subCmpRemoved, rxnRemoved] = p.formulateFBA([], [], true);
            subCmpRemoved(subCmpRemoved(:, 1) == 0, 1) = max(subCmpRemoved(:, 1)) + 1;
            rxnRemoved(rxnRemoved(:, 1) == 0, 1) = max(rxnRemoved(:, 1)) + 1;

            levels = sortrows(unique([subCmpRemoved; rxnRemoved], 'rows'), [1 2 3]);

            [~, subCmpIdxs] = sortrows(subCmpRemoved, 1:3);
            [~, rxnIdxs] = sortrows(rxnRemoved, 1:3);

            [~, subCmpLevels] = ismember(subCmpRemoved, levels, 'rows');
            [~, rxnLevels] = ismember(rxnRemoved, levels, 'rows');

            hold on;

            x = [
                0.5
                numel(rxnIdxs)+0.5
                numel(rxnIdxs)+0.5
                0.5
                ];
            y = [
                0.5
                0.5
                numel(subCmpIdxs)+0.5
                numel(subCmpIdxs)+0.5
                ];
            patch(x, y, 1, 'FaceColor', [1 1 1], 'Parent', axesHandle, 'FaceAlpha', 1);
            patch(x, y, 1, 'CDataMapping', 'direct', 'Parent', axesHandle, 'FaceAlpha', 0.25, 'EdgeAlpha', 1);
            for i = 2:size(levels, 1)
                j = find(subCmpLevels(subCmpIdxs) < i, 1, 'last');
                k = find(rxnLevels(rxnIdxs) < i, 1, 'last');
                if isempty(j), j = 0; end;
                if isempty(k), k = 0; end;

                x = [
                    k+0.5
                    numel(rxnIdxs)+0.5
                    numel(rxnIdxs)+0.5
                    k+0.5
                    ];
                y = [
                    j+0.5
                    j+0.5
                    numel(subCmpIdxs)+0.5
                    numel(subCmpIdxs)+0.5
                    ];
                patch(x, y, 1, 'FaceColor', [1 1 1], 'Parent', axesHandle, 'FaceAlpha', 1);
                patch(x, y, i, 'CDataMapping', 'direct', 'Parent', axesHandle, 'FaceAlpha', 0.25, 'EdgeAlpha', 1);
            end

            rxnSMat = reshape(permute(p.reactionStoichiometryMatrix, [2 1 3]), ...
                size(p.reactionStoichiometryMatrix, 2), [])';

            [y, x] = find(...
                ((rxnSMat(subCmpIdxs, rxnIdxs) < 0 & repmat(p.reactionBounds(rxnIdxs, 2)' > 0, numel(subCmpIdxs), 1)) | ...
                (rxnSMat(subCmpIdxs, rxnIdxs) > 0 & repmat(p.reactionBounds(rxnIdxs, 1)' < 0, numel(subCmpIdxs), 1))) & ...
                ~((rxnSMat(subCmpIdxs, rxnIdxs) > 0 & repmat(p.reactionBounds(rxnIdxs, 2)' > 0, numel(subCmpIdxs), 1)) | ...
                (rxnSMat(subCmpIdxs, rxnIdxs) < 0 & repmat(p.reactionBounds(rxnIdxs, 1)' < 0, numel(subCmpIdxs), 1))));
            h1 = plot(axesHandle, x, y, 'r.', 'MarkerSize', 6);

            [y, x] = find(...
                ~((rxnSMat(subCmpIdxs, rxnIdxs) < 0 & repmat(p.reactionBounds(rxnIdxs, 2)' > 0, numel(subCmpIdxs), 1)) | ...
                (rxnSMat(subCmpIdxs, rxnIdxs) > 0 & repmat(p.reactionBounds(rxnIdxs, 1)' < 0, numel(subCmpIdxs), 1))) &  ...
                ((rxnSMat(subCmpIdxs, rxnIdxs) > 0 & repmat(p.reactionBounds(rxnIdxs, 2)' > 0, numel(subCmpIdxs), 1)) | ...
                (rxnSMat(subCmpIdxs, rxnIdxs) < 0 & repmat(p.reactionBounds(rxnIdxs, 1)' < 0, numel(subCmpIdxs), 1))));
            h2 = plot(axesHandle, x, y, 'g.', 'MarkerSize', 6);

            [y, x] = find(...
                ((rxnSMat(subCmpIdxs, rxnIdxs) < 0 & repmat(p.reactionBounds(rxnIdxs, 2)' > 0, numel(subCmpIdxs), 1)) | ...
                (rxnSMat(subCmpIdxs, rxnIdxs) > 0 & repmat(p.reactionBounds(rxnIdxs, 1)' < 0, numel(subCmpIdxs), 1))) &  ...
                ((rxnSMat(subCmpIdxs, rxnIdxs) > 0 & repmat(p.reactionBounds(rxnIdxs, 2)' > 0, numel(subCmpIdxs), 1)) | ...
                (rxnSMat(subCmpIdxs, rxnIdxs) < 0 & repmat(p.reactionBounds(rxnIdxs, 1)' < 0, numel(subCmpIdxs), 1))));
            h3 = plot(axesHandle, x, y, 'b.', 'MarkerSize', 6);

            legend([h1 h2 h3], {'Drained'; 'Produced'; 'Bidirectional'}, 'Location', 'NorthEastOutside');

            colormap(jet);

            xlim([0.5 numel(rxnIdxs)+0.5])
            ylim([0.5 numel(subCmpIdxs)+0.5]);

            box('on');
            xlabel('Reactions', 'FontSize', 12);
            ylabel('Substrates', 'FontSize', 12);
            set(axesHandle, 'YDir', 'reverse');
            set(axesHandle, 'XAxisLocation', 'top');
            axis('square')
        end
    end
end


% adjustlocs() - read neuroscan polar location file (.asc)
%
% Usage:
%   >> chanlocs = adjustlocs( chanlocs );
%   >> chanlocs = adjustlocs( chanlocs, 'key1', val1, 'key2', val2, ...);
%
% Inputs:
%   chanlocs       - EEGLAB channel location data structure. See
%                    help readlocs()
%
% Optional inputs:
%   'center'       - [cell array] one or several electrode names to compute
%                    center location (if several electrodes are provided, the
%                    function use their iso-barycenter). Ex: { 'cz' } or
%                    { 'fz' 'pz' }.
%   'autocenter'   - ['on'|'off']  attempt to automatically detect all symetrical
%                    electrode in the 10-20 system to compute the center.
%                    Default: 'on'.
%   'rotate'       - [cell array] name and planar angle of landmark electrodes
%                    to use as template planar rotation. Ex: { 'c3', 90 }.
%   'autorotate'   - ['on'|'off'] attempt to automatically detect
%                    electrode in the 10-20 system to compute the average
%                    planar rotation. Default 'on'.
%   'scale'        - [cell array] name and phi angle of electrodes along
%                    horizontal central line. Ex: { 'c3' 44 }. Scale uniformly
%                    all direction. Use 'hscale' and 'vscale' for scaling x and
%                    y axis independently.
%   'hscale'       - [cell array] name and phi angle of electrodes along
%                    honrizontal central line. Ex: { 'c3' 44 }.
%   'vscale'       - [cell array] name and phi angle of one electrodes along
%                    central vertical axis. Ex: { 'fz' 44 }.
%   'autoscale'    - ['on'|'off'] automatic scaling with 10-20 system used as
%                    reference. Default is 'on'.
%   'uniform'      - ['on'|'off'] force the scaling to be uniform along the X
%                    and the Y axis. Default is 'on'.
%   'coordinates'  - ['pol'|'sph'|'cart'] use polar coordinates ('pol'), sperical
%                    coordinates ('sph') or cartesian ('cart'). Default is 'sph'.
%                    (Note that using polar and spherical coordinates have the
%                    same effect, except that units are different).
%                    Default is 'sph'.
%
% Outputs:
%   chanlocs       - EEGLAB channel location data structure. See
%                    help readlocs()
%
% Note: operations are performed in the following order, first re-centering
%       then planar rotation and finally sperical re-scaling.
%
% Author: Arnaud Delorme, CNL / Salk Institute, 1 Dec 2003
%
% See also: readlocs()

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

function chanlocs = adjustlocs( chanlocs, varargin)

    if nargin < 1
        help adjustlocs;
        return;
    end;

    % check input parameters
    % ----------------------
    g = finputcheck( varargin, { 'hscale'     'cell'  []   {};
                                 'vscale'     'cell'  []   {};
                                 'scale'      'cell'  []   {};
                                 'center'     'cell'  []   {};
                                 'rotate'     'cell'  []   {};
                                 'autoscale'  'string'  { 'on' 'off' }    'off';
                                 'autocenter' 'string'  { 'on' 'off' }    'on';
                                 'autorotate' 'string'  { 'on' 'off' }    'on';
                                 'uniform'    'string'  { 'on' 'off' }    'on';
                                 'coordinates' 'string'  { 'pol' 'sph' 'cart' } 'sph' });
    if ischar(g), error(g); end;

    names = { chanlocs.labels };

    % auto center
    % -----------
    if strcmpi(g.autocenter, 'on') & isempty(g.center)
        disp('Reading template 10-20 file');
        locs1020 = readlocs('eeglab1020.ced');

        % scan electrodes for horiz pos
        % -----------------------------
        tmpnames      = lower(names);
        tmpnames1020  = lower({ locs1020.labels });
        [tmp indelec] = intersect(tmpnames1020, tmpnames);

        % remove non-symetrical electrodes
        % --------------------------------
        if ~isempty(indelec)
            if find(indelec == 79), indelec(end+1) = 80; end; % for Cz
            ind2remove = [];
            for index = 1:length(indelec)
                if mod(indelec(index),2)
                    if ~ismember(indelec(index)+1, indelec)
                        ind2remove = [ ind2remove index ];
                    end;
                else
                    if ~ismember(indelec(index)-1, indelec)
                        ind2remove = [ ind2remove index ];
                    end;
                end;
            end;
            indelec(ind2remove) = [];
            if find(indelec == 80), indelec(end) = []; end; % for Cz

            g.center = tmpnames1020(indelec);
        end;
        if isempty(g.center)
            disp('No electrodes found for auto-centering')
        else
            disp([ num2str(length(g.center)) ' landmark electrodes found for position auto-centering' ])
        end;
    end;

    % auto rotate
    % -----------
    if strcmpi(g.autorotate, 'on') & isempty(g.rotate)
        if exist('locs1020') ~= 1
            disp('Reading template 10-20 file');
            locs1020 = readlocs('eeglab1020.ced');
        end;

        % scan electrodes for horiz pos
        % -----------------------------
        tmpnames      = lower(names);
        tmpnames1020  = lower({ locs1020.labels });
        tmptheta1020 = { locs1020.theta };
        [tmp indelec] = intersect(tmpnames1020(1:end-1), tmpnames); % do not use cz

        g.rotate(1:2:2*length(indelec))   = tmpnames1020 (indelec);
        g.rotate(2:2:2*length(indelec)+1) = tmptheta1020(indelec);

        if isempty(g.rotate)
            disp('No electrodes found for auto planar rotation')
        else
            disp([ num2str(length(g.rotate)/2) ' landmark electrodes found for auto planar rotation' ])
        end;
    end;

    % auto scale
    % ----------
    if strcmpi(g.autoscale, 'on') & isempty(g.hscale) & isempty(g.vscale)
        if exist('locs1020') ~= 1
            disp('Reading template 10-20 file');
            locs1020 = readlocs('eeglab1020.ced');
        end;

        if strcmpi(g.uniform, 'off')
            % remove all vertical electrodes for horizontal scaling
            % -----------------------------------------------------
            theta  = [ locs1020.theta ];
            indxh  = find(abs(theta) == 90);
            indxv  = union(find(theta == 0) , find(theta == 180));
            locs1020horiz = locs1020(indxh);
            locs1020vert  = locs1020(indxv);

            % scan electrodes for horiz pos
            % -----------------------------
            tmpnames      = lower(names);
            tmpnames1020  = lower({ locs1020horiz.labels });
            tmpradius1020 = { locs1020horiz.radius };
            [tmp indelec] = intersect(tmpnames1020, tmpnames);

            if isempty(indelec)
                disp('No electrodes found for horiz. position spherical re-scaling')
            else
                disp([ num2str(length(indelec)) ' landmark electrodes found for horiz. position spherical re-scaling' ]);
                if strcmpi(g.coordinates, 'cart')
                    g.hscale(2:2:2*length(indelec)+1) = [ locs1020horiz.Y ];
                else
                    g.hscale(2:2:2*length(indelec)+1) = tmpradius1020(indelec);
                end;
            end;

            % scan electrodes for vert. pos
            % -----------------------------
            tmpnames1020  = lower({ locs1020vert.labels });
            tmpradius1020 = { locs1020vert.radius };
            [tmp indelec] = intersect(tmpnames1020, tmpnames);

            if isempty(indelec)
                disp('No electrodes found for vertical position spherical re-scaling')
            else
                disp([ num2str(length(indelec)) ' landmark electrodes found for vertical spherical re-scaling' ]);
                g.vscale(1:2:2*length(indelec))   = tmpnames1020 (indelec);
                if strcmpi(g.coordinates, 'cart')
                    g.vscale(2:2:2*length(indelec)+1) = [ locs1020vert.X ];
                else
                    g.vscale(2:2:2*length(indelec)+1) = tmpradius1020(indelec);
                end;
            end;
        else
            % uniform scaling
            % ---------------
            tmpnames      = lower(names);
            tmpnames1020  = lower({ locs1020.labels });
            tmpradius1020 = { locs1020.radius };
            [tmp indelec] = intersect(tmpnames1020, tmpnames);

            if isempty(indelec)
                disp('No electrodes found for uniform spherical re-scaling')
            else
                disp([ num2str(length(indelec)) ' landmark electrodes found for uniform spherical re-scaling' ]);
                g.scale(1:2:2*length(indelec))   = tmpnames1020 (indelec);
                if strcmpi(g.coordinates, 'cart')
                    tmpabsxyz = mattocell(abs([ locs1020.X ]+j*[ locs1020.Y ]));
                    g.scale(2:2:2*length(indelec)+1) = tmpabsxyz(indelec);
                else
                    g.scale(2:2:2*length(indelec)+1) = tmpradius1020(indelec);
                end;
            end;
        end;
        if strcmpi(g.coordinates, 'sph')
            g.coordinates = 'pol'; % use polar coordinates for scaling
        end;
    end;

    % get X and Y coordinates
    % -----------------------
    if strcmpi(g.coordinates, 'sph') | strcmpi(g.coordinates, 'pol')
        [X Y] = pol2cart( [ chanlocs.theta ]/180*pi, [ chanlocs.radius ]); Z = 1;
        if strcmpi(g.coordinates, 'sph')
            X = X/0.25*46;
            Y = Y/0.25*46;
        end;
    else
        X = [ chanlocs.X ];
        Y = [ chanlocs.Y ];
        Z = [ chanlocs.Z ];
    end;

    % recenter
    % --------
    if ~isempty(g.center)
        for index = 1:length(g.center)
            tmpindex = strmatch( lower(g.center{index}), lower(names), 'exact' );
            if isempty(tmpindex)
                error(['Electrode ''' g.center{index} ''' not found for re-centering']);
            end;
            indexelec(index) = tmpindex;
        end;
        showmsg('Using electrode', 'for re-centering', g.center);
        centerx = mean(X(indexelec));
        centery = mean(Y(indexelec));
        X = X - centerx;
        Y = Y - centery;
    end;

    % planar rotation
    % ---------------
    if ~isempty(g.rotate)
        % find electrodes
        % ---------------
        clear elec;
        for index = 1:2:length(g.rotate)
            tmpindex = strmatch( lower(g.rotate{index}), lower(names), 'exact' );
            if isempty(tmpindex)
                error(['Electrode ''' g.rotate{index} ''' not found for left-right scaling']);
            end;
            elec((index+1)/2) = tmpindex;
        end;
        vals = [ g.rotate{2:2:end} ];

        % compute average scaling factor
        % ------------------------------
        [ allangles tmp ] = cart2pol(X(elec), Y(elec));
        allangles = allangles/pi*180;
        diffangle = allangles - vals;
        %diffangle2 = allangles + vals;
        %if abs(diffangle1) > abs(diffangle2), diffangle = diffangle2;
        %else                                  diffangle = diffangle1;
        %end;
        tmpind    = find(diffangle >  180); diffangle(tmpind) = diffangle(tmpind)-360;
        tmpind    = find(diffangle < -180); diffangle(tmpind) = diffangle(tmpind)+360;
        anglerot  = mean(diffangle);
        tmpcplx = (X+j*Y)*exp(-j*anglerot/180*pi);
        X = real(tmpcplx);
        Y = imag(tmpcplx);
        showmsg('Using electrode', ['for planar rotation (' num2str(anglerot,2) ' degrees)'], g.rotate(1:2:end));
    end;

    % computing scaling factors
    % -------------------------
    if ~isempty(g.scale)
        % find electrodes
        % ---------------
        clear elec;
        for index = 1:2:length(g.scale)
            tmpindex = strmatch( lower(g.scale{index}), lower(names), 'exact' );
            if isempty(tmpindex)
                error(['Electrode ''' g.scale{index} ''' not found for left-right scaling']);
            end;
            elec((index+1)/2) = tmpindex;
        end;
        vals = [ g.scale{2:2:end} ];

        % compute average scaling factor
        % ------------------------------
        nonzero = find(vals > 0);
        hscalefact = mean(abs(Y(elec(nonzero))+j*X(elec(nonzero)))./vals(nonzero)); % *46/0.25; %/44/0.25;
        vscalefact = hscalefact;
        showmsg('Using electrode', ['for uniform spherical re-scaling (x' num2str(1/hscalefact,4) ')'], g.scale(1:2:end));
    else
        if ~isempty(g.hscale)
            % find electrodes
            % ---------------
            clear elec;
            for index = 1:2:length(g.hscale)
                tmpindex = strmatch( lower(g.hscale{index}), lower(names), 'exact' );
                if isempty(tmpindex)
                    error(['Electrode ''' g.hscale{index} ''' not found for left-right scaling']);
                end;
                elec((index+1)/2) = tmpindex;
            end;
            vals = [ g.hscale{2:2:end} ];
            showmsg('Using electrode', [ 'for left-right spherical re-scaling (x' num2str(1/hscalefact,4) ')'], g.hscale(1:2:end));

            % compute average scaling factor
            % ------------------------------
            hscalefact = mean(abs(Y(elec))./vals); % *46/0.25; %/44/0.25;
            if isempty(g.vscale)
                vscalefact =  hscalefact;
            end;
        end;
        if ~isempty(g.vscale)
            % find electrodes
            % ---------------
            clear elec;
            for index = 1:2:length(g.vscale)
                tmpindex = strmatch( lower(g.vscale{index}), lower(names), 'exact' );
                if isempty(tmpindex)
                    error(['Electrode ''' g.vscale{index} ''' not found for rear-front scaling']);
                end;
                elec((index+1)/2) = tmpindex;
            end;
            vals = [ g.vscale{2:2:end} ];
            showmsg('Using electrode', ['for rear-front spherical re-scaling (x' num2str(1/vscalefact,4) ')'], g.vscale(1:2:end));

            % compute average scaling factor
            % ------------------------------
            vscalefact = mean(abs(X(elec))./vals); % *46/0.25; %/44/0.25;
            if isempty(g.vscale)
                hscalefact =  vscalefact;
            end;
        end;
    end;

    % uniform?
    % --------
    if strcmpi(g.uniform, 'on') & ( ~isempty(g.vscale) | ~isempty(g.hscale))
        disp('uniform scaling: averaging left-right and rear-front scaling factor');
        hscalefact = mean([hscalefact vscalefact]);
        vscalefact = hscalefact;
    end;

    % scaling data
    % ------------
    if ~isempty(g.vscale) | ~isempty(g.hscale) | ~isempty(g.scale)
        Y = Y/hscalefact;
        X = X/vscalefact;
        Z = Z/((hscalefact+vscalefact)/2);
    end;

    % updating structure
    % ------------------
    if strcmpi(g.coordinates, 'sph') |  strcmpi(g.coordinates, 'pol')
        [phi,theta] = cart2pol(Y, X);
        phi = phi/pi*180;
        if strcmpi(g.coordinates, 'pol')
            theta = theta/0.25*46;
        end;

        % convert to other types of coordinates
        % -------------------------------------
        labels = names';
        chanlocs = struct('labels', names, 'sph_theta_besa', mattocell(theta), ...
                'sph_phi_besa', mattocell(phi), 'sph_radius', { chanlocs.sph_radius });
        chanlocs = convertlocs( chanlocs, 'sphbesa2all');
    else
        for index = 1:length(chanlocs)
            chanlocs(index).X = X(index);
            chanlocs(index).Y = Y(index);
            chanlocs(index).Z = Z(index);
        end;
        chanlocs = convertlocs(chanlocs, 'cart2all');
    end;

function showmsg(begmsg, endmsg, struct);
    if length(struct) <= 1
        disp([ begmsg ' ''' struct{1} ''' ' endmsg]);
    elseif length(struct) <= 2
        disp([ begmsg ' ''' struct{1} ''' and ''' struct{2}  ''' ' endmsg]);
    elseif length(struct) <= 3
        disp([ begmsg ' ''' struct{1} ''', ''' struct{2} ''' and ''' struct{3}  ''' ' endmsg]);
    else
        disp([ begmsg ' ''' struct{1} ''', ''' struct{2} ''', ''' struct{3}  ''' ... ' endmsg]);
    end;


%% RRT for 3 DOF Mobile Robot
%
%

% Do not change anything in rrt.m,
% rrt_star.m and rrt_star_fn.m
%

%

%% Getting started
% Create *main_3dof_mobile_rrt.m* file. You can create m-file with any other name, that is
% perfectly okay, this will not affect to the solution of a path/motion
% planning problem. All the sources could be found in examples/ directory
% of the distribution.
%

%% Step 1: Choosing the map
% Firstly, we should define what map to use. It is done by defining map
% structure the sample code is goes after.
%
%   map = struct('name', 'bench_june1.mat', 'start_point', [-14.5 -7.5], 'goal_point', [10 -0.65]);
%

%%
%
% * *name field* defines the file name in maps/ directory
% * *start_point* defines the initial point of the problem
% * *goal_point* defines the goal point on the map
%

%% Step 2: Setting maximum number of iterations
%
%   max_iter = 20e3;
%
% * *max_iter* variable defines how much iteration should be done to solve
% the path planning problem.

%% Step 3: Do we have to benchmark
%
%   is_benchmark = false;
%
% * *is_benchmark* enables benchmarking. For more details please read the
% sources of rrt.m, rrt_star.m and rrt_star_fn.m

%% Step 4: Setting random seed
%
%   rand_seed = 40;
%
% * *rand_seed* variable is a random seed for random number generator, it
% is used for sampling nodes. It is usually used for benchmarking. We set
% the same map, however the random seed is different for the same map. You
% can use *now* if you don't care about random seed.
%
%   rand_seed = now;
%

%% Step 5: Choosing the class (model) we want
%
%   variant = 'FNSimple3D';
%
% * *variant* defines from what class we should instantiate the object. In
% other words it defines what model we choose for application of RRT.
%
% *FNSimple3D* is a name of a class which contains all necessary methods
% and fields in order to represent simple 3 DOF Mobile Robot model.

%% Step 6: Rapidly-Exploring Random Tree (RRT)
%
%   rrt(map, max_iter, is_benchmark, rand_seed, variant);
%
% Line above runs RRT with given parameters. In addition, *rrt* function
% returns the class object with a certain solution.

%% Sources of *main_3dof_mobile_rrt.m*
% Press
% <matlab:edit('examples/main_3dof_mobile_rrt.m') here>
% to play with example code.
%
%   % 3 DOF mobile robot example.
%   % by Almaskhan Baimyshev
%   % 08/28/2013
%
%   map = struct('name', 'bench_june1.mat', 'start_point', [-14.5 -7.5], 'goal_point', [10 -0.65]);
%   max_iter = 20e3;
%   is_benchmark = false;
%   rand_seed = 40;
%   variant = 'FNSimple3D';
%   result = rrt(map, max_iter, is_benchmark, rand_seed, variant);
%


function byteStream = mrMeshTcpSerializeParams(params)
%
%    byteStream = mrMeshTcpSerializeParams(params)
%
% Turns the Matlab structure params into a byte-stream suitable for
% TCP transmission using the mrMesh protocol.  That protocol uses pnet.
%
% See also:  mrMesh, pnet_WriteMsg and pnet_ReadMsg
%
% HISTORY
% 2007.04.12 RFD wrote it.

if(~isstruct(params))
    byteStream=params;
    return;
end

byteStream = [];
if(~isempty(params))
    % the termination char is a new-line
    termSeq = uint8(sprintf('\n'));
    eq = uint8(' = ');
    % arrays (non-scalars) are sent in raw for and are enclodes in
    % single-quotes. Scalars are sent in text (sprintf) form.
    sq = uint8('''');
    fnStr = fieldnames(params);

    for(ii=1:length(fnStr))
        data = getfield(params,fnStr{ii});
        sz = size(data);
        data = data(:)';
        fn = uint8(fnStr{ii});
        if(ischar(data))
            fn = uint8(fnStr{ii});
            byteStream = [byteStream fn eq sq data sq termSeq];

        elseif(length(data)>1)
            % *** FIX ME ***
            % The current mrMesh server expects all numeric arrays to be
            % sent as doubles. This sends 8x more data than necessary when
            % sending uint8's! We should fix the server so that it can
            % accept various data types.
            dimStr = sprintf('%d,',sz);
            fn = uint8(sprintf('%s[%s]',fnStr{ii},dimStr(1:end-1)));
            byteStream = [byteStream fn eq sq typecast(double(data),'uint8') sq termSeq];
        else
            fn = uint8(fnStr{ii});
            if(isinteger(data))
                byteStream = [byteStream fn eq uint8(sprintf('%d',data)) termSeq];
            else
                byteStream = [byteStream fn eq uint8(sprintf('%f',data)) termSeq];
            end
        end
    end
end

byteStream(end+1) = 0;

return


function []=panel2fdisp(N,n,T,Units,endo,Ymat,stringdates2,decimaldates2,Fstartlocation,Fendlocation,forecast_estimates,pref)

% preliminary task: gather in a cell the values to be plotted
% initiate the cell
plotdata={};
% because forecasts have to be computed for each unit, loop over units
for ii=1:N
% each cell entry is a matrix of actual and forecast values
% this matrix comprises 4 rows: the first row is actual data, while the three other rows are the estimates (point estimates and confidence bands) for the forecasts
% also, this matrix has a number of rows equal to the dimension of decimaldates2, which comprises the total period sample+forecasts
   % loop over variables
   for jj=1:n
      plotdata{jj,1,ii}=nan(4,size(decimaldates2,1));
      % record actual sample values
      plotdata{jj,1,ii}(1,1:T)=Ymat(:,jj,ii)';
      % copy the last point of the actual sample for the forecast part of the matrix (required to have a clean plot)
      plotdata{jj,1,ii}(:,Fstartlocation-1)=repmat(Ymat(Fstartlocation-1,jj,ii),4,1);
      % record forecast, lower bound
      plotdata{jj,1,ii}(2,Fstartlocation:Fendlocation)=forecast_estimates{jj,1,ii}(1,:);
      % record forecast, point estimate
      plotdata{jj,1,ii}(3,Fstartlocation:Fendlocation)=forecast_estimates{jj,1,ii}(2,:);
      % record forecast, upper bound
      plotdata{jj,1,ii}(4,Fstartlocation:Fendlocation)=forecast_estimates{jj,1,ii}(3,:);
   end
end
% then plot the figure
if pref.plot
forecast=figure('Tag','BEARresults');
set(forecast,'Color',[0.9 0.9 0.9]);
set(forecast,'name','unconditional forecasts');
% initiate the count
count=0;
% loop over units
for ii=1:N
   % loop over endogenous variables
   for jj=1:n
   % increment count
   count=count+1;
   % then plot
   subplot(N,n,count)
   hold on
   Xpatch=[decimaldates2(Fstartlocation-1:Fendlocation,1)' fliplr((decimaldates2(Fstartlocation-1:Fendlocation,1))')];
   Ypatch=[plotdata{jj,1,ii}(2,Fstartlocation-1:Fendlocation) fliplr(plotdata{jj,1,ii}(4,Fstartlocation-1:Fendlocation))];
   Fpatch=patch(Xpatch,Ypatch,[0.7 0.78 1]);
   set(Fpatch,'facealpha',0.6);
   set(Fpatch,'edgecolor','none');
   plot(decimaldates2,plotdata{jj,1,ii}(3,:),'Color',[0.4 0.4 1],'LineWidth',2);
   plot(decimaldates2,plotdata{jj,1,ii}(1,:),'Color',[0 0 0],'LineWidth',2);
   hold off
   set(gca,'XLim',[decimaldates2(1,1) decimaldates2(end,1)],'FontName','Times New Roman');
   set(gca,'XGrid','on');
   set(gca,'YGrid','on');
      % top labels
      if count<=n
      title(endo{count,1},'FontWeight','normal');
      end
      % side labels
      if jj==1
      ylabel(Units{ii,1},'FontWeight','normal');
      end
   end
end
end

% save on Excel
% create the cell that will be saved on excel
forecastcell={};
% build preliminary elements: space between the tables
vertspace=repmat({''},size(stringdates2,1)+3,1);
horzspace=repmat({''},3,6*n);
% loop over units
for ii=1:N
% initiate the cell of results
unitcell={};
   % loop over endogenous variables (horizontal dimension)
   for jj=1:n
   % create a header
   header=[{[Units{ii,1} ': ' endo{jj,1}]} {''} {''} {''} {''};{''} {''} {''} {''} {''};{''} {'actual'} {'lower bound'} {'median'} {'upper bound'}];
   % complete the cell
   endocell=[[header;stringdates2 num2cell((plotdata{jj,1,ii})')] vertspace];
   % concatenate to the previous parts of unitcell
   unitcell=[unitcell endocell];
   end
% concatenate to the previous parts of afcell
forecastcell=[forecastcell;horzspace;unitcell];
end
% trim
forecastcell=forecastcell(4:end,1:end-1);
% write in excel
if pref.results==1
    bear.xlswritegeneral(fullfile(pref.results_path, [pref.results_sub '.xlsx']),forecastcell,'forecasts','B2');
end


function vbrfa2010_testbed_experiment(D, common_nu, common_tau, maxiter)

testbed_experiment_vbrfa(D, common_nu, common_tau, maxiter, 'robustness', ...
                         'independent-t');
testbed_experiment_vbrfa(D, common_nu, common_tau, maxiter, 'robustness', ...
                         'multivariate-t');
testbed_experiment_vbrfa(D, common_nu, common_tau, maxiter, 'robustness', ...
                         'none');


function dat = read_spmeeg_data(filename, varargin)

% read_spmeeg_data() - import SPM5 and SPM8 meeg datasets
%
% Usage:
%   >> header = read_spmeeg_data(filename, varargin);
%
% Inputs:
%   filename - [string] file name
%
% Optional inputs:
%   'begsample'      first sample to read
%   'endsample'      last sample to read
%   'chanindx'  -    list with channel indices to read
%   'header'    - FILEIO structure header
%
% Outputs:
%   dat    - data over the specified range
% _______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
% Vladimir Litvak

if nargin < 1
    help read_spmeeg_data;
    return;
end;

typenames = {'uint8','int16','int32','float32','float64','int8','uint16','uint32'};
typesizes   = [1  2  4  4 8 1 2 4];

header    = ft_getopt(varargin, 'header');
begsample = ft_getopt(varargin, 'begsample');
endsample = ft_getopt(varargin, 'endsample');
chanindx  = ft_getopt(varargin, 'chanindx');

if isempty(header)
    header = read_spmeeg_header([filename(1:(end-3)) 'mat']);
end

if isempty(begsample), begsample = 1; end;
if isempty(endsample), endsample = header.nSamples; end;

datatype = 'float32-le';
scale = [];
if isfield(header, 'orig')
    if isfield(header.orig, 'data') && isnumeric(header.orig.data) ...
            && ~isempty(header.orig.data)
        try
            dat = reshape(header.orig.data(chanindx, :, :), length(chanindx), []);
            dat = dat(:, begsample:endsample);
            return;
        end
    end

    if isfield(header.orig, 'datatype')
        datatype = header.orig.datatype;
    elseif isfield(header.orig.data, 'datatype')
        datatype = header.orig.data.datatype;
    end
    if isfield(header.orig, 'scale')
        if isnumeric(header.orig.scale)
            scale = header.orig.scale;
        else
            scale = header.orig.scale.values;
        end
    elseif isfield(header.orig.data, 'scale')
        scale = header.orig.data.scale;
    end
end

stepsize = typesizes(strmatch(strtok(datatype, '-'), typenames));

filename = [filename(1:(end-3)) 'dat'];

fid = fopen_or_error(filename, 'r');
fseek(fid, stepsize*header.nChans*(begsample-1), 'bof');
[dat, siz] = fread(fid, [header.nChans, (endsample-begsample+1)], strtok(datatype, '-'));
fclose(fid);

if ~isempty(chanindx)
    % select the desired channels
    dat = dat(chanindx,:);
end

if ~isempty(scale) && ~ismember(strtok(datatype, '-'), {'float32', 'float64'})

    % This is a somewhat complicated mechanism to figure out which scaling
    % coefficients go with which data points in a generic way

    trlind = floor(((begsample:endsample)-1)/header.nSamples)+1;

    utrlind = unique(trlind);

    for i = 1:length(utrlind)
        dat(:, trlind == utrlind(i)) = dat(:, trlind == utrlind(i)).* ...
            repmat(squeeze(scale(chanindx,utrlind(i))), 1, sum(trlind == utrlind(i)));
    end

end


classdef FixedInCoordSysSensorSteeringModel < AbstractSensorSteeringModel
    %FixedInCoordSysSensorSteeringModel Summary of this class goes here
    %   Detailed explanation goes here

    properties
        rhtAsc(1,1) double
        dec(1,1) double
        roll(1,1) double
        coordSys AbstractGeometricCoordSystem

        lvdData LvdData
    end

    methods
        function obj = FixedInCoordSysSensorSteeringModel(rhtAsc, dec, roll, coordSys, lvdData)
            obj.rhtAsc = rhtAsc;
            obj.dec = dec;
            obj.roll = roll;
            obj.coordSys = coordSys;

            obj.lvdData = lvdData;
        end

        function [boreDir] = getBoresightVector(obj, time, vehElemSet, ~, inFrame)
            rotMat = obj.coordSys.getCoordSysAtTime(time, vehElemSet, inFrame);

            [x,y,z] = sph2cart(obj.rhtAsc, obj.dec, 1);
            v = [x;y;z];

            boreDir = rotMat * v;
        end

        function rollAngle = getBoresightRollAngle(obj)
            rollAngle = obj.roll;
        end

        function parentDcm = getSensorParentDcmToInertial(obj, time, vehElemSet, dcm, inFrame)
            parentDcm = obj.coordSys.getCoordSysAtTime(time, vehElemSet, inFrame);
        end

        %body to inertial
        function sensorDcm = getSensorDcmToInertial(obj, time, vehElemSet, dcm, inFrame)
%             sensorToParentDcm = eul2rotmARH([obj.rhtAsc,obj.dec,obj.roll],'zyx');
%             parentToInertialDcm = obj.getSensorParentDcmToInertial(time, vehElemSet, dcm, inFrame);
%
%             sensorDcm = parentToInertialDcm * sensorToParentDcm;

            boreDir = obj.getBoresightVector(time, vehElemSet, dcm, inFrame);
            M1 = vrrotvec2mat(vrrotvec([1;0;0], boreDir));
            M2 = rotx(rad2deg(obj.getBoresightRollAngle()));

            sensorDcm = M2 * M1;
        end

        function tf = isVehDependent(obj)
            tf = obj.coordSys.isVehDependent();
        end

        function useTf = openEditDialog(obj)
            output = AppDesignerGUIOutput({false});
            lvd_EditFixedInCoordSysSensorSteeringModelGUI_App(obj, obj.lvdData, output);
            useTf = output.output{1};
        end

        function enum = getEnum(obj)
            enum = SensorSteeringModelEnum.FixedInCoordSys;
        end
    end
end


%io_loadspec_data.m
%Jamie Near, McGill University 2014.
%
% USAGE:
% [out,out_w]=io_loadspec_data(filename,sw,Larmor,subspecs,te,tr);
%
% DESCRIPTION:
% Reads in philips MRS data (.data and .list files) using code adapted from
% PhilipsRead_data.m, provided as part of the Gannet software package by
% Richard Edden (gabamrs.blogspot.com).
%
% op_loadspec_data outputs the data in structure format, with fields
% corresponding to time scale, fids, frequency scale, spectra, and header
% fields containing information about the acquisition.  The resulting
% matlab structure can be operated on by the other functions in this MRS
% toolbox.  NOTE:  Since the Gannet code is geared towards edited GABA MRS
% data, this code may not be general enough to handle all types of MRS data.
% Suggestions are most welcome.
%
% INPUTS:
% filename   = filename of Philips .data file to be loaded.
% sw         = spectral width (Hz)
% Larmor     = Larmor frequency (Hz/ppm, ie.  127 for 3T)
% subspecs   = number of subspectra in the data (from spectral editing, ISIS, etc.)
% te         = echo time (ms).  Optional, default is [].
% tr         = repetition time (ms).  Optional, default is [].
%
% OUTPUTS:
% out        = Input water suppressed dataset in FID-A structure format.
% out_w      = Input water reference dataset in FID-A structure format.

function [out,out_w]=io_loadspec_data(filename,sw,Larmor,subspecs,te,tr);

if nargin<6
    if nargin<5
        te=[];
    end
    tr=[];
end

%read in the data using the philipsDataLoad.m (adapted from PhilipsRead_data.m)
[FullData,WaterData]=philipsDataLoad(filename);

%As far as I can tell, the data that comes out of the philipsDataLoad
%function is normally a N x Navgs matrix.  The coils have already been
%combined. The Navgs dimension contains all the subspectra, so we will
%split them now.  Note, that in the data-list format that I have seen, the
%edit-OFF subspectra appear in elements [1 2 5 6 9 10 13 14...] and the
%edit-ON subspectra appear in the elements [3 4 7 8 11 12 15 16...].  Other sequences
%may result in a different subspecs order, but for now we will separate the
%subspectra in this way.
%If the data has multiple subspectra
if subspecs>1
    %First make an vector that holds the indices of the ON subspectra:
    totalAvgs=size(FullData,2);
    OFFindices=[1:2:totalAvgs]-mod([0:(totalAvgs/2)-1],2);
    ONindices=[2:2:totalAvgs]+mod([1:totalAvgs/2],2);
    %Now split the subspectra out of the "averages" dimension:
    data(:,:,1)=FullData(:,OFFindices);
    data(:,:,2)=FullData(:,ONindices);
else
    data=FullData;
end

fids=squeeze(data);
fids_w=squeeze(WaterData)';

sz=size(fids);
sz_w=size(fids_w);

%Find the magnetic field strength:
Bo=Larmor/42.577;

%Find the number of averages:
Naverages=size(fids,2)*size(fids,3);
Naverages_w=size(fids_w,2)*size(fids_w,3);

%In Philips data/list format, coil channels have already been combined:
Ncoils=1;
Ncoils_w=1;

%Now create a record of the dimensions of the data array.
dims.t=1;
dims.coils=0;
dims.averages=2;
if subspecs>1
    dims.subSpecs=3;
else
    dims.subSpecs=0;
end

dims_w.t=1;
dims_w.coils=0;
dims_w.averages=2;
dims_w.subSpecs=0;

specs=fftshift(ifft(fids,[],dims.t),dims.t);
specs_w=fftshift(ifft(fids_w,[],dims_w.t),dims_w.t);

%Now get relevant scan parameters:*****************************

%Get Spectral width and Dwell Time
spectralwidth=sw;
dwelltime=1/spectralwidth;

%Get TxFrq
txfrq=Larmor*1e6;

%Leave date blank
date='';

%Find the number of averages.  'averages' will specify the current number
%of averages in the dataset as it is processed, which may be subject to
%change.  'rawAverages' will specify the original number of acquired
%averages in the dataset, which is unchangeable.
%FOR WATER SUPPRESSED DATA:
if dims.subSpecs ~=0
    if dims.averages~=0
        averages=sz(dims.averages)*sz(dims.subSpecs);
        rawAverages=averages;
    else
        averages=sz(dims.subSpecs);
        rawAverages=1;
    end
else
    if dims.averages~=0
        averages=sz(dims.averages);
        rawAverages=averages;
    else
        averages=1;
        rawAverages=1;
    end
end

%FOR WATER UNSUPPRESSED DATA:
if dims_w.subSpecs ~=0
    if dims_w.averages~=0
        averages_w=sz(dims_w.averages)*sz(dims_w.subSpecs);
        rawAverages_w=averages_w;
    else
        averages_w=sz(dims_w.subSpecs);
        rawAverages_w=1;
    end
else
    if dims_w.averages~=0
        averages_w=sz(dims_w.averages);
        rawAverages_w=averages_w;
    else
        averages_w=1;
        rawAverages_w=1;
    end
end

%Find the number of subspecs.  'subspecs' will specify the current number
%of subspectra in the dataset as it is processed, which may be subject to
%change.  'rawSubspecs' will specify the original number of acquired
%subspectra in the dataset, which is unchangeable.
%FOR WATER SUPPRESSED DATA:
if dims.subSpecs ~=0
    subspecs=sz(dims.subSpecs);
    rawSubspecs=subspecs;
else
    subspecs=1;
    rawSubspecs=subspecs;
end

%FOR WATER UNSUPPRESSED DATA:
if dims_w.subSpecs ~=0
    subspecs_w=sz(dims.subSpecs);
    rawSubspecs_w=subspecs_w;
else
    subspecs_w=1;
    rawSubspecs_w=subspecs_w;
end

%****************************************************************

%Calculate t and ppm arrays using the calculated parameters:
f=[(-spectralwidth/2)+(spectralwidth/(2*sz(1))):spectralwidth/(sz(1)):(spectralwidth/2)-(spectralwidth/(2*sz(1)))];
ppm=f/(Bo*42.577);
ppm=ppm+4.65;

t=[0:dwelltime:(sz(1)-1)*dwelltime];

%FOR WATER SUPPRESSED DATA
%FILLING IN DATA STRUCTURE
out.fids=fids;
out.specs=specs;
out.sz=sz;
out.ppm=ppm;
out.t=t;
out.spectralwidth=spectralwidth;
out.dwelltime=dwelltime;
out.txfrq=txfrq;
out.date=date;
out.dims=dims;
out.Bo=Bo;
out.averages=averages;
out.rawAverages=rawAverages;
out.subspecs=subspecs;
out.rawSubspecs=rawSubspecs;
out.seq='';
out.te=te;
out.tr=tr;
out.pointsToLeftshift=0;

%FILLING IN THE FLAGS
out.flags.writtentostruct=1;
out.flags.gotparams=1;
out.flags.leftshifted=0;
out.flags.filtered=0;
out.flags.zeropadded=0;
out.flags.freqcorrected=0;
out.flags.phasecorrected=0;
out.flags.averaged=0;
out.flags.addedrcvrs=0;
out.flags.subtracted=0;
out.flags.writtentotext=0;
out.flags.downsampled=0;
if out.dims.subSpecs==0
    out.flags.isFourSteps=0;
else
    out.flags.isFourSteps=(out.sz(out.dims.subSpecs)==4);
end

%FOR WATER UNSUPPRESSED DATA
%FILLING IN DATA STRUCTURE
out_w.fids=fids_w;
out_w.specs=specs_w;
out_w.sz=sz_w;
out_w.ppm=ppm;
out_w.t=t;
out_w.spectralwidth=spectralwidth;
out_w.dwelltime=dwelltime;
out_w.txfrq=txfrq;
out_w.date=date;
out_w.dims=dims_w;
out_w.Bo=Bo;
out_w.averages=averages_w;
out_w.rawAverages=rawAverages_w;
out_w.subspecs=subspecs_w;
out_w.rawSubspecs=rawSubspecs_w;
out_w.seq='';
out_w.te=te;
out_w.tr=tr;
out_w.pointsToLeftshift=0;

%FILLING IN THE FLAGS
out_w.flags.writtentostruct=1;
out_w.flags.gotparams=1;
out_w.flags.leftshifted=0;
out_w.flags.filtered=0;
out_w.flags.zeropadded=0;
out_w.flags.freqcorrected=0;
out_w.flags.phasecorrected=0;
out_w.flags.averaged=0;
out_w.flags.addedrcvrs=0;
out_w.flags.subtracted=0;
out_w.flags.writtentotext=0;
out_w.flags.downsampled=0;
if out_w.dims.subSpecs==0
    out_w.flags.isFourSteps=0;
else
    out_w.flags.isFourSteps=(out.sz(out.dims.subSpecs)==4);
end

%DONE


function y = subsasgn(X,I,Y)
%SUBASGN (overloaded)

try
    if strcmp('()',I.type)
        X_is_spdvar = isa(X,'sdpvar') |  isa(X,'ndsdpvar');
        Y_is_spdvar = isa(Y,'sdpvar') |  isa(Y,'ndsdpvar');
        if islogical(I.subs{1})
            I.subs{1} = double(find(I.subs{1}));
        end
        if any(I.subs{1} <=0)
            error('Index into matrix is negative or zero.');
        end

        if length(I.subs)>2 && X_is_spdvar
            y = subsasgn(ndsdpvar(X),I,Y);
            return
        end

        switch 2*X_is_spdvar+Y_is_spdvar
            case 1
                % This code does not work properly
                % Only work if b is undefined!!?!!
                % generally ugly code...
                y = Y;
                [n_y,m_y] = size(Y);
                y_lmi_variables = y.lmi_variables;
                try
                    X0 = subsasgn(full(X),I,full(reshape(Y.basis(:,1),n_y,m_y)));
                    dim = size(X0);
                    y.basis = reshape(X0,prod(dim),1);
                    X = full(X)*0;
                    for i = 1:length(y_lmi_variables)
                        X0 = subsasgn(X,I,full(reshape(Y.basis(:,i+1),n_y,m_y)));
                        y.basis(:,i+1) = reshape(X0,prod(dim),1);
                    end
                    y.dim = dim;
                    % Reset info about conic terms
                    y.conicinfo = [0 0];
                    y.basis = sparse(y.basis);
                    if length(dim)>2
                        y = ndsdpvar(y);
                    end
                catch
                    error(lasterr)
                end
            case 2
                if ~isempty(Y)
                    if isa(Y,'uint8') || isa(Y,'uint16') || isa(Y,'uint32') || isa(Y,'uint64')
                        Y = sparse(double(Y));
                    elseif isnumeric(Y)
                        Y = sparse(Y);
                    else
                        Y = sparse(double(Y));
                    end
                end
                y = X;

                % Special code for speed
                % elements in vector replaced with constants
                if min(X.dim(1),X.dim(2))==1 & (length(I.subs)==1)
                     y = X;
                     if isempty(Y)
                         y.basis(I.subs{1},:) = [];
                         if X.dim(1) == 1
                             y.dim(2) = y.dim(2) - length(unique(I.subs{1}));
                         else
                             y.dim(1) = y.dim(1) - length(unique(I.subs{1}));
                         end
                     else
                         y.basis(I.subs{1},1) = Y;
                         y.basis(I.subs{1},2:end) = 0;
                     end
                     if prod(y.dim)~=size(y.basis,1)
                         % Ah bugger, the dimension of the object was changed)
                         aux = X.basis(:,1);
                         aux = reshape(aux,X.dim);
                         aux(I.subs{1})=Y;
                         y.dim = size(aux);
                     end
                     y = clean(y);
                     % Reset info about conic terms
                     if isa(y,'sdpvar')
                         y.conicinfo = [0 0];
                     end
                     return;
                end

                x_lmi_variables = X.lmi_variables;
                lmi_variables = [];

                n = y.dim(1);
                m = y.dim(2);
                subX = sparse(subsasgn(full(reshape(X.basis(:,1),n,m)),I,Y));
                y.basis = subX(:);
                if isa(I.subs{1},'char')
                    I.subs{1} = 1:n;
                end
                if length(I.subs)>1
                    if isa(I.subs{2},'char')
                        I.subs{2} = 1:m;
                    end
                end
                if length(I.subs)>1
                    if length(I.subs{1})==1 & length(I.subs{2})~=1
                        I.subs{1} = repmat(I.subs{1},size(I.subs{2},1),size(I.subs{2},2));
                    elseif length(I.subs{2})==1 & length(I.subs{1})~=1
                        I.subs{2} = repmat(I.subs{2},size(I.subs{1},1),size(I.subs{1},2));
                    end
                end

                if length(I.subs)>1
                    ii = kron(I.subs{1}(:),ones(length(I.subs{2}),1));
                    jj = kron(ones(length(I.subs{1}),1),I.subs{2}(:));
                    LinearIndex = sub2ind([n m],ii,jj);
                else
                    LinearIndex = I.subs{1};
                end

                if isempty(Y)
                    X.basis = X.basis(:,2:end);
                    X.basis(LinearIndex,:) = [];
                    y.basis = [y.basis(:,1) X.basis];
                else
                    X.basis(LinearIndex,2:end)=sparse(0);
                    y.basis = [y.basis(:,1) X.basis(:,2:end)];
                end

                y.dim(1) = size(subX,1);
                y.dim(2) = size(subX,2);
                if ~isempty(x_lmi_variables)
                    y = clean(y);
                end
                if isa(y,'sdpvar')
                    % Reset info about conic terms
                    y.conicinfo = [0 0];
                end

            case 3
                z = X;

                x_lmi_variables = X.lmi_variables;
                y_lmi_variables = Y.lmi_variables;

                % In a first run, we fix the constant term and null terms in the X basis
                lmi_variables = [];
                nx = X.dim(1);
                mx = X.dim(2);
                ny = Y.dim(1);
                my = Y.dim(2);

                if (mx==1) & (my == 1) & isempty(setdiff(y_lmi_variables,x_lmi_variables)) & (max(I.subs{1}) < nx) & length(I.subs)==1 & length(unique(I.subs{1}))==length(I.subs{1}) ;
                    % Fast specialized code for Didier
                     y = specialcode(X,Y,I);
                     return
                end

                subX = subsasgn(reshape(X.basis(:,1),nx,mx),I,reshape(Y.basis(:,1),ny,my));
                [newnx, newmx] = size(subX);

                j = 1;

                yz = reshape(1:ny*my,ny,my);
                subX2 = subsasgn(reshape(zeros(nx*mx,1),nx,mx),I,yz);
                subX2 = subX2(:);
                [ix,jx,sx] = find(subX2);
                yz = 0*reshape(Y.basis(:,1),ny,my);
                lmi_variables = zeros(1,length(x_lmi_variables));

                A = reshape(1:nx*mx,nx,mx);
                B = reshape(1:newnx*newmx,newnx,newmx);

                rm = B(1:nx,1:mx);rm = rm(:);
                [iix,jjx,ssx] = find(X.basis(:,2:end));
                z.basis = [subX(:) sparse(rm(iix),jjx,ssx,newnx*newmx,size(X.basis,2)-1)];
                z.basis(ix,2:end) = 0;

                keep = find(any(z.basis(:,2:end),1));
                z.basis = z.basis(:,[1 1+keep]);
                lmi_variables2 = x_lmi_variables(keep);

                z.lmi_variables = lmi_variables2;
                lmi_variables = lmi_variables2;

                all_lmi_variables = union(lmi_variables,y_lmi_variables);
                in_z = ismembcYALMIP(all_lmi_variables,lmi_variables);
                in_y = ismembcYALMIP(all_lmi_variables,y_lmi_variables);
                z_ind = 2;
                y_ind = 2;
                basis = spalloc(size(z.basis,1),1+length(all_lmi_variables),0);
                basis(:,1) = z.basis(:,1);
                nz = size(subX,1);
                mz = size(subX,2);
                template = full(0*reshape(X.basis(:,1),nx,mx));
                in_yin_z = 2*in_y + in_z;
                if all(in_yin_z<3)
                    case1 = find(in_yin_z==1);
                    if ~isempty(case1)
                        basis(:,case1+1) = z.basis(:,2:1+length(case1));
                        in_yin_z(case1) = 0;
                    end
                end
                    % Let's identify the indices at which we need to intervene
                    case1 = find(in_yin_z==1);
                    checkI = union(find(in_yin_z >= 2), setdiff(case1,case1+1));
                    if size(checkI,1) > size(checkI,2)
                        % Sometimes the in_yin_z vector is vertical (not
                        % always though), so we make sure that checkI, on
                        % which we'll iterate, is horizontal.
                        checkI = checkI';
                    end
                    for i = checkI
                        switch in_yin_z(i)
                            case 1
                                % We look for the end of the block of ones
                                % starting at i
                                iend = i + find([in_yin_z(i+1:end) 0] ~= 1, 1, 'first')-1;
                                basis(:,i+1:iend+1) = z.basis(:,z_ind:z_ind+(iend-i));z_ind = z_ind+(iend-i)+1;
                        case 2
                            temp = sparse(subsasgn(template,I,full(reshape(Y.basis(:,y_ind),ny,my))));
                            basis(:,i+1) = temp(:);
                            y_ind = y_ind+1;
                        case 3
                            Z1 = z.basis(:,z_ind);
                            Z4 = Y.basis(:,y_ind);
                            Z3 = reshape(Z4,ny,my);
                            Z2 = sparse(subsasgn(0*reshape(full(X.basis(:,1)),nx,mx),I,Z3));
                            temp = reshape(Z1,nz,mz)+Z2;
                            basis(:,i+1) = temp(:);
                            z_ind = z_ind+1;
                            y_ind = y_ind+1;
                        otherwise
                    end
                end;
                z.dim(1) = nz;
                z.dim(2) = mz;
                z.basis = basis;
                z.lmi_variables = all_lmi_variables(:)';
                y = z;
                % Reset info about conic terms
                y.conicinfo = [0 0];
            otherwise
        end
    else
        error('Reference type not supported');
    end

catch
    error(lasterr)
end

function y = specialcode(X,Y,I)

y = X;
X_basis = X.basis;
Y_basis = Y.basis;
ind = I.subs{1};ind = ind(:);
yvar_in_xvar = zeros(length(Y.lmi_variables),1);
for i = 1:length(Y.lmi_variables);
    yvar_in_xvar(i) = find(X.lmi_variables==Y.lmi_variables(i));
end
y.basis(ind,:) = 0;
mapper = [1 1+yvar_in_xvar(:)'];mapper = mapper(:);
[i,j,k] = find(y.basis);
[ib,jb,kb] = find(Y_basis);
i = [i(:);ind(ib(:))];
j = [j(:);mapper(jb(:))];
k = [k(:);kb(:)];
y.basis = sparse(i,j,k,size(y.basis,1),size(y.basis,2));
y = clean(y);


function feature_map = extract_features(image, pos, scales, features, gparams, extract_info)

% Sample image patches at given position and scales. Then extract features
% from these patches.
% Requires that cell size and image sample size is set for each feature.

if ~iscell(features)
    error('Wrong input');
end;

num_features = length(features);
num_scales = length(scales);
num_sizes = length(extract_info.img_sample_sizes);

% Extract image patches
img_samples = cell(2,1);
for sz_ind = 1:num_sizes
    img_sample_sz = extract_info.img_sample_sizes{sz_ind};
    img_input_sz = extract_info.img_input_sizes{sz_ind};
    img_samples{sz_ind} = zeros(img_input_sz(1), img_input_sz(2), size(image,3), num_scales, 'uint8');
    for scale_ind = 1:num_scales
        img_samples{sz_ind}(:,:,:,scale_ind) = sample_patch(image, pos, round(img_sample_sz*scales(scale_ind)), img_input_sz, gparams);
    end
end

% Find the number of feature blocks and total dimensionality
num_feature_blocks = 0;
total_dim = 0;
for feat_ind = 1:num_features
    num_feature_blocks = num_feature_blocks + length(features{feat_ind}.fparams.nDim);
    total_dim = total_dim + sum(features{feat_ind}.fparams.nDim);
end

feature_map = cell(1, 1, num_feature_blocks);

% Extract feature maps for each feature in the list
ind = 1;
for feat_ind = 1:num_features
    feat = features{feat_ind};
    gparams.cell_size = feat.fparams.cell_size;

    % get the image patch index
    img_sample_ind = cellfun(@(sz) isequal(feat.img_sample_sz, sz), extract_info.img_sample_sizes);

    % do feature computation
    if feat.is_cell
        num_blocks = length(feat.fparams.nDim);
        feature_map(ind:ind+num_blocks-1) = feat.getFeature(img_samples{img_sample_ind}, feat.fparams, gparams);
    else
        num_blocks = 1;
        feature_map{ind} = feat.getFeature(img_samples{img_sample_ind}, feat.fparams, gparams);
    end

    ind = ind + num_blocks;
end

% Do feature normalization
if ~isempty(gparams.normalize_power) && gparams.normalize_power > 0
    if gparams.normalize_power == 2
        feature_map = cellfun(@(x) bsxfun(@times, x, ...
            sqrt((size(x,1)*size(x,2))^gparams.normalize_size * size(x,3)^gparams.normalize_dim ./ ...
            (sum(reshape(x, [], 1, 1, size(x,4)).^2, 1) + eps))), ...
            feature_map, 'uniformoutput', false);
    else
        feature_map = cellfun(@(x) bsxfun(@times, x, ...
            ((size(x,1)*size(x,2))^gparams.normalize_size * size(x,3)^gparams.normalize_dim ./ ...
            (sum(abs(reshape(x, [], 1, 1, size(x,4))).^gparams.normalize_power, 1) + eps)).^(1/gparams.normalize_power)), ...
            feature_map, 'uniformoutput', false);
    end
end
if gparams.square_root_normalization
    feature_map = cellfun(@(x) sign(x) .* sqrt(abs(x)), feature_map, 'uniformoutput', false);
end
end


fid = fopen('pairs.txt');
CC = fscanf(fid,'%d %d');
n_set = CC(1);n_num=CC(2);

same_pair = cell(n_set*n_num,2);
diff_pair = cell(n_set*n_num,2);
lfw_label = zeros(n_set*n_num * 2,2);

for i=1:n_set
    for j = 1 : n_num
        CC = textscan(fid, '%s %d %d\n');
        p = CC{1};id1=CC{2};id2=CC{3};
        same_pair((i-1)*n_num + j,1) = {sprintf('%s/%s/%s_%04d.jpg',pwd,p{1},p{1},id1)};
        same_pair((i-1)*n_num + j,2) = {sprintf('%s/%s/%s_%04d.jpg',pwd,p{1},p{1},id2)};
        if exist('list','var')
            lfw_label((i-1)*n_num + j,1) = find(strcmp(list, sprintf('%s_%04d.jpg',p{1},id1)));
            lfw_label((i-1)*n_num + j,2) = find(strcmp(list, sprintf('%s_%04d.jpg',p{1},id2)));
        end;
    end;
    for j = 1 : n_num
         CC = textscan(fid, '%s %d %s %d\n');
         p1 = CC{1};id1=CC{2};p2=CC{3};id2=CC{4};
        diff_pair((i-1)*n_num + j,1) = {sprintf('%s/%s/%s_%04d.jpg',pwd,p1{1},p1{1},id1)};
        diff_pair((i-1)*n_num + j,2) = {sprintf('%s/%s/%s_%04d.jpg',pwd,p2{1},p2{1},id2)};
        if exist('list','var')
            lfw_label(n_set*n_num + (i-1)*n_num + j,1) = find(strcmp(list, sprintf('%s_%04d.jpg',p1{1},id1)));
            lfw_label(n_set*n_num + (i-1)*n_num + j,2) = find(strcmp(list, sprintf('%s_%04d.jpg',p2{1},id2)));
        end;
    end;
end;
fclose(fid);

if exist('feature','var')
    AllFeature1 = feature(:,lfw_label(:,1));
    AllFeature2 = feature(:,lfw_label(:,2));
end;