function saveas(this,filename,format)
% Save GIfTI object in external file format
% FORMAT saveas(this,filename,format)
% this      - GIfTI object
% filename  - name of file to be created [Default: 'untitled.vtk']
% format    - optional argument to specify encoding format, among
%             VTK (.vtk,.vtp), Collada (.dae), IDTF (.idtf), Wavefront OBJ
%             (.obj), JavaScript (.js), JSON (.json), FreeSurfer
%             (.surf,.curv), MZ3 (.mz3) [Default: VTK]
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Guillaume Flandin
% $Id: saveas.m 7676 2019-10-22 10:19:29Z guillaume $

% Check filename and file format
%--------------------------------------------------------------------------
ext = '.vtk';
if nargin == 1
    filename = ['untitled' ext];
else
    if nargin == 3 && strcmpi(format,'js')
        ext = '.js';
    end
    if nargin == 3 && strcmpi(format,'json')
        ext = '.json';
    end
    if nargin == 3 && strcmpi(format,'collada')
        ext = '.dae';
    end
    if nargin == 3 && strcmpi(format,'idtf')
        ext = '.idtf';
    end
    if nargin == 3 && strncmpi(format,'vtk',3)
        format = lower(format(5:end));
        ext = '.vtk';
    end
    if nargin == 3 && strcmpi(format,'obj')
        ext = '.obj';
    end
    if nargin == 3 && strcmpi(format,'ply')
        ext = '.ply';
    end
    if nargin == 3 && strcmpi(format,'curv')
        ext = '.curv';
    end
    if nargin == 3 && strcmpi(format,'surf')
        ext = '.surf';
    end
    if nargin == 3 && strcmpi(format,'mz3')
        ext = '.mz3';
    end
    [p,f,e] = fileparts(filename);
    if strcmpi(e,'.gii')
        warning('Use save instead of saveas.');
        save(this,filename);
        return;
    end
    if ~ismember(lower(e),{ext})
        warning('Changing file extension from %s to %s.',e,ext);
        e = ext;
    end
    filename = fullfile(p,[f e]);
end

% Write file
%--------------------------------------------------------------------------
s = struct(this);

switch ext
    case {'.js','.json'}
        save_js(s,filename);
    case '.dae'
        save_dae(s,filename);
    case '.idtf'
        save_idtf(s,filename);
    case {'.vtk','.vtp'}
        if nargin < 3, format = 'legacy-ascii'; end
        mvtk_write(s,filename,format);
    case '.obj'
        save_obj(s,filename);
    case '.ply'
        save_ply(s,filename);
    case {'.curv','.surf'}
        write_freesurfer_file(s,filename,format);
    case '.mz3'
        mz3_write(s,filename,true);
    otherwise
        error('Unknown file format.');
end

%==========================================================================
% function save_js(s,filename)
%==========================================================================
function save_js(s,filename)

% Vertices & faces
%--------------------------------------------------------------------------
trace = struct(...
    'type','mesh3d',...
    'x',s.vertices(:,1),...
    'y',s.vertices(:,2),...
    'z',s.vertices(:,3),...
    'i',s.faces(:,1)-1,...
    'j',s.faces(:,2)-1,...
    'k',s.faces(:,3)-1);
if isfield(s,'cdata') && ~isempty(s.cdata)
    if size(s.cdata,2) == 1
        trace.intensity = s.cdata(:,1);
    elseif size(s.cdata,2) == 3
        trace.vertexcolor = cell(1,size(trace.x,1));
        for i=1:numel(trace.vertexcolor)
            trace.vertexcolor{i} = sprintf('rgb(%d,%d,%d)',floor(s.cdata(i,:)*255));
        end
    end
end
data = {trace};

%-Save as JS variable or JSON file
%--------------------------------------------------------------------------
if filename(end) == 's' % JS
    if exist('jsonencode','builtin')
        data = jsonencode(data);
    else
        data = spm_jsonwrite(data);
    end
    fid = fopen(filename,'wt');
    if fid == -1
        error('Unable to write file %s: permission denied.',filename);
    end
    fprintf(fid,'/*\n * JavaScript file saved by %s\n */\n\n','SPM'); % spm('Version')
    fprintf(fid,'/*\n  <!DOCTYPE html><meta charset="utf-8"/>\n');
    fprintf(fid,'  \n','https://cdn.plot.ly/plotly-latest.min.js');
    fprintf(fid,'  \n');
    fprintf(fid,'

\n','plotly',650,800);
    fprintf(fid,'  \n');
    fprintf(fid,'  \n','plotly');
    fprintf(fid,'  \n*/\n');
    fclose(fid);
else % JSON
    if exist('jsonencode','builtin')
        fid = fopen(filename,'wt');
        if fid == -1
            error('Unable to write file %s: permission denied.',filename);
        end
        fprintf(fid,'%s',jsonencode(struct('data',{data},'layout',struct())));
        fclose(fid);
    else
        spm_jsonwrite(filename,struct('data',{data},'layout',struct()),struct('indent',' '));
    end
end

%==========================================================================
% function save_dae(s,filename)
%==========================================================================
function save_dae(s,filename)

o = @(x) blanks(x*3);

% Split the mesh into connected components
%--------------------------------------------------------------------------
try
    C = spm_mesh_label(s.faces);
    d = [];
    for i=1:numel(unique(C))
        d(i).faces    = s.faces(C==i,:);
        u             = unique(d(i).faces);
        d(i).vertices = s.vertices(u,:);
        a             = 1:max(d(i).faces(:));
        a(u)          = 1:size(d(i).vertices,1);
        %a = sparse(1,double(u),1:1:size(d(i).vertices,1));
        d(i).faces    = a(d(i).faces);
    end
    s = d;
end

% Open file for writing
%--------------------------------------------------------------------------
fid = fopen(filename,'wt');
if fid == -1
    error('Unable to write file %s: permission denied.',filename);
end

% Prolog & root of the Collada XML file
%--------------------------------------------------------------------------
fprintf(fid,'<?xml version="1.0"?>\n');
fprintf(fid,'<COLLADA xmlns="http://www.collada.org/2008/03/COLLADASchema" version="1.5.0">\n');

% Assets
%--------------------------------------------------------------------------
fprintf(fid,'%s<asset>\n',o(1));
fprintf(fid,'%s<contributor>\n',o(2));
fprintf(fid,'%s<author_website>%s</author_website>\n',o(3),...
    'http://www.fil.ion.ucl.ac.uk/spm/');
fprintf(fid,'%s<authoring_tool>%s</authoring_tool>\n',o(3),'SPM');
fprintf(fid,'%s</contributor>\n',o(2));
fprintf(fid,'%s<created>%s</created>\n',o(2),datestr(now,'yyyy-mm-ddTHH:MM:SSZ'));
fprintf(fid,'%s<modified>%s</modified>\n',o(2),datestr(now,'yyyy-mm-ddTHH:MM:SSZ'));
fprintf(fid,'%s<unit name="millimeter" meter="0.001"/>\n',o(2));
fprintf(fid,'%s<up_axis>Z_UP</up_axis>\n',o(2));
fprintf(fid,'%s</asset>\n',o(1));

% Image, Materials, Effects
%--------------------------------------------------------------------------
%fprintf(fid,'%s<library_images/>\n',o(1));

fprintf(fid,'%s<library_materials>\n',o(1));
for i=1:numel(s)
    fprintf(fid,'%s<material id="material%d" name="material%d">\n',o(2),i,i);
    fprintf(fid,'%s<instance_effect url="#material%d-effect"/>\n',o(3),i);
    fprintf(fid,'%s</material>\n',o(2));
end
fprintf(fid,'%s</library_materials>\n',o(1));

fprintf(fid,'%s<library_effects>\n',o(1));
for i=1:numel(s)
    fprintf(fid,'%s<effect id="material%d-effect" name="material%d-effect">\n',o(2),i,i);
    fprintf(fid,'%s<profile_COMMON>\n',o(3));
    fprintf(fid,'%s<technique sid="COMMON">\n',o(4));
    fprintf(fid,'%s<lambert>\n',o(5));
    fprintf(fid,'%s<emission>\n',o(6));
    fprintf(fid,'%s<color>%f %f %f %d</color>\n',o(7),[0 0 0 1]);
    fprintf(fid,'%s</emission>\n',o(6));
    fprintf(fid,'%s<ambient>\n',o(6));
    fprintf(fid,'%s<color>%f %f %f %d</color>\n',o(7),[0 0 0 1]);
    fprintf(fid,'%s</ambient>\n',o(6));
    fprintf(fid,'%s<diffuse>\n',o(6));
    fprintf(fid,'%s<color>%f %f %f %d</color>\n',o(7),[0.5 0.5 0.5 1]);
    fprintf(fid,'%s</diffuse>\n',o(6));
    fprintf(fid,'%s<transparent>\n',o(6));
    fprintf(fid,'%s<color>%d %d %d %d</color>\n',o(7),[1 1 1 1]);
    fprintf(fid,'%s</transparent>\n',o(6));
    fprintf(fid,'%s<transparency>\n',o(6));
    fprintf(fid,'%s<float>%f</float>\n',o(7),0);
    fprintf(fid,'%s</transparency>\n',o(6));
    fprintf(fid,'%s</lambert>\n',o(5));
    fprintf(fid,'%s</technique>\n',o(4));
    fprintf(fid,'%s</profile_COMMON>\n',o(3));
    fprintf(fid,'%s</effect>\n',o(2));
end
fprintf(fid,'%s</library_effects>\n',o(1));

% Geometry
%--------------------------------------------------------------------------
fprintf(fid,'%s<library_geometries>\n',o(1));
for i=1:numel(s)
    fprintf(fid,'%s<geometry id="shape%d" name="shape%d">\n',o(2),i,i);
    fprintf(fid,'%s<mesh>\n',o(3));
    fprintf(fid,'%s<source id="shape%d-positions">\n',o(4),i);
    fprintf(fid,'%s<float_array id="shape%d-positions-array" count="%d">',o(5),i,numel(s(i).vertices));
    fprintf(fid,'%f ',reshape(s(i).vertices',1,[]));
    fprintf(fid,'</float_array>\n');
    fprintf(fid,'%s<technique_common>\n',o(5));
    fprintf(fid,'%s<accessor count="%d" offset="0" source="#shape%d-positions-array" stride="3">\n',o(6),size(s(i).vertices,1),i);
    fprintf(fid,'%s<param name="X" type="float" />\n',o(7));
    fprintf(fid,'%s<param name="Y" type="float" />\n',o(7));
    fprintf(fid,'%s<param name="Z" type="float" />\n',o(7));
    fprintf(fid,'%s</accessor>\n',o(6));
    fprintf(fid,'%s</technique_common>\n',o(5));
    fprintf(fid,'%s</source>\n',o(4));
    fprintf(fid,'%s<vertices id="shape%d-vertices">\n',o(4),i);
    fprintf(fid,'%s<input semantic="POSITION" source="#shape%d-positions"/>\n',o(5),i);
    fprintf(fid,'%s</vertices>\n',o(4));
    fprintf(fid,'%s<triangles material="material%d" count="%d">\n',o(4),i,size(s(i).faces,1));
    fprintf(fid,'%s<input semantic="VERTEX" source="#shape%d-vertices" offset="0"/>\n',o(5),i);
    fprintf(fid,'%s
',o(5));
    fprintf(fid,'%d ',reshape(s(i).faces',1,[])-1);
    fprintf(fid,'
\n');
    fprintf(fid,'%s</triangles>\n',o(4));
    fprintf(fid,'%s</mesh>\n',o(3));
    fprintf(fid,'%s</geometry>\n',o(2));
end
fprintf(fid,'%s</library_geometries>\n',o(1));

% Scene
%--------------------------------------------------------------------------
fprintf(fid,'%s<library_visual_scenes>\n',o(1));
fprintf(fid,'%s<visual_scene id="VisualSceneNode" name="SceneNode">\n',o(2));
for i=1:numel(s)
    fprintf(fid,'%s<node id="node%d">\n',o(3),i);
    fprintf(fid,'%s<instance_geometry url="#shape%d">\n',o(4),i);
    fprintf(fid,'%s<bind_material>\n',o(5));
    fprintf(fid,'%s<technique_common>\n',o(6));
    fprintf(fid,'%s<instance_material symbol="material%d" target="#material%d"/>\n',o(7),i,i);
    fprintf(fid,'%s</technique_common>\n',o(6));
    fprintf(fid,'%s</bind_material>\n',o(5));
    fprintf(fid,'%s</instance_geometry>\n',o(4));
    fprintf(fid,'%s</node>\n',o(3));
end
fprintf(fid,'%s</visual_scene>\n',o(2));
fprintf(fid,'%s</library_visual_scenes>\n',o(1));
fprintf(fid,'%s<scene>\n',o(1));
fprintf(fid,'%s<instance_visual_scene url="#VisualSceneNode" />\n',o(2));
fprintf(fid,'%s</scene>\n',o(1));

% End of XML
%--------------------------------------------------------------------------
fprintf(fid,'</COLLADA>\n');

% Close file
%--------------------------------------------------------------------------
fclose(fid);

%==========================================================================
% function save_idtf(s,filename)
%==========================================================================
function save_idtf(s,filename)

o = @(x) blanks(x*3);

% Compute normals
%--------------------------------------------------------------------------
if ~isfield(s,'normals')
    try
        s.normals = spm_mesh_normals(...
            struct('vertices',s.vertices,'faces',s.faces),true);
    catch
        s.normals = [];
    end
end

% Split the mesh into connected components
%--------------------------------------------------------------------------
try
    C = spm_mesh_label(s.faces);
    d = [];
    try
        if size(s.cdata,2) == 1 && (any(s.cdata>1) || any(s.cdata<0))
            mi = min(s.cdata); ma = max(s.cdata);
            s.cdata = (s.cdata-mi)/ (ma-mi);
        else
        end
    end
    for i=1:numel(unique(C))
        d(i).faces    = s.faces(C==i,:);
        u             = unique(d(i).faces);
        d(i).vertices = s.vertices(u,:);
        d(i).normals  = s.normals(u,:);
        a             = 1:max(d(i).faces(:));
        a(u)          = 1:size(d(i).vertices,1);
        %a = sparse(1,double(u),1:1:size(d(i).vertices,1));
        d(i).faces    = a(d(i).faces);
        d(i).mat      = s.mat;
        try
            d(i).cdata = s.cdata(u,:);
            if size(d(i).cdata,2) == 1
                d(i).cdata = repmat(d(i).cdata,1,3);
            end
        end
    end
    s = d;
end

% Open file for writing
%--------------------------------------------------------------------------
fid = fopen(filename,'wt');
if fid == -1
    error('Unable to write file %s: permission denied.',filename);
end

% FILE_HEADER
%--------------------------------------------------------------------------
fprintf(fid,'FILE_FORMAT "IDTF"\n');
fprintf(fid,'FORMAT_VERSION 100\n\n');

% NODES
%--------------------------------------------------------------------------
for i=1:numel(s)
    fprintf(fid,'NODE "MODEL" {\n');
    fprintf(fid,'%sNODE_NAME "%s"\n',o(1),sprintf('Mesh%04d',i));
    fprintf(fid,'%sPARENT_LIST {\n',o(1));
    fprintf(fid,'%sPARENT_COUNT %d\n',o(2),1);
    fprintf(fid,'%sPARENT %d {\n',o(2),0);
    fprintf(fid,'%sPARENT_NAME "%s"\n',o(3),'<NULL>');
    fprintf(fid,'%sPARENT_TM {\n',o(3));
    I = s(i).mat; % eye(4);
    for j=1:size(I,2)
        fprintf(fid,'%s',o(4)); fprintf(fid,'%f ',I(:,j)'); fprintf(fid,'\n');
    end
    fprintf(fid,'%s}\n',o(3));
    fprintf(fid,'%s}\n',o(2));
    fprintf(fid,'%s}\n',o(1));
    fprintf(fid,'%sRESOURCE_NAME "%s"\n',o(1),sprintf('Mesh%04d',i));
    %fprintf(fid,'%sMODEL_VISIBILITY "BOTH"\n',o(1));
    fprintf(fid,'}\n\n');
end

% NODE_RESOURCES
%--------------------------------------------------------------------------
for i=1:numel(s)
    fprintf(fid,'RESOURCE_LIST "MODEL" {\n');
    fprintf(fid,'%sRESOURCE_COUNT %d\n',o(1),1);
    fprintf(fid,'%sRESOURCE %d {\n',o(1),0);
    fprintf(fid,'%sRESOURCE_NAME "%s"\n',o(2),sprintf('Mesh%04d',i));
    fprintf(fid,'%sMODEL_TYPE "MESH"\n',o(2));
    fprintf(fid,'%sMESH {\n',o(2));
    fprintf(fid,'%sFACE_COUNT %d\n',o(3),size(s(i).faces,1));
    fprintf(fid,'%sMODEL_POSITION_COUNT %d\n',o(3),size(s(i).vertices,1));
    fprintf(fid,'%sMODEL_NORMAL_COUNT %d\n',o(3),size(s(i).normals,1));
    if ~isfield(s(i),'cdata') || isempty(s(i).cdata)
        c = 0;
    else
        c = size(s(i).cdata,1);
    end
    fprintf(fid,'%sMODEL_DIFFUSE_COLOR_COUNT %d\n',o(3),c);
    fprintf(fid,'%sMODEL_SPECULAR_COLOR_COUNT %d\n',o(3),0);
    fprintf(fid,'%sMODEL_TEXTURE_COORD_COUNT %d\n',o(3),0);
    fprintf(fid,'%sMODEL_BONE_COUNT %d\n',o(3),0);
    fprintf(fid,'%sMODEL_SHADING_COUNT %d\n',o(3),1);
    fprintf(fid,'%sMODEL_SHADING_DESCRIPTION_LIST {\n',o(3));
    fprintf(fid,'%sSHADING_DESCRIPTION %d {\n',o(4),0);
    fprintf(fid,'%sTEXTURE_LAYER_COUNT %d\n',o(5),0);
    fprintf(fid,'%sSHADER_ID %d\n',o(5),0);
    fprintf(fid,'%s}\n',o(4));
    fprintf(fid,'%s}\n',o(3));

    fprintf(fid,'%sMESH_FACE_POSITION_LIST {\n',o(3));
    fprintf(fid,'%d %d %d\n',s(i).faces'-1);
    fprintf(fid,'%s}\n',o(3));

    fprintf(fid,'%sMESH_FACE_NORMAL_LIST {\n',o(3));
    fprintf(fid,'%d %d %d\n',s(i).faces'-1);
    fprintf(fid,'%s}\n',o(3));

    fprintf(fid,'%sMESH_FACE_SHADING_LIST {\n',o(3));
    fprintf(fid,'%d\n',zeros(size(s(i).faces,1),1));
    fprintf(fid,'%s}\n',o(3));

    if c
        fprintf(fid,'%sMESH_FACE_DIFFUSE_COLOR_LIST {\n',o(3));
        fprintf(fid,'%d %d %d\n',s(i).faces'-1);
        fprintf(fid,'%s}\n',o(3));
    end

    fprintf(fid,'%sMODEL_POSITION_LIST {\n',o(3));
    fprintf(fid,'%f %f %f\n',s(i).vertices');
    fprintf(fid,'%s}\n',o(3));

    fprintf(fid,'%sMODEL_NORMAL_LIST {\n',o(3));
    fprintf(fid,'%f %f %f\n',s(i).normals');
    fprintf(fid,'%s}\n',o(3));

    if c
        fprintf(fid,'%sMODEL_DIFFUSE_COLOR_LIST {\n',o(3));
        fprintf(fid,'%f %f %f\n',s(i).cdata');
        fprintf(fid,'%s}\n',o(3));
    end

    fprintf(fid,'%s}\n',o(2));
    fprintf(fid,'%s}\n',o(1));
    fprintf(fid,'}\n');
end

% Close file
%--------------------------------------------------------------------------
fclose(fid);

%==========================================================================
% function save_obj(s,filename)
%==========================================================================
function save_obj(s,filename)

% Open file for writing
%--------------------------------------------------------------------------
fid = fopen(filename,'wt');
if fid == -1
    error('Unable to write file %s: permission denied.',filename);
end

% Vertices & faces
%--------------------------------------------------------------------------
fprintf(fid,'# Wavefront OBJ file saved by %s\n','SPM'); % spm('Version')
fprintf(fid,'v %f %f %f\n',s.vertices');
fprintf(fid,'f %d %d %d\n',s.faces');

% Close file
%--------------------------------------------------------------------------
fclose(fid);

%==========================================================================
% function save_ply(s,filename)
%==========================================================================
function save_ply(s,filename)

% Open file for writing
%--------------------------------------------------------------------------
fid = fopen(filename,'wt');
if fid == -1
    error('Unable to write file %s: permission denied.',filename);
end

% Header
%--------------------------------------------------------------------------
fprintf(fid,'ply\n');
fprintf(fid,'format ascii 1.0\n');
fprintf(fid,'element vertex %d\n',size(s.vertices,1));
fprintf(fid,'property float32 x\n');
fprintf(fid,'property float32 y\n');
fprintf(fid,'property float32 z\n');
fprintf(fid,'element face %d\n',size(s.faces,1));
fprintf(fid,'property list uint8 int32 vertex_indices\n');
fprintf(fid,'end_header\n');

% Vertices & faces
%--------------------------------------------------------------------------
fprintf(fid,'%f %f %f\n',s.vertices');
fprintf(fid,'3 %d %d %d\n',s.faces'-1);

% Close file
%--------------------------------------------------------------------------
fclose(fid);

%==========================================================================
% function write_freesurfer_file(s,filename,format)
%==========================================================================
function write_freesurfer_file(s,filename,format)

switch lower(format)
    case 'surf'
        fid = fopen(filename,'wb','ieee-be');
        if fid == -1, error('Cannot open "%s".',filename); end
        fwrite(fid,[255 255 254],'uchar');
        fprintf(fid,'created by @gifti on %s\n\n',...
            datestr(now,'ddd mmm dd HH:MM:SS yyyy'));
        fwrite(fid,size(s.vertices,1),'int32'); % nv
        fwrite(fid,size(s.faces,1),'int32'); % nf
        fwrite(fid,s.vertices','float32');
        fwrite(fid,s.faces'-1,'int32');
        fclose(fid);
    case 'curv'
        fid = fopen(filename,'wb','ieee-be');
        if fid == -1, error('Cannot open "%s".',filename); end
        fwrite(fid,[255 255 255],'uchar');
        fwrite(fid,size(s.cdata,1),'int32'); % nv
        if isfield(s,'faces')
            nf = size(s.faces,1);
        else
            nf = 0;
        end
        fwrite(fid,nf,'int32'); % nf
        fwrite(fid,size(s.cdata,2),'int32'); % n
        fwrite(fid,s.cdata','float32');
        fclose(fid);
    otherwise
        error('File format not supported.');
end


function [G, G_ind, related, n_genes_KO, G_time] = buildGmatrix(model_name, model, separate_isoform, numWorkers, printLevel)
% Build the G matrix required for the calculation of genetic Minimal Cut
% Sets (gMCSs).
%
% USAGE:
%
%    [G, G_ind, related, n_genes_KO, G_time] = buildGmatrix(model_name, model_struct, separate_isoform, numWorkers, printLevel)
%
% INPUTS:
%    model_name:          Name of the metabolic model under study.
%    model_struct:        Metabolic model structure (COBRA Toolbox format).
%    separate_isoform:    Character used to discriminate different isoforms of a gene.
%
% OPTIONAL INPUTS:
%    numWorkers:        Maximum number of workers
%                       * 0 - maximum provided by the system (automatic)
%                       * 1 - sequential
%                       * 2+ - parallel
%    printLevel:        show the reactions created in models.
%                       * 0 - shows nothing
%                       * 1 - shows progress by reactions (default)
%                       * 2+ - shows everything (reaction and network generation)
%
% OUTPUTS:
%    G:             G matrix.
%    G_ind:         Gene knockouts associated with each row in the G matrix.
%    related:       Relationships among rows of the G matrix.
%    n_genes_KO:    Number of genes whose knockout is added by each row of the G matrix.
%    G_time:        Calculation times for each of the steps.
%
% EXAMPLE:
%
%    [G, G_ind, related, n_genes_KO, G_time] = buildGmatrix('Recon2.v04', modelR204, '.')
%
% .. Authors:
%       - Inigo Apaolaza, 16/11/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.
%       - Inigo Apaolaza, 10/04/2018, University of Navarra, TECNUN School of Engineering.

time_a = tic;
% Generate name for temporary folder
global CBTDIR
tmpFolderName = [CBTDIR filesep '.tmp'];
if ~exist(tmpFolderName,'dir')  % Create directories if needed
    mkdir(tmpFolderName)
end
if ~exist([tmpFolderName filesep 'rxn_level_gMCSs'],'dir')
    mkdir([tmpFolderName filesep 'rxn_level_gMCSs'])
end
if ~exist([tmpFolderName filesep 'rxn_level_gMCSs_by_rxn'],'dir')
    mkdir([tmpFolderName filesep 'rxn_level_gMCSs_by_rxn'])
end
if ~exist([tmpFolderName filesep 'rxn_level_models'],'dir')
    mkdir([tmpFolderName filesep 'rxn_level_models'])
end

% Analyze the GPR rules in order to set the strategy for the calculation of
% the knockouts for the G matrix
grRules = model.grRules;
rxnGeneMat = model.rxnGeneMat;
n_rxns = size(rxnGeneMat, 1);

rxns_0_genes = sum(rxnGeneMat, 2) == 0;
rxns_1_gene = sum(rxnGeneMat, 2) == 1;
rxns_or = cellfun(@strfind, grRules, repmat({'or'}, n_rxns, 1), 'UniformOutput', false);
rxns_or = ~cellfun(@isempty, rxns_or) & sum(rxnGeneMat, 2) > 1;
rxns_and = cellfun(@strfind, grRules, repmat({'and'}, n_rxns, 1), 'UniformOutput', false);
rxns_and = ~cellfun(@isempty, rxns_and) & sum(rxnGeneMat, 2) > 1;
rxns_only_or = rxns_or & ~rxns_and;
rxns_only_and = ~rxns_or & rxns_and;
rxns_or_and = rxns_or & rxns_and;

n_rxns_0_genes = sum(rxns_0_genes);
n_rxns_1_gene = sum(rxns_1_gene);
n_rxns_only_or = sum(rxns_only_or);
n_rxns_only_and = sum(rxns_only_and);
n_rxns_or_and = sum(rxns_or_and);
n_rxns_total = n_rxns_0_genes+n_rxns_1_gene+n_rxns_only_or+n_rxns_only_and+n_rxns_or_and;

summary_1 = {'n_rxns_0_genes', n_rxns_0_genes; 'n_rxns_1_gene', n_rxns_1_gene;
    'n_rxns_only_or', n_rxns_only_or; 'n_rxns_only_and', n_rxns_only_and;
    'n_rxns_or_and', n_rxns_or_and; 'n_rxns_total', n_rxns_total};
if printLevel >=1
    fprintf('\nG MATRIX - Summary\n')
    disp(summary_1)
end
ini_time = toc(time_a);

% Step 1 - Reactions with 1 gene
% clc
if printLevel >=1
    disp('G MATRIX - STEP 1');
end
time_b = tic;
act_rxnGeneMat = rxnGeneMat(rxns_1_gene, :);
not_delete_cols = sum(act_rxnGeneMat, 1) ~= 0;
act_rxnGeneMat = act_rxnGeneMat(:, not_delete_cols);
G_ind_1 = model.genes(not_delete_cols);
n_KO_1 = length(G_ind_1);
tmp_G_1 = act_rxnGeneMat';
G_1 = zeros(n_KO_1, n_rxns);
G_1(:, rxns_1_gene) = tmp_G_1;
G_time(1, 1) = toc(time_b);

% Step2 - Reactions with more than one gene and only OR rules
% clc
if printLevel >=1
    disp('G MATRIX - STEP 2');
end
time_c = tic;
act_rxnGeneMat = rxnGeneMat(rxns_only_or, :);
pos_rxns_only_or = find(rxns_only_or);
for i = 1:n_rxns_only_or
    G_ind_2{i, 1} = model.genes(logical(act_rxnGeneMat(i, :)))';
end
tmp_G_2 = eye(n_rxns_only_or);
G_2 = zeros(n_rxns_only_or, n_rxns);
G_2(:, rxns_only_or) = tmp_G_2;
G_time(2, 1) = toc(time_c);

% Reactions with more than one gene and only AND rules
% clc
if printLevel >=1
    disp('G MATRIX - STEP 3');
end
time_d = tic;
act_rxnGeneMat = rxnGeneMat(rxns_only_and, :);
not_delete_cols = sum(act_rxnGeneMat, 1) ~= 0;
act_rxnGeneMat = act_rxnGeneMat(:, not_delete_cols);
G_ind_3 = model.genes(not_delete_cols);
n_KO_3 = length(G_ind_3);
tmp_G_3 = act_rxnGeneMat';
G_3 = zeros(n_KO_3, n_rxns);
G_3(:, rxns_only_and) = tmp_G_3;
G_time(3, 1) = toc(time_d);

% Reactions with more than one gene and both OR and AND rules
time_e = tic;
search_filename = [tmpFolderName filesep 'rxn_level_models' filesep 'rxn_level_' model_name '_and_or.mat'];
if exist(search_filename,'file')
    load(search_filename);
else
    pos_rxns_or_and = find(rxns_or_and);
    [models_or_and, rxnNumGenes_or_and] = GPR2models(model, pos_rxns_or_and, separate_isoform, numWorkers, printLevel);
    save(search_filename, 'models_or_and', 'rxnNumGenes_or_and');
end

search_filename_2 = [tmpFolderName filesep 'rxn_level_gMCSs' filesep 'rxn_level_gMCSs_' model_name '.mat'];
if exist(search_filename_2,'file')
    load(search_filename_2);
else
    target_b = 1e-3;
    n_mcs = 100000000000;
    timelimit = 5*60;
    pos_rxns_or_and = find(rxns_or_and);
    if printLevel >=1
        disp('G MATRIX - STEP 4');
        showprogress(0);
    end
    for i = 1:n_rxns_or_and
        if printLevel >=1
%             disp([num2str(i),' of ', num2str(n_rxns_or_and)]);
            showprogress(i/n_rxns_or_and);
        end
        search_filename_3 = [tmpFolderName filesep 'rxn_level_gMCSs_by_rxn' filesep 'rxn_level_gMCSs_' model_name '_rxn' num2str(pos_rxns_or_and(i)) '.mat'];
        if exist(search_filename_3,'file')
            load(search_filename_3);
            mcs{i, 1} = act_mcs;
        else
            act_model = models_or_and{i};
            nbio = find(act_model.c);
            rxns = act_model.rxns;
            tmp = repmat({'DM_'}, length(rxns), 1);
            DM = cellfun(@strfind, rxns, tmp, 'UniformOutput', false);
            DM = ~cellfun(@isempty, DM);
            n_DM = sum(DM);
            DM = rxns(find(DM));
%             options.rxn_set = DM;
% %             options.timelimit = timelimit;
%             options.target_b = target_b;
%             options.printLevel = 0;
            max_len_mcs = length(DM);
            [act_mcs, act_mcs_time] = calculateMCS(act_model, n_mcs, max_len_mcs,...
                'rxn_set', DM,...
                'timelimit', timelimit,...
                'target_b', target_b,...
                'printLevel', 0);
            mcs{i, 1} = act_mcs;
            mcs_time{i, 1} = act_mcs_time;
            save(search_filename_3, 'act_mcs', 'act_mcs_time');
        end
    end
    save(search_filename_2);
end

k = 0;
for i = 1:n_rxns_or_and
    load([tmpFolderName filesep 'rxn_level_gMCSs_by_rxn' filesep 'rxn_level_gMCSs_' model_name '_rxn' num2str(pos_rxns_or_and(i)) '.mat']);
    n_act_mcs = length(act_mcs);

    for j = 1:n_act_mcs
        act_G_ind = act_mcs{j};
        if ~iscell(act_G_ind) && isnan(act_G_ind)
        else
            act_G_ind = cellfun(@strrep, act_G_ind, repmat({'DM_'}, length(act_G_ind), 1), repmat({''}, length(act_G_ind), 1), 'UniformOutput', false);
            act_G_ind = cellfun(@strtok, act_G_ind, repmat({separate_isoform}, length(act_G_ind), 1), 'UniformOutput', false);
            k = k+1;
            G_4(k, :) = zeros(1, n_rxns);
            G_4(k, pos_rxns_or_and(i)) = 1;
            G_ind_4{k, 1} = act_G_ind';
        end
    end
end
G_time(4, 1) = toc(time_e);

% Delete isoforms in order to work at the gene level
time_f = tic;
G_ind_1 = cellfun(@strtok, G_ind_1, repmat({separate_isoform}, length(G_ind_1), 1), 'UniformOutput', false);

n_KO_2 = length(G_ind_2);
for i = 1:n_KO_2
    act_G_ind_2 = G_ind_2{i};
    act_G_ind_2 = cellfun(@strtok, act_G_ind_2, repmat({separate_isoform}, 1, length(act_G_ind_2)), 'UniformOutput', false);
    G_ind_2{i} = unique(act_G_ind_2);
end
G_ind_3 = cellfun(@strtok, G_ind_3, repmat({separate_isoform}, length(G_ind_3), 1), 'UniformOutput', false);

% Delete repeats
if printLevel >=1
    disp('G MATRIX - Delete Repeats');
end
tmp_G = [];
try tmp_G = [tmp_G; G_1]; end
try tmp_G = [tmp_G; G_2]; end
try tmp_G = [tmp_G; G_3]; end
try tmp_G = [tmp_G; G_4]; end
tmp_G_ind = [];
try tmp_G_ind = [tmp_G_ind; G_ind_1]; end
try tmp_G_ind = [tmp_G_ind; G_ind_2]; end
try tmp_G_ind = [tmp_G_ind; G_ind_3]; end
try tmp_G_ind = [tmp_G_ind; G_ind_4]; end
n_tmp_G_ind = length(tmp_G_ind);

k = 0;
clear G G_ind
for i = 1:n_tmp_G_ind
    if i == 1
        k = k+1;
        G(k, :) = tmp_G(i, :);
        if ~iscell(tmp_G_ind{i})
            G_ind{k, 1} = tmp_G_ind(i);
        else
            G_ind{k, 1} = sort(tmp_G_ind{i});
        end
    else
        if ~iscell(tmp_G_ind{i})
            act_G_ind = tmp_G_ind(i);
        else
            act_G_ind = sort(tmp_G_ind{i});
        end

        pos_equal = cellfun(@isequal, G_ind, repmat({act_G_ind}, length(G_ind), 1));
        if sum(pos_equal) > 0
            G(pos_equal, :) = G(pos_equal, :) + tmp_G(i, :);
        else
            k = k+1;
            G(k, :) = tmp_G(i, :);
            G_ind{k, 1} = act_G_ind;
        end
    end
end

% Fill the G matrix with reactions which are knocked out by a given KO
% without being a gMCS
n_genes_KO = cellfun(@length, G_ind);
[n_genes_KO, ind] = sort(n_genes_KO, 'ascend');
G_ind = G_ind(ind);
G = G(ind, :);
n_G_ind = length(G_ind);
for i = 1:n_G_ind
    act_G_ind = G_ind{i};
    n_act_G_ind = length(act_G_ind);
    pos = find(n_genes_KO > n_act_G_ind);
    greater_G_ind = G_ind(pos);
    n_greater_G_ind = length(pos);
    for j = 1:n_greater_G_ind
        if sum(ismember(G_ind{pos(j)}, act_G_ind)) == n_act_G_ind
            G(pos(j), :) = G(pos(j), :) + G(i, :);
        end
    end
end
G = double(G>0);

% Check the interconnections between KOs
if printLevel >=1
    disp('G MATRIX - Check Relations');
end
k = 0;
n_genes_KO = cellfun(@length, G_ind);
for i = 2:n_G_ind
    act_G_ind = G_ind(i);
    n_act_G_ind = length(act_G_ind{:});
    pos = find(n_genes_KO < n_act_G_ind);
    if ~isempty(pos)
        pos = pos(end);
        for j = 1:pos
            act_G_ind_2 = G_ind(j);
            tmp = ismember(act_G_ind{:}, act_G_ind_2{:});
            n_act_G_ind_2 = length(act_G_ind_2{:});
            if sum(tmp) == n_act_G_ind_2
                k = k+1;
                related(k, 1) = i;
                related(k, 2) = j;
            end
        end
    end
end

if exist('related')
    un_related = unique(related(:, 1));
    n_un_related = length(un_related);
    for i = 1:n_un_related
        act_KO = un_related(i);
        ind = find(related(:, 1) == act_KO);
        act_related = related(ind, 2);
        all_genes = [G_ind{act_related}];
        un_all_genes = unique(all_genes);
        n_un_all_genes = length(un_all_genes);
        n_genes_KO(act_KO) = n_genes_KO(act_KO)-n_un_all_genes;
    end
else
    related = NaN;
end

final_filename = [pwd filesep 'G_' model_name '.mat'];
G_time(5, 1) = toc(time_f)+ini_time;
save(final_filename, 'G', 'G_ind', 'related', 'n_genes_KO', 'G_time');
if printLevel >=1
    disp('The G Matrix has been successfully calculated');
end
rmdir(tmpFolderName, 's');
end


function [num_all_images, sensors, paths, info_count_text] = CheckImagesPath(path_data)
%CHECKIMAGEPATH Ensure the input path is right to find a Landsats 4-8, and
%Sentinel 2 image(s).
% path_data - the input path

    % searching deeps. 0 is default.
    [image_types_paths] = CheckImagePath(path_data,0);

    % all count info foe searched images at current folder.
    num_all_images = size(image_types_paths,1);
    num_L4_tm = 0;
    num_L5_tm = 0;
    num_L6_tm = 0;
    num_L7_tm_plus = 0;
    num_L8_oli_tirs = 0;
    num_S2A_msi = 0;
    num_S2B_msi = 0;

    % key info: the senor and path are needed as outputs, the first one is
    % to determine the default parameters for Fmask, and the second one is
    % to determine the path loading all data.
    sensors = [];
    paths = [];
    info_count_text = [];

    for i_all = 1:num_all_images
        % c: current.
        cimage_sensor = image_types_paths{i_all,1};
        cimage_num = image_types_paths{i_all,2};
        cimage_type = Convert2ImageType(cimage_sensor,cimage_num);
        clear cimage_num;
        cimage_path = image_types_paths{i_all,3};
        switch cimage_type
            case {'Landsat 4 TM'}
                num_L4_tm=num_L4_tm+1;
            case {'Landsat 5 TM'}
                num_L5_tm=num_L5_tm+1;
            case {'Landsat 6 TM'}
                num_L6_tm=num_L6_tm+1;
            case {'Landsat 7 ETM+'}
                num_L7_tm_plus=num_L7_tm_plus+1;
            case {'Landsat 8 OLI/TIRS'}
                num_L8_oli_tirs=num_L8_oli_tirs+1;
            case {'Sentinel 2A MSI'}
                % further check Sentinel 2 image folder, see there is
                % .SAFE.
                if contains(cimage_path,'.SAFE')
                    num_S2A_msi=num_S2A_msi+1;
                else
                    cimage_sensor = [];% no available Sentinel 2 data.
                end
            case {'Sentinel 2B MSI'}
                % see there is .SAFE.
                if contains(cimage_path,'.SAFE')
                    num_S2B_msi=num_S2B_msi+1;
                else
                    cimage_sensor = [];% no available Sentinel 2 data.
                end
        end
        if ~isempty(cimage_sensor)
            sensors = [sensors;{cimage_sensor}];
            paths = [paths;{cimage_path}];
        end
        clear cimage_sensor;
    end
    % renew num_all_images
    num_all_images = length(sensors);
    % used to notice user.
    text_line = 0;
    % multide
    if isequal(num_all_images,num_L4_tm)||...
            isequal(num_all_images,num_L5_tm)||...
            isequal(num_all_images,num_L6_tm)||...
            isequal(num_all_images,num_L7_tm_plus)||...
            isequal(num_all_images,num_L8_oli_tirs)||...
            isequal(num_all_images,num_S2A_msi)||...
            isequal(num_all_images,num_S2B_msi)
       % only for 1 type image
        if num_L4_tm > 0
        text_line = text_line+1;
        info_count_text{text_line} = sprintf('%s Landsat 4 TM images are found at ''%s''\n',...
            num2str(num_L4_tm),path_data);
        end
        if num_L5_tm > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Landsat 5 TM images are found at ''%s''\n',...
                num2str(num_L5_tm),path_data);
        end
        if num_L6_tm > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Landsat 6 TM images are found at ''%s''\n',...
            num2str(num_L6_tm),path_data);
        end
        if num_L7_tm_plus > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Landsat 7 ETM+ images are found at ''%s''\n',...
                num2str(num_L7_tm_plus),path_data);
        end
        if num_L8_oli_tirs > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Landsat 8 OLI/TIRS images are found at ''%s''\n',...
                 num2str(num_L8_oli_tirs),path_data);
        end
        if num_S2A_msi > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Sentinel 2A MSI images are found at ''%s''\n',...
                num2str(num_S2A_msi),path_data);
        end
        if num_S2B_msi > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Sentinel 2B MSI images are found at ''%s''\n',...
                num2str(num_S2B_msi),path_data);
        end
    else
         text_line = text_line+1;
         info_count_text{text_line} = sprintf(...
            'A total of %s images (as follows) are found at ''%s''\n',...
            num2str(num_all_images), path_data);
        if num_L4_tm > 0
        text_line = text_line+1;
        info_count_text{text_line} = sprintf('%s Landsat 4 TM images\n',...
            num2str(num_L4_tm));
        end
        if num_L5_tm > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Landsat 5 TM images\n',...
                num2str(num_L5_tm));
        end
        if num_L6_tm > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Landsat 6 TM images\n',...
            num2str(num_L6_tm));
        end
        if num_L7_tm_plus > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Landsat 7 ETM+ images\n',...
                num2str(num_L7_tm_plus));
        end
        if num_L8_oli_tirs > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Landsat 8 OLI/TIRS images\n',...
                 num2str(num_L8_oli_tirs));
        end
        if num_S2A_msi > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Sentinel 2A MSI images\n',...
                num2str(num_S2A_msi));
        end
        if num_S2B_msi > 0
            text_line = text_line+1;
            info_count_text{text_line} = sprintf('%s Sentinel 2B MSI images\n',...
                num2str(num_S2B_msi));
        end
    end

    % if no data is found, give mention info.
    if isempty(sensors)
        text_line = text_line+1;
        info_count_text{text_line} = sprintf('%s available images are found at ''%s''\n',...
            '0',path_data);
        text_line = text_line+1;
        info_count_text{text_line} = sprintf('Please ensure the path is correct\n');
    end
%     fprintf(info_count);
end

function [image_types_paths] = CheckImagePath(path_data,subfolder_level)
%CHECKIMAGEPATH Ensure the input path is right to find a Landsats 4-8, and
%Sentinel 2 image(s).
% path_data - the input path
% subfolder_level - the level of subfolders that can be used to limit
% searching deeps. 0 is default.

    % If the searching deeps are more than 5, stop and return;
    if subfolder_level > 5
        image_types_paths = [];
        return;
    end
	image_types_paths = [];
    % first search the image(s) at current folder.image_types_paths
    [sensor,num_Lst,~,~] = LoadSensorType(path_data);
    if isempty(sensor)
        % if no available image at current folder,
        % and search its subfolders.
          subfolders = dir(path_data);
          for i_sub=1:length(subfolders)
              % filter out the file names starting with '.', that is not
              % right folder (system crashes).
              if strcmp(subfolders(i_sub).name(1),'.')
                  continue;
              end
              % go to search the images at each subfolder
              path_subfoler = fullfile(subfolders(i_sub).folder,...
                  subfolders(i_sub).name);
              [image_types_paths_sub] = CheckImagePath(path_subfoler,subfolder_level+1);
              if ~isempty(image_types_paths_sub)
                  image_types_paths =[image_types_paths;image_types_paths_sub];
              end
          end

    else
        % successfully searched a supported image.
        % and, return the sensor and the image path
        image_types_paths = [image_types_paths;{sensor,num_Lst,path_data}];
    end
end
function image_type = Convert2ImageType(sensor,num_Lst)
% CONVERT@IMAGETYPE Contruct image type from the sensor and num

    switch sensor
        case 'L_TM'
            image_type = ['Landsat ',num_Lst,' TM'];
        case 'L_ETM_PLUS'
            image_type = ['Landsat ',num_Lst,' ETM+'];
        case 'L_OLI_TIRS'
            image_type = ['Landsat ',num_Lst,' OLI/TIRS'];
        case 'S_MSI'
            image_type = ['Sentinel ',num_Lst,' MSI'];
        otherwise
            image_type=[];
%             error(['Errors occur when searching images at ''', path_data],'''.');
    end
end


function [valid, saveflg]= isUniformized(scanNum, planC)
%"isUniformized"
%   Checks to see if the uniform data for the specified scanNum exists and
%   that all fields appear valid.  Returns true if they are, false if they
%   arent (therefore suggesting the data should be regenerated using
%   setUniformizedData).
%
%JRA 05/24/05
%DK  04/20/06 check uniformization for old plans
%Usage:
%   function valid = isUniformized(scanNum, planC);
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

indexS = planC{end};
pathStr = getCERRPath;
optName = [pathStr 'CERROptions.json'];
optS = opts4Exe(optName);
saveflg = 0;
%Assume valid to start.
valid = 1;

%Check for required planC fields.
if ~isfield(indexS, 'scan') || ~isfield(indexS, 'structureArray')
    valid = 0;
    return;
end

%Check the two major planC components.
scanStruct = planC{indexS.scan}(scanNum);
if length(planC{indexS.structureArray})>=scanNum
    uniStruct  = planC{indexS.structureArray}(scanNum);
else
    uniStruct = [];
end

if isempty(scanStruct.uniformScanInfo)
    valid = 0;
    return;
end

%if isfield(uniStruct,'bitsArray') & isempty(uniStruct.bitsArray)& length(planC{indexS.structures})~= 0
if isfield(uniStruct,'bitsArray') && isempty(uniStruct.bitsArray) && ismember(scanNum,getAssociatedScan({planC{indexS.structures}.assocScanUID},planC))
    valid = 0;
    return;
elseif isempty(planC{indexS.structures})
    return;
end

if ~isfield(scanStruct, 'uniformScanInfo') ||...
        ~isfield(scanStruct, 'scanArrayInferior') || ~isfield(scanStruct, 'scanArraySuperior')
    valid = 0;
    return;
end

if isempty(uniStruct) || isempty(uniStruct.indicesArray) || isempty(uniStruct.bitsArray)
    %The uniformized structs are empty.  This should only happen if no
    %structures associated with this scan have no rasterSegments or if the
    %structures are excluded from uniformization in the options file.

    nStructs = length(planC{indexS.structures});
    assocScansV = getStructureAssociatedScan(1:nStructs, planC);

    %Check only structs that are associated with this scan.
    structsToCheck = find(assocScansV == scanNum);

    for i=1:length(structsToCheck)
        structNum = structsToCheck(i);
        structName = planC{indexS.structures}(structNum).structureName;

        %Ignore structures that are on the exclude list.
        if ismember(lower(structName), lower(optS.uniformizeExcludeStructs))
            continue;
        end

        [rS, planC] = getRasterSegments(structNum, planC);
        if ~isempty(rS) && ~(isfield(planC{indexS.structures},'rasterized') && planC{indexS.structures}(1).rasterized == 1)
            valid = 0;
            return;
        end
    end
else
    [~, ~, zV] = getUniformScanXYZVals(planC{indexS.scan}(scanNum));
    indicesM = planC{indexS.structureArray}(scanNum).indicesArray;
    askQuestion = 1;
%     for cellNum = 1:length(indicesC)
%         indicesM = indicesC{cellNum};
        if ~isempty(indicesM) && max(indicesM(:,3))>length(zV) && askQuestion
            valid = 0;
            querry = {'This is an old archived plan which was uniformized incorrectly'...
                'CERR will uniformized the plan again'...
                ''...
                'Would you like to save changes to original plan?'};
            ButtonName = questdlg(querry,'Uniformization Check','Yes','No','Yes');
            if strcmpi(ButtonName,'yes')
                saveflg = 1;
            end
        end
%     end
end


function F = transpose(F)
% .'   Transpose of a SPHEREFUNV.

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

F.isTransposed = ~F.isTransposed;

end


function varargout = process_evt_extended( varargin )
% PROCESS_EVT_EXTENDED: Convert simple events to extended events.
%
% USAGE:  OutputFiles = process_evt_extended('Run', sProcess, sInput)

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2013

eval(macro_method);
end

%% ===== GET DESCRIPTION =====
function sProcess = GetDescription() %#ok<DEFNU>
    % Description the process
    sProcess.Comment     = 'Convert to extended event';
    sProcess.Category    = 'File';
    sProcess.SubGroup    = 'Events';
    sProcess.Index       = 62;
    sProcess.Description = 'https://neuroimage.usc.edu/brainstorm/Tutorials/EventMarkers#Other_menus';
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'data', 'raw', 'matrix'};
    sProcess.OutputTypes = {'data', 'raw', 'matrix'};
    sProcess.nInputs     = 1;
    sProcess.nMinFiles   = 1;
    % Event name
    sProcess.options.eventname.Comment = 'Event names: ';
    sProcess.options.eventname.Type    = 'text';
    sProcess.options.eventname.Value   = '';
    % Time offset
    sProcess.options.timewindow.Comment = 'Time window around event:';
    sProcess.options.timewindow.Type    = 'range';
    sProcess.options.timewindow.Value   = {[-0.2, 0.2], 's', []};
end

%% ===== FORMAT COMMENT =====
function Comment = FormatComment(sProcess) %#ok<DEFNU>
    Comment = sProcess.Comment;
end

%% ===== RUN =====
function OutputFile = Run(sProcess, sInput) %#ok<DEFNU>
    % Return all the input files
    OutputFile = {sInput.FileName};

    % ===== GET OPTIONS =====
    % Time offset
    TimeWindow = sProcess.options.timewindow.Value{1};
    % Event names
    EvtNames = strtrim(str_split(sProcess.options.eventname.Value, ',;'));
    if isempty(EvtNames)
        bst_report('Error', sProcess, [], 'No events selected.');
        return;
    end

    % ===== LOAD FILE =====
    % Get file descriptor
    isRaw = strcmpi(sInput.FileType, 'raw');
    % Load the raw file descriptor
    if isRaw
        DataMat = in_bst_data(sInput.FileName, 'F');
        sEvents = DataMat.F.events;
        sFreq = DataMat.F.prop.sfreq;
    else
        DataMat = in_bst_data(sInput.FileName, 'Events', 'Time');
        sEvents = DataMat.Events;
        sFreq = 1 ./ (DataMat.Time(2) - DataMat.Time(1));
    end
    % If no markers are present in this file
    if isempty(sEvents)
        bst_report('Error', sProcess, sInput, 'This file does not contain any event.');
        return;
    end
    % Find event names
    iEvtList = [];
    for i = 1:length(EvtNames)
        iEvt = find(strcmpi(EvtNames{i}, {sEvents.label}));
        if isempty(iEvt)
            bst_report('Warning', sProcess, sInput, 'This file does not contain any event.');
        elseif isempty(sEvents(iEvt).times)
            bst_report('Warning', sProcess, sInput, ['Event category "' sEvents(iEvt).label '" is empty.']);
        elseif (size(sEvents(iEvt).times,1) > 1)
            bst_report('Warning', sProcess, sInput, ['Event category "' sEvents(iEvt).label '" already contains extended events.']);
        else
            iEvtList(end+1) = iEvt;
        end
    end
    % No events to process
    if isempty(iEvtList)
        bst_report('Error', sProcess, sInput, 'No events to process.');
        return;
    end

    % ===== PROCESS EVENTS =====
    for i = 1:length(iEvtList)
        sEvents(iEvtList(i)).times = round([...
            sEvents(iEvtList(i)).times + TimeWindow(1);
            sEvents(iEvtList(i)).times + TimeWindow(2)] .* sFreq) ./ sFreq;
    end

    % ===== SAVE RESULT =====
    % Report results
    if isRaw
        DataMat.F.events = sEvents;
    else
        DataMat.Events = sEvents;
    end
    % Only save changes if something was change
    bst_save(file_fullpath(sInput.FileName), DataMat, 'v6', 1);
end


% pop_runscript() - Run Matlab script
%
% Usage: >> pop_runscript;
%        >> pop_runscript( filename );
%
% Input:
%   filename - [string] name of the file.
%
% Author: Arnaud Delorme, SCCN / INC / UCSD, August 2009

% Copyright (C) Arnaud Delorme, August 2009
%
% 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 com = pop_runscript(filename);

com = [];
if nargin <1
    [filename filepath] = uigetfile('*.*', 'Please select input script -- pop_runscript()');

    if filename(1) == 0, return; end;

    filename = fullfile(filepath, filename);
end;

str = readtxtfile(filename);
try
    evalin('base', str);
catch
    lasterr
end;
com = sprintf('pop_runscript(''%s'');', filename);


function outcell = parse_char_to_cell(invar,sepval)
% take a row of characters and separate into cells, breaking at either
% spaces or tabs
%
% :Usage:
% :Usage:
% ::
%
%     outcell = parse_char_to_cell(invar,sepval)
%
% :Examples:
% ::
%
%    % copy from Excel as row, then parse:
%    disorder = ['SAD	PTSD	PTSD	PTSD	PTSD	PTSD	SP	SAD	PTSD	PTSD	PTSD	PTSD	PTSD	SAD	SAD	PTSD	PTSD	SP	SP	SP	PTSD	PTSD	PTSD	PTSD	SAD	SAD	SAD	SP	SAD	SAD	SAD	SP	SP	SP	SAD	SP	PTSD	SP	PTSD	PTSD'];
%    disorder = parse_char_to_cell(disorder, 'tab');
%
% ..
%    tor wager
% ..

switch sepval
    case 'space'
whsep = find(invar == ' ');
    case 'tab'
whsep = find(invar == sprintf('\t'));
    otherwise
        error('Enter space or tab')
end

st = [1 whsep+1];
en = [st(2:end) - 1 length(invar)+1];
n = length(st);

for i = 1:n
    outcell{i} = invar(st(i):en(i)-1);
end

end


function out=cellFilter(filterFunction,in)

keep=cellfun(filterFunction,in);
out=in(keep);

end


classdef DesignCapturerOfMaterialDesignExperiment < handle

    properties (Access = public)

    end

    properties (Access = private)
        outputFigureName
        inputFile
        experimentPath
        pathInput
        iterations
    end

    properties (Access = private)

    end

    methods (Access = public)

        function obj = DesignCapturerOfMaterialDesignExperiment()
            obj.init()
            obj.captureAllImages();
        end

    end

    methods (Access = private)

        function init(obj)
            path = '/home/alex/Dropbox/MaterialDesign/CC/Poisson';
            obj.outputFigureName = fullfile(path,'Poisson');
            obj.inputFile = 'HorizontalMaterialDesign';
            %obj.experimentPath = '/media/alex/MyPassport/MaterialDesign/CStar/LargeSquareWithPerimeter10_1';
            %obj.iterations = round(linspace(1,133,15));

         %   obj.experimentPath = '/media/alex/MyPassport/MaterialDesign/CStar/LargeCircleWithPerimeter10_12c';
         %   obj.iterations = round(linspace(1,67,15));

           % obj.experimentPath = '/media/alex/MyPassport/MaterialDesign/CStar/LargeCircleWithPerimeter10_1c';
           % obj.iterations = round(linspace(1,154,15));

            %obj.experimentPath = '/media/alex/MyPassport/MaterialDesign/CStar/HorizontalFromCircleWithPerimeter10_8_LargeCircle';
           % obj.iterations = round(linspace(1,27,9));

            obj.experimentPath = '/media/alex/MyPassport/MaterialDesign/CStar/NegPoissonNoPerimeter5x6';
            obj.iterations = round(linspace(1,162,10));

            %obj.experimentPath = '/home/alex/git-repos/Swan/Output/HorizontalMaterialDesign';
            %obj.iterations = 0;

        end

        function captureAllImages(obj)
            nIter = length(obj.iterations);
            for iter = 1:nIter
                iterImage = obj.iterations(iter);
                obj.captureImage(iterImage);
            end
        end

        function captureImage(obj,iter)
            i = iter;
            f = obj.inputFile;
            outPutNameWithIter = [obj.outputFigureName,'Iter',num2str(i)];
            inputFileName = fullfile(obj.experimentPath,[f,num2str(i),'.flavia.res']);
            s.fileName = f;
            s.outPutImageName = outPutNameWithIter;
            s.inputFileName   = inputFileName;
            imageCapturer     = GiDImageCapturer(s);
            imageCapturer.capture();
        end

    end

end


classdef TestBilateralFilter
    %TestBilateralFilter

    properties (Constant)
        im = fullfile(mexopencv.root(),'test','img001.jpg');
    end

    methods (Static)
        function test_simple
            img = cv.imread(TestBilateralFilter.im, 'ReduceScale',2);
            result = cv.bilateralFilter(img);
            validateattributes(result, {class(img)}, {'size',size(img)});
        end

        function test_options
            img = cv.imread(TestBilateralFilter.im, 'ReduceScale',2);
            result = cv.bilateralFilter(img, ...
                'Diameter',7, 'SigmaColor',50, 'SigmaSpace',50, ...
                'BorderType','Default');
            validateattributes(result, {class(img)}, {'size',size(img)});
        end

        function test_error_argnum
            try
                cv.bilateralFilter();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end

        function test_error_non_existant_option
            img = imread(TestBilateralFilter.im);
            try
                cv.bilateralFilter(img, 'foo','bar');
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end

        function test_error_invalid_option_value
            img = imread(TestBilateralFilter.im);
            try
                cv.bilateralFilter(img, 'BorderType','foo');
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end


function definput=arg_plotfwt(definput)

  definput.flags.frqbands = {'uni', 'dyad'};
  definput.flags.wavplottype = {'image', 'stem', 'surf','waterfall'};
  definput.keyvals.fc=[];
  definput.keyvals.ntickpos=10;
  definput.keyvals.tick=[];

  definput.groups.audtick={'tick',[0,100,250,500,1000,2000,4000,8000,16000,32000]};


function error_string = yalmiperror(errorcode,solver)
%YALMIPERROR Creates YALMIP error message based on error code
%
%   s = YALMIPERROR(ID) gives a textual description of an error
%   code generated by YALMIP (typically in SOLVESDP)
%
%   The complete set of error codes are
%
%   -12 Solver license cannot be located
%   -11 Solver license expired
%   -10 NaN in model data
%    -9 Specified solver name not recognized
%    -8 Problem does not satisfy geometric programming rules
%    -7 Solver does not return error codes
%    -6 Search space not bounded (bound all variables)
%    -5 License problems in solver
%    -4 Solver not applicable
%    -3 Solver not found in MATLAB path
%    -2 Successfully solved
%    -1 Unknown error
%     0 Successfully solved
%     1 Infeasible problem
%     2 Unbounded objective function
%     3 Maximum #iterations or time-limit exceeded
%     4 Numerical problems
%     5 Lack of progress
%     6 Initial solution infeasible
%     7 YALMIP sent incorrect input to solver
%     8 Feasibility cannot be determined
%     9 Unknown problem in solver
%    10 bigM failed (obsolete)
%    11 Other identified error (use savesolveroutput and refer to solver
%    documentation)
%    12 Infeasible or unbounded
%    13 YALMIP cannot determine status in solver
%    14 Model creation failed
%    15 Problem either infeasible or unbounded
%    16 User terminated
%    17 Presolve recovery failed
%    18 Missing non-negativity bounds in GP formulation
%    19 Convexity requirements not met
%    20 Solver complains about bad data
%    21 Failed to initialize bisection space (typically means infeasibility)
%    22 Ill-posed problem according to solver
%
%   See also OPTIMIZE

if nargin ==0
    help yalmiperror
    return
end

if nargin==1
    solver = '';
else
    solver = ['(' strrep(solver,'+','') ')'];
end

switch errorcode
case -12
  error_string = ['Solver license cannot be located ' solver];
case -11
  error_string = ['Solver license expired ' solver];
case -10
  error_string = ['NaN in model data ' solver];
case -9
  error_string = ['Specified solver name not recognized ' solver];
case -8
  error_string = ['Problem does not satisfy geometric programming rules'];
case -7
  error_string = ['Solver does not return error codes ' solver];
case -6
  error_string = ['Search space not bounded ' solver];
case -5
  error_string = ['License problems in solver ' solver];
 case -4
  error_string = ['Solver not applicable ' solver];
case -3
  error_string = ['Solver not found ' solver];
 case -2
  error_string = 'No suitable solver';
 case -1
  error_string = ['Unknown error ' solver];
 case 0
  error_string = ['Successfully solved ' solver ];
 case 1
  error_string = ['Infeasible problem ' solver ];
 case 2
  error_string = ['Unbounded objective function ' solver ];
 case 3
  error_string = ['Maximum iterations or time limit exceeded ' solver ];
 case 4
  error_string = ['Numerical problems ' solver ];
 case 5
  error_string = ['Lack of progress ' solver ];
 case 6
  error_string = ['Initial solution infeasible ' solver ];
 case 7
  error_string = ['YALMIP called solver with incorrect input ' solver ];
 case 8
  error_string = ['Feasibility cannot be determined ' solver ];
 case 9
  error_string = ['Unknown problem in solver (Turn on ''debug'' in sdpsettings) ' solver ];
 case 10
  error_string = ['bigM failed, increase sp.Mfactor ' solver ];
 case 11
  error_string = ['Other identified error ' solver ];
 case 12
  error_string = ['Either infeasible or unbounded ' solver ];
 case 13
  error_string = ['YALMIP cannot determine status in solver ' solver ];
 case 14
  error_string = ['Model creation failed ' solver ];
 case 15
  error_string = ['Infeasible or unbounded problem ' solver ];
 case 16
  error_string = ['User terminated ' solver ];
 case 17
  error_string = ['Presolve recovery failed ' solver ];
 case 18
  error_string = ['Missing non-negativity bounds in GP formulation ' solver ];
 case 19
  error_string = ['Convexity requirements not met ' solver ];
case 20
  error_string = ['Solver complains about bad data ' solver ];
case 21
  error_string = ['Failed to initialize bisection space (probably infeasible)' solver ];
case 22
  error_string = ['Ill-posed problem according to solver ' solver ];

 otherwise
end


% icp030001_new = poseSparsification( icp030001, '/home/yh/mapModel/2018/08.03/keep_0301.txt', 0.20);
% getDistribution(icp030001);
% hold on;
% getDistribution(icp030001_new);

% [pose10_new, pose10_keep] = ForKITTIPoses( '/home/yh/mapModel/2018/08.02/kitti10_pose.txt', '/home/yh/mapModel/2018/08.02/kitti10_keep.txt', pose10, 0.70);
%
% getDistribution(pose10_new);
% hold on;
% getDistribution(pose10_keep);

%% test

% icp0901_new = poseSparsification( icp0901, '/home/yh/mapModel/2018/08.03/test/keep_0901.txt', 0.20);
% getDistribution(icp0901);
% hold on;
% getDistribution(icp0901_new);

%% Chery test'

% chery_pose = poseSparsification( globalpose, '/home/yh/mapModel/2018/09.22/keep_chery.txt', 0.20);
% getDistribution(globalpose);
% hold on;
% getDistribution(chery_pose);

%% New YQ data pepare, the former are too dense\
%
% icp0301_new = poseSparsification( icp0301, '/home/yh/mapModel/2018/10.18/keep_0301.txt', 1.0);
% getDistribution(icp0301);
% hold on;
% getDistribution(icp0301_new);

%% Re-index for exp , 2019.07

% icp0301_new = poseSparsification_yq( '/home/yh/mapModel/2019/07.11/keep_0301.txt', '/home/yh/mapModel/2019/07.11/index_0301.txt', icp0301, 0.2);

% icp0301_new = poseSparsification_yq( '/home/yh/mapModel/2019/07.11/keep_0901.txt', '/home/yh/mapModel/2019/07.11/index_0901.txt', icp0901, 0.2);

% park_new = poseSparsification_yq( '/home/yh/mapModel/2019/07.23/keep_park.txt', '/home/yh/mapModel/2019/07.23/index_park.txt', parkpose, 0.2);

% kitti_new = poseSparsification_kitti( '/home/yh/mapModel/2019/07.21/keep_kitti.txt', '/home/yh/mapModel/2019/07.21/index_kitti.txt', Untitled, 0.5);

% kitti_new = poseSparsification_kitti( '/home/yh/mapModel/2019/07.27/keep_kitti.txt', '/home/yh/mapModel/2019/07.27/index_kitti.txt', X07, 0.5);


function [F,failure,cause,ALREADY_MODELLED] = expandmodel(F,h,options,w)

% FIX : Current code experimental, complex, conservative, has issues with
% nonlinearities and is slow...
%
% If it wasn't for polynomials and sigmonials, it would be trivial, but the
% code is extremely messy since we want to have this functionality too

global LUbounds
global ALREADY_MODELLED
global MARKER_VARIABLES
global DUDE_ITS_A_GP
global ALREADY_MODELLED_INDEX
global REMOVE_THESE_IN_THE_END
global OPERATOR_IN_POLYNOM
global CONSTRAINTCUTSTATE

% All extended variables in the problem. It is expensive to extract this
% one so we will keep it and pass it along in the recursion
extendedvariables = yalmip('extvariables');

integers = yalmip('intvariables');
binaries = yalmip('binvariables');
if ~isempty(F)
    declareI = find(is(F,'integer'));
    declareB = find(is(F,'binary'));
    if ~isempty(declareI)
        integers = [integers depends(F(declareI))];
    end
    if ~isempty(declareB)
        binaries = [binaries depends(F(declareB))];
    end
end
yalmip('settempintvariables',integers);
yalmip('settempbinvariables',binaries);

% We keep track of all auxilliary variables introduced by YALMIP
nInitial = yalmip('nvars');

boundsAlreadySet = 0;
% Meta constraints are expanded first (iff, implies, alldifferent etc)
if ~isempty(F)
    meta = find(is(F,'meta'));
    if ~isempty(meta)
        LUbounds=setupBounds(F+extractglobalboundsmeta(F),options,extendedvariables);
        boundsAlreadySet = 1;
        F = expandmeta(F);
    end
end

if isa(F,'constraint')
    F = lmi(F);
end

if nargin < 3
    options = sdpsettings;
end

if isempty(options)
    options = sdpsettings;
end

if isfield(options,'reusemodel')

else

    ALREADY_MODELLED = [];

    % Temporary hack to deal with a bug in CPLEX. For the implies operator (and
    % some more) YALMIP creates a dummy variable x with (x==1). Cplex fails
    % to solve problem with these stupid variables kept, hence we need to
    % remove these variables and constraints...
    MARKER_VARIABLES = [];

    % Temporary hack to deal with geometric programs. GPs are messy here,
    % becasue we can by mistake claim nonconvexity, since we may have no
    % sigmonial terms but indefinite quadratic term, but the whole problem is
    % meant to be solved using a GP solver. YES, globals suck, but this is
    % only temporary...hrm.
    DUDE_ITS_A_GP = 0;

    % Keep track of expressions that already have been modelled. Note that if a
    % graph-model already has been constructed but we now require a milp, for
    % numerical reasons, we should remove the old graph descriptions (important
    % for MPT models in particular)
    % FIX: Pre-parse the whole problem etc (solves the issues with GP also)
    ALREADY_MODELLED = {};
    ALREADY_MODELLED_INDEX = [];
    REMOVE_THESE_IN_THE_END = [];

    % Nonlinear operator variables are not allowed to be used in polynomial
    % expressions, except if they are exactly modelled, i.e. modelled using
    % MILP models. We will expand the model and collect variables that are in
    % polynomials, and check in the end if they are exaclty modelled
    OPERATOR_IN_POLYNOM = [];
end
% Assume success
failure = 0;
cause = '';

% Early bail out
if isempty(extendedvariables)
    return
end

if nargin < 4
    w = [];
end

if isempty(F) & isempty(h)
    return
end

% Check if it already has ben expanded in robustify or similar
F_alreadyexpanded = [];
if ~isempty(F)
    F_alreadyexpanded = [];
    already_expanded = expanded(F);
    if all(already_expanded)
        if isempty(setdiff(getvariables(h),expanded(h)))
            return
        end
    elseif any(already_expanded)
        F_alreadyexpanded = F(find(already_expanded));
        F = F(find(~already_expanded));
    end
end

if ~isempty(F)
    % Extract all simple bounds from the model, and update the internal bounds
    % in YALMIP. This is done in order to get tighter big-M models

    if boundsAlreadySet == 0;
        LUbounds = setupBounds(F,options,extendedvariables);
    end

    % Expand equalities first, since these might generate nonconvex models,
    % thus making it unnecessaryu to generate epigraphs etc
    equalities = is(F,'equality');
    if any(equalities)
        F = [F(find(equalities));F(find(~equalities))];
    end
end

% All variable indicies used in the problem
v1 = getvariables(F);
v2 = depends(F);
v3 = getvariables(h);
v4 = depends(h);

% HACK: Performance for LARGE-scale dualizations
if isequal(v3,v4) & isequal(v1,v2)
    variables = uniquestripped([v1 v3]);
else
    variables = uniquestripped([v1 v2 v3 v4]);
end

% Index to variables modeling operators
extended = find(ismembcYALMIP(variables,extendedvariables));

if nargin < 3
    options = sdpsettings;
end

% This is a tweak to allow epxansion of bilinear terms in robust problems,
% is expression such as abs(x*w) < 1 for all -1 < w < 1
% This field is set to 1 in robustify and tells YALMIP to skip checking for
% polynomial nonconvexity in the propagation
if ~isfield(options,'expandbilinear')
    options.expandbilinear = 0;
end

% Monomial information. Expensive to retrieve, so we pass this along
[monomtable,variabletype] = yalmip('monomtable');

% Is this trivially a GP, or meant to be at least?
if strcmpi(options.solver,'gpposy') | strcmpi(options.solver,'fmincon-geometric') | strcmpi(options.solver,'mosek-geometric')
    DUDE_ITS_A_GP = 1;
else
    if ~isequal(options.solver,'fmincon') & ~isequal(options.solver,'snopt') & ~isequal(options.solver,'ipopt') & ~isequal(options.solver,'') &  ~isequal(options.solver,'mosek')
        % User has specified some other solver, which does not
        % support GPs, hence it cannot be intended to be a GP
        DUDE_ITS_A_GP = 0;
    else
        % Check to see if there are any sigmonial terms on top-level
        DUDE_ITS_A_GP = ~isempty(find(variabletype(variables) == 4));
    end
end

% Constraints generated during recursive process to model operators
F_expand = ([]);

if isempty(F)
    F = ([]);
end

% First, check the objective
variables = uniquestripped([depends(h) getvariables(h)]);
monomtable = monomtable(:,extendedvariables);

% However, some of the variables are already expanded (expand can be called
% sequentially from solvemp and solverobust)
variables = setdiff1D(variables,expanded(h));

% Determine if we should aim for MILP/EXACT model directly
if options.allowmilp == 2
    method = 'exact';
else
    method = 'graph';
end

if DUDE_ITS_A_GP == 1
    options.allowmilp = 0;
    method = 'graph';
end

% Test for very common special case with only norm expression
ExtendedMap = yalmip('extendedmap');
fail = 0;
if  0%length(ExtendedMap) > 0 &&  all(strcmp('norm',{ExtendedMap.fcn}))
    for i = 1:length(ExtendedMap)
        if ~isequal(ExtendedMap(i).arg{2},2)
            fail = 1;
            break;
        end
        if ~isreal(ExtendedMap(i).arg{1})
            fail = 1;
            break;
        end
        if any(ismembcYALMIP(getvariables(ExtendedMap(i).arg{1}),extendedvariables))
             fail = 1;
            break;
        end
    end
    for i = 1:length(ExtendedMap)
        F_expand = [F_expand, cone(ExtendedMap(i).arg{1},ExtendedMap(i).var)];
    end
    F = F + lifted(F_expand,1);
    return
end
% *************************************************************************
% OK, looks good. Apply recursive expansion on the objective
% *************************************************************************
index_in_extended = find(ismembcYALMIP(variables,extendedvariables));
allExtStructs = yalmip('extstruct');
if ~isempty(index_in_extended)
    [F_expand,failure,cause] = expand(index_in_extended,variables,h,F_expand,extendedvariables,monomtable,variabletype,'objective',0,options,method,[],allExtStructs,w);
end

% *************************************************************************
% Continue with constraints
% *************************************************************************
constraint = 1;
all_extstruct = yalmip('extstruct');
while constraint <=length(F) & ~failure

    if ~already_expanded(constraint)
        Fconstraint = F(constraint);
        variables = uniquestripped([depends(Fconstraint) getvariables(Fconstraint)]);

        % If constraint is a cut, all generated constraints must be marked
        % as cuts too
        CONSTRAINTCUTSTATE =  getcutflag(Fconstraint);
        [ix,jx,kx] = find(monomtable(variables,:));
        if ~isempty(jx) % Bug in 6.1
            if any(kx>1)
                OPERATOR_IN_POLYNOM = [OPERATOR_IN_POLYNOM extendedvariables(jx(find(kx>1)))];
            end
        end

        index_in_extended = find(ismembcYALMIP(variables,extendedvariables));
        if ~isempty(index_in_extended)
            if is(Fconstraint,'equality')
                if options.allowmilp | options.allownonconvex
                    [F_expand,failure,cause] = expand(index_in_extended,variables,-sdpvar(Fconstraint),F_expand,extendedvariables,monomtable,variabletype,['constraint #' num2str(constraint)],0,options,'exact',[],allExtStructs,w);
                else
                    failure = 1;
                    cause = ['integer model required for equality in constraint #' num2str(constraint)];
                end
            else
                [F_expand,failure,cause] = expand(index_in_extended,variables,-sdpvar(Fconstraint),F_expand,extendedvariables,monomtable,variabletype,['constraint #' num2str(constraint)],0,options,method,[],allExtStructs,w);
            end
        end
    end
    constraint = constraint+1;
end

CONSTRAINTCUTSTATE = 0;

% *************************************************************************
% Temporary hack to fix the implies operator (cplex has some problem on
% these trivial models where a variable only is used in x==1
% FIX: Automatically support this type of nonlinear operators
% *************************************************************************
if ~isempty(MARKER_VARIABLES)
    MARKER_VARIABLES = sort(MARKER_VARIABLES);
    equalities = find(is(F,'equality'));
    equalities = equalities(:)';
    remove = [];
    for j = equalities
        v = getvariables(F(j));
        if length(v)==1
            if ismembcYALMIP(v,MARKER_VARIABLES)
                remove = [remove j];
            end
        end
    end
    if ~isempty(remove)
        F(remove) = [];
    end
end

nNow = yalmip('nvars');
if nNow > nInitial
    % YALMIP has introduced auxilliary variables
    % We mark these as auxilliary
    yalmip('addauxvariables',nInitial+1:nNow);
end

F_expand = lifted(F_expand,1);
% *************************************************************************
% We are done. We might have generated some stuff more than once, but
% luckily we keep track of these mistakes and remove them in the end (this
% happens if we have constraints like (max(x)<1) + (max(x)>0) where
% the first constraint would genrate a graph-model but the second set
% creates a integer model.
% *************************************************************************
if ~failure
    F = F + F_expand;
    if length(REMOVE_THESE_IN_THE_END) > 0
        F = F(find(~ismember(getlmiid(F),REMOVE_THESE_IN_THE_END)));
    end
end

% *************************************************************************
% Normally, operators are not allowed in polynomial expressions. We do
% however allow this if the variable has been modelled with an exact MILP
% model.
% *************************************************************************
if ~failure
    dummy = unique(OPERATOR_IN_POLYNOM);
    if ~isempty(dummy)
        for i = 1:length(dummy)
            aux(i,1) = find(ALREADY_MODELLED_INDEX == dummy(i));
        end
        %    Final_model = {ALREADY_MODELLED{unique(OPERATOR_IN_POLYNOM)}};
        Final_model = {ALREADY_MODELLED{aux}};
        for i = 1:length(Final_model)
            if ~(strcmp(Final_model{i}.method,'integer') | strcmp(Final_model{i}.method,'exact') | options.allownonconvex)
                failure = 1;
                cause = 'Nonlinear operator in polynomial expression.';
                return
            end
        end
    end
end

% Append the previously appended
F = F + F_alreadyexpanded;
% Declare this model as expanded
F = expanded(F,1);

function [F_expand,failure,cause] = expand(index_in_extended,variables,expression,F_expand,extendedvariables,monomtable,variabletype,where,level,options,method,extstruct,allExtStruct,w)
global DUDE_ITS_A_GP ALREADY_MODELLED ALREADY_MODELLED_INDEX REMOVE_THESE_IN_THE_END OPERATOR_IN_POLYNOM

% *************************************************************************
% Go through all parts of expression to check for convexity/concavity
% First, a small gateway function before calling the recursive stuff
% *************************************************************************
if ~DUDE_ITS_A_GP
    [ix,jx,kx] = find(monomtable(variables,:));
    if ~isempty(jx) % Bug in 6.1
        if any(kx>1)
            OPERATOR_IN_POLYNOM = [OPERATOR_IN_POLYNOM extendedvariables(jx(find(kx>1)))];
        end
    end
end

failure = 0;
j = 1;

try
    % Optimized for 6.5 and higher (location in ismember). If user has
    % older version, it will crash and go to code below
    expression_basis = getbase(expression);
    expression_vars  = getvariables(expression);
    [yesno,location] = ismember(variables(index_in_extended),expression_vars);
    ztemp = recover(variables(index_in_extended));
    while j<=length(index_in_extended) & ~failure
        % i = index_in_extended(j);
        % zi = recover(variables(i));
        zi = ztemp(j);%recover(variables(i));
        basis = expression_basis(:,1 + location(j));
        if all(basis == 0) % The nonlinear term is inside a monomial
            if options.allownonconvex
                [F_expand,failure,cause] = expandrecursive(zi,F_expand,extendedvariables,monomtable,variabletype,where,level+1,options,'exact',[],'exact',allExtStruct,w);
            else
                failure = 1;
                cause = 'Possible nonconvexity due to operator in monomial';
            end
            %[F_expand,failure,cause] = expandrecursive(zi,F_expand,extendedvariables,monomtable,variabletype,where,level+1,options,method,[],'exact',allExtStruct,w);
        elseif all(basis >= 0)
            [F_expand,failure,cause] = expandrecursive(zi,F_expand,extendedvariables,monomtable,variabletype,where,level+1,options,method,[],'convex',allExtStruct,w);
        else
            [F_expand,failure,cause] = expandrecursive(zi,F_expand,extendedvariables,monomtable,variabletype,where,level+1,options,method,[],'concave',allExtStruct,w);
        end
        j=j+1;
    end
catch
    while j<=length(index_in_extended) & ~failure
        i = index_in_extended(j);
        basis = getbasematrix(expression,variables(i));
        if all(basis >= 0)
            [F_expand,failure,cause] = expandrecursive(recover(variables(i)),F_expand,extendedvariables,monomtable,variabletype,where,level+1,options,method,[],'convex',allExtStruct,w);
        else
            [F_expand,failure,cause] = expandrecursive(recover(variables(i)),F_expand,extendedvariables,monomtable,variabletype,where,level+1,options,method,[],'concave',allExtStruct,w);
        end
        j=j+1;
    end
end


function [Iex,Iexmask,Icb,Icbmask] = esvm_get_exemplar_icon(models, ...
                                                  index,flip,subind, ...
                                                  loadseg, VOCopts)
% Extract an exemplar visualization image (one from gt box, one from
% cb box) [and does flip if specified]
% Allows allows for the loading of a segmentation too
% NOTE(TJM): this function works, but needs cleanup
%
% Copyright (C) 2011-12 by Tomasz Malisiewicz
% All rights reserved.
%
% This file is part of the Exemplar-SVM library and is made
% available under the terms of the MIT license (see COPYING file).
% Project homepage: https://github.com/quantombone/exemplarsvm

if ~isfield(models{index}.model,'bb') || numel(models{index}.model.bb)==0
  Iex = ones(10,10,3);
  Iexmask = ones(10,10,1);
  Icb = ones(10,10,3);
  Icbmask = ones(10,10,1);
  return;
end

%Subind indicates which window to show (defaults to the base)
if ~exist('subind','var')
  subind = 1;
%else
%  flip = models{index}.model.bb(subind,7);
end

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

if ~exist('loadseg','var')
  loadseg = 1;
end

%cb = models{index}.model.bb(subind,1:4);
%TJM: changed
cb = models{index}.gt_box;
d1 = max(0,1 - cb(1));
d2 = max(0,1 - cb(2));
d3 = max(0,cb(3) - models{index}.sizeI(2));
d4 = max(0,cb(4) - models{index}.sizeI(1));
mypad = max([d1,d2,d3,d4]);
PADDER = round(mypad)+2;

if isfield(models{index},'I')
  I = convert_to_I(models{index}.I);
else
  I = ...
      convert_to_I(models{index}.train_set{models{index}.model.bb(subind,11)});
end
%pre-pad mask because GT region can be outside image
mask = pad_image(zeros(size(I,1),size(I,2)),PADDER);
g = models{index}.gt_box;
g2 = g + PADDER;
mask(g2(2):g2(4),g2(1):g2(3)) = 1;

if loadseg == 1 && exist('VOCopts','var')
  try
    %NOTE(TJM): this is voc-only and should not be here in the most
    %general scenario
    [I2, mask2] = load_seg(VOCopts,models{index});
    if numel(I2) > 0
      I = I2;
      mask = mask2;
    end
  catch
  end
end

cb = models{index}.gt_box;
Iex = pad_image(I, PADDER);
Iexmask = pad_image(mask,PADDER);
cb = round(cb + PADDER);

Iex = Iex(cb(2):cb(4),cb(1):cb(3),:);
Iexmask = Iexmask(cb(2):cb(4),cb(1):cb(3));

cb = models{index}.model.bb(subind,1:4);
Icb = pad_image(I, PADDER);
cb = round(cb + PADDER);
Icb = Icb(cb(2):cb(4),cb(1):cb(3),:);
Icbmask = mask(cb(2):cb(4),cb(1):cb(3));

if flip == 1
  Iex = flip_image(Iex);
  Icb = flip_image(Icb);
  Iexmask = flip_image(Iexmask);
  Icbmask = flip_image(Icbmask);
end

function [I, mask] = load_seg(VOCopts, model)

filer = sprintf('%s/%s/SegmentationObject/%s.png',VOCopts.datadir, ...
                VOCopts.dataset,model.curid);

filer_class = sprintf('%s/%s/SegmentationClass/%s.png',VOCopts.datadir, ...
                      VOCopts.dataset,model.curid);

cmap=VOClabelcolormap;

if ~fileexists(filer)
  I = [];
  mask = [];
  return;
end

classes = {'aeroplane','bicycle','bird','boat','bottle','bus', ...
           'car','cat','chair','cow','diningtable','dog','horse', ...
           'motorbike','person','pottedplant','sheep','sofa', ...
           'train','tvmonitor'};

clsid = find(ismember(classes,model.cls));

has_seg = 1;
res = imread(filer);
res_class = imread(filer_class);
res_class = reshape(cmap(res_class(:)+1,:),size(res_class,1), ...
                    size(res_class,2),3);

mask = double((res==model.objectid));
I= res_class;


function res = isreal(Y)
%ISREAL (overloaded)

res = isreal(Y.basis);


function response = Craby(n,prev)

if n>4 && n<9 || n==1 || n>18
    response = 'cooperate';
else
    response = 'defect';
end


function K = set_params_kernel(K, name, val)
% SET_PARAMS_KERNEL Accessor function for a field (table_kernel)
% K = set_params_kernel(K, name, val)
%
% e.g., K = set_params_kernel(K, 'table', rand(2,3,2)) for a kernel on 3 nodes with 2,3,2 values each

% We should check if the arguments are valid...

switch name
 case 'table', K.table = val;
 otherwise,
  error(['invalid field name ' name]);
end


function ok=validatenodes(t,j)
%VALIDATENODES Validate array of node numbers
%   OK=VALIDATENODES(T,J) returns true if J is a valid array of node
%   numbers or logical array for indexing into an object having a leading
%   dimension with one element per node in the array T.

%   Copyright 2006-2007 The MathWorks, Inc.
%   $Revision: 1.1.6.2 $  $Date: 2007/02/15 21:48:15 $

numnodes = numel(t.node);
if islogical(j)
    ok = (numel(j) <= numnodes);
else
    ok = ismember(j,1:numnodes);
    ok = all(ok(:));
end


function tc_saveParfiles(tc);
% tc_saveParfiles(tc);
%
% Time Course UI: save parfiles specified in tc struct.
%
% If an onset shift is specified in the 'onsetDelta' param, this is
% applied to the parfiles before saving.
%
% 07/04 ras.
global HOMEDIR;

dlgTitle = 'Save parfiles...';
for i = 1:length(tc.params.parfiles)
    prompt{i} = sprintf('Scan %i parfile name:',tc.params.scans(i));
    defaults{i} = tc.params.parfiles{i};
end

answer = inputdlg(prompt,dlgTitle,1,defaults);

scans = tc.params.scans;

for i = 1:length(answer)
    ind = find(tc.trials.run==i);
    par.cond = tc.trials.cond(ind);
    D = tc.params.onsetDelta;
    if i==1
        par.onset = tc.trials.onsetSecs(ind) + D;
    else
        par.onset = tc.trials.onsetSecs(ind) + D - tc.trials.onsetSecs(ind(1));
    end
    par.label = tc.trials.label(ind);
    par.color = cell(size(par.label));

    % use the currently-assigned cond names for the first label
    % for each condition
    for c = unique(par.cond)
        subind = find(par.cond==c);
        par.label{subind(1)} = tc.trials.condNames{find(tc.trials.condNums==c)};
        par.color{subind(1)} = tc.trials.condColors{find(tc.trials.condNums==c)};
    end

    parPath = fullfile(parfilesDir(initHiddenInplane), answer{i});
    writeParfile(par, parPath);
end

% because we applied the onset shift in the parfiles, we can set the
% onsetDelta param back to 0, and save it, so we don't shift twice:
if tc.params.onsetDelta ~= 0
    tc.params.onsetDelta = 0;
    hI = initHiddenInplane(tc.params.dataType, tc.params.scans(1));
    er_setParams(hI, tc.params);
end

return


function overlayMaps(vw,map1,map2,anatFlag,map1Name,map2Name)
%
% overlayMaps(view,map1,map2,[anatFlag],[map1Name,map2Name]);
%
% Given two volumes containing values
% relevant for the current view (such
% as param maps, corAnal fields, etc),
% grab the relevant anatomical images from
% the view, take into account relevant
% clip values, zoom, and other factors, and
% overlay using the overlayVolumes GUI.
%
% map1Name and map2Name are optional strings
% specifying the names to use in the
% GUI for the two volumes.
%
%
% ras 04/02/2005
if ieNotDefined('map1Name')
    map1Name = inputname(2);
end

if ieNotDefined('map2Name')
    map2Name = inputname(3);
end

if ieNotDefined('anatFlag')
    anatFlag = 1;
end

if anatFlag==1
    % initialize anatomy
	viewType = viewGet(vw,'viewType');
	switch viewType
        case {'Inplane','Flat'},
            nSlices = numSlices(vw);
            for i = 1:nSlices
                bg(:,:,i) = recomputeAnatImage(vw,[],i);
            end

        case {'Volume','Gray'},
            bg = viewGet(vw,'anat');
            ori = getCurSliceOri(vw);
            if ori==1, % permute to axial view
                bg = permute(bg,[2 3 1]);
            elseif ori==2, % permute to coronal view
                bg = permute(bg,[1 3 2]);
            end
	end

    % resize overlay volumes to be same size as bg
    switch viewType
        case {'Inplane'},
            vs = viewGet(vw,'Size');
            for i = 1:vs(3)
                tmp1(:,:,i) = imresize(map1(:,:,i),[vs(1) vs(2)]);
                tmp2(:,:,i) = imresize(map2(:,:,i),[vs(1) vs(2)]);
            end
            map1 = tmp1; map2 = tmp2; clear tmp1 tmp2;

        case {'Volume','Gray','volume3View'},
            coords = canOri2CurOri(vw,vw.coords);
            ind = sub2ind(size(bg),coords(1,:),coords(2,:),coords(3,:));

            tmp1 = zeros(size(bg));
            tmp1(ind) = map1;
            map1 = tmp1;
            clear tmp1;

            tmp2 = zeros(size(bg));
            tmp2(ind) = map2;
            map2 = tmp2;
            clear tmp2;

            if isfield(vw.ui,'flipLR') & vw.ui.flipLR==1
                map1 = flipdim(map1,2);
                map2 = flipdim(map2,2);
                bg = flipdim(bg,2);
            end

        case {'Flat'},
            % threshold to see sulci/gyri clearly
            thresh = 0.5 .* max(bg(:));
            lightRng = [0.6 0.8] .* max(bg(:));
            darkRng = [0.2 0.4] .* max(bg(:));
            bg(bg < thresh) = normalize(bg(bg < thresh),darkRng(1),darkRng(2));
            bg(bg >= thresh) = normalize(bg(bg >= thresh),lightRng(1),lightRng(2));
    end

    % apply a zoom, if specified in ui
    ui = viewGet(vw,'ui');
    if isfield(ui,'zoom')
        switch viewType
            case {'Inplane','Flat'},
                zoom = round(ui.zoom);
                xrng = zoom(1):zoom(2);
                yrng = zoom(3):zoom(4);
                map1 = map1(yrng,xrng,:);
                map2 = map2(yrng,xrng,:);
                bg = bg(yrng,xrng,:);
            case {'Volume','Gray'},
                zoom = round(ui.zoom);
                ap = zoom(1,1):zoom(1,2);
                si = zoom(2,1):zoom(2,2);
                rl = zoom(3,1):zoom(3,2);
                map1 = map1(ap,si,rl);
                map2 = map2(ap,si,rl);
                bg = bg(ap,si,rl);
        end
    end

    bg = brighten(bg,0.5);

    overlayVolumes(map1,map2,bg,[],'map1Name',map1Name,'map2Name',map2Name);
else
    overlayVolumes(map1,map2,[],[],'map1Name',map1Name,'map2Name',map2Name);
end

return


function [data] = ft_rejectcomponent(cfg, comp, data)

% FT_REJECTCOMPONENT backprojects an ICA (or similar) decomposition to the
% channel level after removing the independent components that contain
% the artifacts. This function does not automatically detect the artifact
% components, you will have to do that yourself.
%
% Use as
%    [data] = ft_rejectcomponent(cfg, comp)
% or as
%    [data] = ft_rejectcomponent(cfg, comp, data)
%
% where the input comp is the result of FT_COMPONENTANALYSIS. The output
% data will have the same format as the output of FT_PREPROCESSING.
%
% An optional input argument data can be provided. In that case
% componentanalysis will do a subspace projection of the input data
% onto the space which is spanned by the topographies in the unmixing
% matrix in comp, after removal of the artifact components.  Please use
% this option of including data as input, if you wish to use the output
% data.grad in further computation, for example for leadfield computation.
%
% The configuration structure can contain
%   cfg.component  = list of components to remove, e.g. [1 4 7] or see FT_CHANNELSELECTION
%   cfg.demean     = 'no' or 'yes', whether to demean the input data (default = 'yes')
%   cfg.updatesens = 'no' or 'yes' (default = 'yes')
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
%   cfg.outputfile  =  ...
% If you specify one of these (or both) the input data will be read from a *.mat
% file on disk and/or the output data will be written to a *.mat file. These mat
% files should contain only a single variable, corresponding with the
% input/output structure.
%
% See also FT_COMPONENTANALYSIS, FT_PREPROCESSING

% Copyright (C) 2005-2014, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% these are used by the ft_preamble/ft_postamble function and scripts
ft_revision = '$Id$';
ft_nargin   = nargin;
ft_nargout  = nargout;

% do the general setup of the function
ft_defaults
ft_preamble init
ft_preamble debug
ft_preamble loadvar comp data
ft_preamble provenance comp data

% the ft_abort variable is set to true or false in ft_preamble_init
if ft_abort
  return
end

% set the defaults
cfg.component       = ft_getopt(cfg, 'component',  []);
cfg.demean          = ft_getopt(cfg, 'demean',     'yes');
cfg.feedback        = ft_getopt(cfg, 'feedback',   'text');
cfg.updatesens      = ft_getopt(cfg, 'updatesens', 'yes');

% the data can be passed as input arguments or can be read from disk
hascomp = exist('comp', 'var');
hasdata = exist('data', 'var');

if hascomp && hasdata
  % check if the input data is valid for this function
  istlck  = ft_datatype(data, 'timelock');  % this will be temporary converted into raw
  data    = ft_checkdata(data, 'datatype', 'raw');
  comp    = ft_checkdata(comp, 'datatype', 'comp');
  label   = data.label;
  nchans  = length(data.label);
  ncomps  = length(comp.label);
elseif hascomp
  % check if the input data is valid for this function
  istlck  = ft_datatype(comp, 'timelock');  % this will be temporary converted into raw
  comp    = ft_checkdata(comp, 'datatype', 'raw+comp');
  label   = comp.topolabel;
  ncomps  = length(comp.label);
else
  ft_error('incorrect number of input arguments');
end

% cfg.component can be indicated by number or by label
cfg.component = ft_channelselection(cfg.component, comp.label);
reject = match_str(comp.label, cfg.component);

if isempty(reject)
  ft_warning('no components were selected for rejection');
end

if min(reject)<1
  ft_error('you cannot remove components that are not present in the data');
end

if max(reject)>ncomps
  ft_error('you cannot remove components that are not present in the data');
end

if hasdata && strcmp(cfg.demean, 'yes')
  % optionally perform baseline correction on each trial
  ft_info('baseline correcting data \n');
  for trial=1:numel(data.trial)
    data.trial{trial} = ft_preproc_baselinecorrect(data.trial{trial});
  end
end

% set the rejected component amplitudes to zero
ft_info('removing %d components\n', length(reject));
ft_info('keeping %d components\n',  ncomps-length(reject));

% create a projection matrix by subtracting the subspace spanned by the
% topographies of the to-be-removed components from identity
[seldat, selcomp] = match_str(label, comp.topolabel);

if hasdata && length(seldat)~=length(label)
  ft_warning('the subspace projection is not guaranteed to be correct for non-orthogonal components');
end

if hasdata
  mixing   = comp.topo(selcomp,:);
  unmixing = comp.unmixing(:,selcomp);

  % I am not sure about this, but it gives comparable results to the ~hasdata case
  % when comp contains non-orthogonal (=ica) topographies, and contains a complete decomposition

  montage     = [];
  montage.tra = eye(length(selcomp)) - mixing(:, reject)*unmixing(reject, :);
  % we are going from data to components, and back again
  montage.labelold = comp.topolabel(selcomp);
  montage.labelnew = comp.topolabel(selcomp);

  keepunused = 'yes'; % keep the original data which are not present in the mixing provided
  bname = 'reject';

else
  mixing = comp.topo(selcomp, :);
  mixing(:, reject) = 0;

  montage     = [];
  montage.tra = mixing;
  % we are going from components to data
  montage.labelold = comp.label;
  montage.labelnew = comp.topolabel(selcomp);

  keepunused = 'no'; % don't need to keep the original rejected components
  bname = 'invcomp';

  % create the initial data structure, remove all component details
  data = keepfields(comp, {'trial', 'time', 'label', 'fsample', 'grad', 'elec', 'opto', 'trialinfo', 'sampleinfo'});
end % if hasdata

% apply the linear projection to the data
data = ft_apply_montage(data, montage, 'keepunused', keepunused, 'feedback', cfg.feedback, 'showcallinfo', cfg.showcallinfo);

sensfield = cell(0,1);
if isfield(data, 'grad')
  sensfield{end+1} = 'grad';
end
if isfield(data, 'elec')
  sensfield{end+1} = 'elec';
end
if isfield(data, 'opto')
  sensfield{end+1} = 'opto';
end

% apply the linear projection also to the sensor description
if ~isempty(sensfield)
  if  strcmp(cfg.updatesens, 'yes')

    for m = 1:numel(sensfield)
      ft_info('also applying the backprojection matrix to the %s structure\n', sensfield{m});

      % the balance field is needed to keep the sequence of linear projections
      if ~isfield(data.(sensfield{m}), 'balance')
        data.(sensfield{m}).balance.current = 'none';
      end

      % keepunused = 'yes' is required to get back e.g. reference or otherwise
      % unused sensors in the sensor description. the unused components need to
      % be removed in a second step
      sens = ft_apply_montage(data.(sensfield{m}), montage, 'keepunused', 'yes', 'balancename', bname, 'feedback', cfg.feedback);

      % remove the unused channels from the grad/elec/opto
      [junk, remove]    = match_str(comp.label, sens.label);
      sens.tra(remove,:) = [];
      sens.label(remove) = [];
      sens.chanpos(remove,:) = [];
      if isfield(sens, 'chanori')
        sens.chanori(remove,:) = [];
      end

      % there could have been sequential subspace projections, so the
      % invcomp-field may have been renamed into invcompX. If this it the case,
      % take the one with the highest suffix
      invcompfield = bname;
      if  ~isfield(sens.balance, invcompfield)
        for k = 10:-1:1
          if isfield(sens.balance, [bname num2str(k)])
            invcompfield = [invcompfield num2str(k)];
            break;
          end

        end
      end

      % remove the unused components from the balancing
      [junk, remove]    = match_str(comp.label, sens.balance.(invcompfield).labelnew);
      sens.balance.(invcompfield).tra(remove, :)   = [];
      sens.balance.(invcompfield).labelnew(remove) = [];
      data.(sensfield{m})  = sens;
    end

  else
    for m = 1:numel(sensfield)
      ft_info('not applying the backprojection matrix to the %s structure\n', sensfield{m});
      % simply copy it over
      comp.(sensfield{m}) = data.(sensfield{m});
    end
  end
end % if sensfield

if istlck
  % convert the raw structure back into a timelock structure
  data = ft_checkdata(data, 'datatype', 'timelock');
end

% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug
ft_postamble previous   comp data
ft_postamble provenance data
ft_postamble history    data
ft_postamble savevar    data


function imdb = getMLIVEDatabase_train(Dir)

Scores1 = load([Dir, '\Part 1\Scores.mat']);
imdb.dmos1 = Scores1.DMOSscores;
Scores2 = load([Dir, '\Part 2\Scores.mat']);
imdb.dmos2 = Scores2.DMOSscores;

Imagelists1 = load([Dir, '\Part 1\Imagelists.mat']);
refnames1 = Imagelists1.refimgs;
distimgs1 = Imagelists1.distimgs;
ref4dist1 = Imagelists1.ref4dist;
Imagelists2 = load([Dir, '\Part 2\Imagelists.mat']);
refnames2 = Imagelists2.refimgs;
distimgs2 = Imagelists2.distimgs;
ref4dist2 = Imagelists2.ref4dist;

imdb.dmos = [imdb.dmos1,imdb.dmos2];

imdb.dir_dist1 = cell(1,225);
for i = 1:225
    imdb.dir_dist1{1,i} = fullfile('Part 1\blurjpeg',distimgs1{i,1});
end
imdb.dir_dist2 = cell(1,225);
for i = 1:225
    imdb.dir_dist2{1,i} = fullfile('Part 2\blurnoise',distimgs2{i,1});
end

imdb.imgDir =  cat(2,imdb.dir_dist1,imdb.dir_dist2);
imdb.dataset = 'MLIVE';
imdb.filenum = 450;

imdb.dmosall = imdb.dmos;
imdb.refnum = 15;
for i = 1:15
    imdb.refname{i} = num2str(i);
end
for i = 1:225
    imdb.refnames_all{i} = num2str(ref4dist1(i));
end
for i = 226:450
    imdb.refnames_all{i} = num2str(ref4dist2(i-225));
end

sel = randperm(15);
% sel = 1:15;
train_path = [];
train_dmos = [];
for i = 1:12
    train_sel = strcmpi(imdb.refname(sel(i)),imdb.refnames_all);
    train_sel = find(train_sel == 1);
    train_path = [train_path, imdb.imgDir(train_sel)];
    train_dmos = [train_dmos,imdb.dmos(train_sel)];
end

test_path = [];
test_dmos = [];
for i = 13:15
    test_sel = strcmpi(imdb.refname(sel(i)),imdb.refnames_all);
    test_sel = find(test_sel == 1);
    test_path = [test_path, imdb.imgDir(test_sel)];
    test_dmos = [test_dmos,imdb.dmos(test_sel)];
end

imdb.images.id = 1:450 ;
imdb.images.set = [ones(1,size(train_path,2)),2*ones(1,size(test_path,2))];
imdb.images.label = [train_dmos,test_dmos];
imdb.classes.description = {'MLIVE'};
imdb.images.name = [train_path,test_path] ;
imdb.imageDir = Dir;


function eventLog = ma_executeBasicMassDump(massDumpEvent, initialState, eventNum)
%ma_executeMassDump Summary of this function goes here
%   Detailed explanation goes here

    ut = initialState(1);
    rVectUT = initialState(2:4);
    vVectUT = initialState(5:7);
    bodyID = initialState(8);

    dmasses = massDumpEvent.dumpValue;
    masses = initialState(9:12) - dmasses;

    eventLog(1,:) = [ut, rVectUT, vVectUT, bodyID, masses, eventNum];
end