function matlab_install(SuiteSparse_path)
%  Matlab function to compile all the c-files to mex in the GPstuff toolbox.
%
%  Some of the sparse GP functionalities in the toolbox require
%  SuiteSparse toolbox by Tim Davis:
%    http://www.cise.ufl.edu/research/sparse/SuiteSparse/current/SuiteSparse/
%
%  This package includes the SuiteSparse version 4.4.2.
%
%  * To install without SuiteSparse run matlab_install
%  * To install with SuiteSparse run matlab_install('SuiteSparseOn')
%
%   The function matlab_install compiles the mex-files and prints on
%   the screen, which directories should be added to Matlab paths.

% Copyright (c) 2008-2012, 2016 Jarno Vanhatalo
% Copyright (c) 2016            Eero Siivola

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

    if nargin < 1
        SuiteSparse_path = [];
        fprintf('\n The path to the SuiteSparse package is not provided. \n')
        fprintf('\n Installing GPstuff without compactly supported covariance functions. \n')
        fprintf(' You are not able to use the following covariance functions:  \n')
        fprintf(' gpcf_ppcs0  \n gpcf_ppcs1 \n gpcf_ppcs2 \n gpcf_ppcs3 \n\n\n')
    elseif strcmp(SuiteSparse_path, 'SuiteSparseOn')
        cdir = pwd;
        cd SuiteSparse % Change this to correspond your own settings!
        SuiteSparse_path = path_spaces([pwd '/']);

        % Compile SuiteSparse
        fprintf('Compiling SuiteSparse. This may take a while \n \n')
        SuiteSparse_install(false);

        paths{1} = SuiteSparse_path;
        paths{2} = [SuiteSparse_path 'UMFPACK/MATLAB'];
        paths{3} = [SuiteSparse_path 'CHOLMOD/MATLAB'];
        paths{4} = [SuiteSparse_path 'AMD/MATLAB'];
        paths{5} = [SuiteSparse_path 'COLAMD/MATLAB'];
        paths{6} = [SuiteSparse_path 'CCOLAMD/MATLAB'];
        paths{7} = [SuiteSparse_path 'CAMD/MATLAB'];
        paths{8} = [SuiteSparse_path 'CXSparse/MATLAB/Demo'];
        paths{9} = [SuiteSparse_path 'CXSparse/MATLAB/CSparse'];
        paths{10} = [SuiteSparse_path 'LDL/MATLAB'];
        paths{11} = [SuiteSparse_path 'BTF/MATLAB'];
        paths{12} = [SuiteSparse_path 'KLU/MATLAB'];
        paths{13} = [SuiteSparse_path 'SPQR/MATLAB'];
        paths{14} = [SuiteSparse_path 'RBio/RBio'];
        paths{15} = [SuiteSparse_path 'MATLAB_Tools'];
        paths{16} = [SuiteSparse_path 'MATLAB_Tools/Factorize'];
        paths{17} = [SuiteSparse_path 'MATLAB_Tools/MESHND'];
        paths{18} = [SuiteSparse_path 'MATLAB_Tools/LINFACTOR'];
        paths{19} = [SuiteSparse_path 'MATLAB_Tools/find_components'];
        paths{20} = [SuiteSparse_path 'MATLAB_Tools/GEE'];
        paths{21} = [SuiteSparse_path 'MATLAB_Tools/shellgui'];
        paths{22} = [SuiteSparse_path 'MATLAB_Tools/waitmex'];
        paths{23} = [SuiteSparse_path 'MATLAB_Tools/spqr_rank'];
        paths{24} = [SuiteSparse_path 'MATLAB_Tools/spqr_rank/SJget'];
        paths{25} = [SuiteSparse_path 'MATLAB_Tools/UFcollection'];
        paths{26} = [SuiteSparse_path 'MATLAB_Tools/SSMULT'];
        paths{27} = [SuiteSparse_path 'MATLAB_Tools/dimacs10'];
        paths{28} = [SuiteSparse_path 'MATLAB_Tools/spok'];
        paths{29} = [SuiteSparse_path 'MATLAB_Tools/sparseinv'];

        cd(cdir)
        fprintf('Compiling GPstuff. This may take a while \n \n')
    else
        error('Unknown input argument. See help matlab_install for usage.')
    end

    % Go to diag/ and compile the mex-functions
    fprintf('\n Compiling files in diag.\n \n')
    cd('diag')
    diag_install
    cd('..')

    % Go to dist/ and compile the mex-functions
    fprintf('\n Compiling files in dist.\n \n')
    cd('dist')
    dist_install
    cd('..')

    % Go to gp/ and compile the mex-functions
    fprintf('\n Compiling files in gp.\n \n')
    cd('gp')
    gp_install(SuiteSparse_path)
    cd('..')

    % Go to mc/ and compile the mex-functions
    fprintf('\n Compiling files in mc. \n \n')
    cd('mc')
    mc_install
    cd('..')

    PP = pwd;
    S{1} = [PP '/diag'];
    S{2} = [PP '/dist'];
    S{3} = [PP '/gp'];
    S{4} = [PP '/mc'];
    S{5} = [PP '/misc'];
    S{6} = [PP '/optim'];
    S{7} = [PP '/tests'];

    fprintf ('\n The following paths have been added.  You may wish to add them\n') ;
    fprintf ('permanently, using the MATLAB pathtool command or copying the below\n') ;
    fprintf ('lines to your startup.m file. \n\n');
    for i = 1:length(S)
       addpath(S{i});
       fprintf ('addpath %s\n', S{i}) ;
    end

    if nargin==1
        fprintf ('\n')
        for k = 1:length (paths)
            fprintf ('addpath %s\n', paths {k}) ;
        end
    end
end

function path = path_spaces(path)
% Build correct path if path includes spaces

space_ind=strfind(path, ' ');
path=strrep(path, ' ', ''' ');
space_ind=space_ind+length(space_ind);
for i=1:length(space_ind)

  indd=strfind(path(space_ind(i):end), '/');
  path=[path(1:space_ind(i)+indd(1)-2) '''/' path(space_ind(i)+indd(1):end)];
  space_ind=space_ind+1;

end

end


function results = mapRxnsViaMets(model,mnx,mapRxns)
%mapRxnsViaMets  Map model reactions to MNX database via metabolite MNXIDs.
%
% mapRxnsViaMets searches an MNX database structure for reactions that
% share the same set of metabolites as reactions in model, and returns the
% corresponding MNX reaction IDs and reaction equations. The mapping is
% performed by looking for any MNX reactions that contain the same set of
% metabolite MNX IDs as a model reaction, meaning that STOICHIOMETRY
% COEFFICIENTS ARE IGNORED.
%
% This function can also handle model metabolites associated with multiple
% MNX IDs. In this case, only one of the multiple met IDs for a particular
% metabolite need to match a metabolite in the corresponding MNX reaction.
%
% USAGE:
%
%   results = mapRxnsViaMets(model,mnx,mapRxns)
%
% INPUT:
%
%   model    Model structure.
%
%   mnx      (Optional, will be generated if not provided) MNX database
%            structure, generated using the following command:
%            mnx = buildMNXmodel('both');
%
%   mapRxns  (Optional, Default = all reactions) A logical vector of the
%            same size as model.rxns, indicating which reactions should be
%            mapped. Reactions corresponding to mapRxns entries that are
%            FALSE will be skipped.
%
% OUTPUT:
%
%   results  A results structure with the following fields:
%
%       rxnMNXID: A column cell array containing the MNX IDs mapped to each
%                 reaction. For reactions to which multiple MNX IDs were
%                 mapped, the corresponding rxnMNXID entry will be a nested
%                 cell of MNX IDs.
%
%      rxnMNXeqn: A column cell array containing the reaction equations
%                 from the MNX database that correspond to the MNX ID(s)
%                 mapped to each model reaction.
%
%          notes: A column of strings providing information on if and how
%                 each model reaction was mapped to any MXN ID(s).
%

% handle input arguments
if nargin < 3
    mapRxns = true(size(model.rxns));
elseif ~isequal(size(mapRxns),size(model.rxns))
    error('mapRxns input must have same dimensions as model.rxns');
end
if nargin < 2
    mnx = [];
end

% initialize results structure
results.rxnMNXID = {};
results.rxnMNXeqn = {};
results.notes = repmat({''},size(model.rxns));
results.notes(~mapRxns) = {'IGNORED'};

%% Prepare model and MNX structures for processing

fprintf('Pre-processing model and MNX structures... ');

% if the model.metMNXID field contains multiple columns, convert it to a
% single column of nested cells
if size(model.metMNXID,2) > 1
    model.metMNXID = nestCell(model.metMNXID,true);
elseif all(cellfun(@ischar,model.metMNXID)) && any(contains(model.metMNXID,';'))
    empty_inds = cellfun(@isempty,model.metMNXID);
    model.metMNXID = cellfun(@(id) strsplit(id,';\s*','DelimiterType','RegularExpression'),model.metMNXID,'UniformOutput',false);
    model.metMNXID(empty_inds) = {''};  % to deal with cells that should be empty, but are recognized as non-empty
end

% generate binary (logical) version of S-matrix indicating which mets are
% involved in each rxn
S = (full(model.S) ~= 0);

% do not try to map model rxns that contain a metabolite without an MNXID
met_noID = cellfun(@isempty,model.metMNXID);
rxn_noID = any(S(met_noID,:),1)';
results.notes(mapRxns & rxn_noID) = {'SKIPPED: one or more mets lacking MNXID'};
mapRxns(rxn_noID) = false;

% Create an additional field in model that lists all possible metMNXIDs
% associated with each reaction.
for i = 1:length(model.rxns)
    model.rxnMetsMNX{i,1} = unique(horzcat(model.metMNXID{S(:,i)}));
end

% For faster processing later on, remove all rxns in the MNX structure that
% contain at least one metabolite that is not present in the model.

% get list of all metMNXIDs in the model (for reactions to be mapped)
met_inds = any(S(:,mapRxns),2);
allMetMNXIDs = unique(horzcat(model.metMNXID{met_inds}))';
allMetMNXIDs(cellfun(@isempty,allMetMNXIDs)) = [];

% load MNX database structure if not provided as input
if isempty(mnx)
    fprintf('MNX database structure not provided. It will be loaded.\n\n');
    mnx = buildMNXmodel('both');
end

% flatten mnx.rxnMets (single column -> multi column cell array)
mnx.rxnMets = flattenCell(mnx.rxnMets,true);

% find MNX rxns with mets that aren't present in model
mismatches = ~ismember(mnx.rxnMets,allMetMNXIDs);
mismatches(cellfun(@isempty,mnx.rxnMets)) = false;
del_rxns = any(mismatches,2);

% restore mnx.rxnMets to its original format of a column of nested cells
mnx.rxnMets = nestCell(mnx.rxnMets,true);

% remove reactions from MNX structure
nrxns = length(mnx.rxns);
f = fields(mnx);
for i = 1:length(f)
    if iscell(mnx.(f{i})) && size(mnx.(f{i}),1) == nrxns
        mnx.(f{i})(del_rxns,:) = [];
    end
end

% initialize rxn MNX IDs
rxnMNXID = repmat({''},size(model.rxns));

fprintf('Done.\n');

%% STAGE 1: Find exact matches to MNX reactions that are balanced

fprintf('Searching for exact, balanced rxn matches... ');

% subset MNX structure to include only the balanced reactions
mnx_bal = mnx;
unbal = ~ismember(mnx_bal.rxnBalanced,'true');
mnx_bal.rxns(unbal) = [];
mnx_bal.rxnMets(unbal) = [];

% map reactions
rxnMNXID(mapRxns) = findMNXrxns(model,mnx_bal,mapRxns);

% find newly mapped rxns
newMapped = mapRxns & ~cellfun(@isempty,rxnMNXID);
results.notes(newMapped) = {'MATCH: exact'};
mapRxns(newMapped) = false;  % update to ignore rxns that are now mapped

% clear MNX structure to free up some memory
clear mnx_bal

fprintf('Done.\n');

%% STAGE 2: Ignore protons (H+) and water (H2O) in reaction equations

fprintf('Searching for matches, ignoring balance status, protons (H+), and water (H2O)... ');

% remove H+ and H2O from all model reaction equations
rem_ind = ismember(model.metFormulas,{'H2O','H'});
model.S(rem_ind,:) = 0;

% also remove from MNX reaction equations
rem_ind = ismember(mnx.metFormulas,{'H2O','H'});
rem_ind(contains(mnx.metNames,{'(.)','deuterium','tritium','hydride'},'IgnoreCase',true)) = false;  % exclude other variants
rem_IDs = mnx.mets(rem_ind);
mnx.rxnMets = flattenCell(mnx.rxnMets,true);  % flatten cell
mnx.rxnMets(ismember(mnx.rxnMets,rem_IDs)) = {''};  % remove IDs
mnx.rxnMets = nestCell(mnx.rxnMets,true);  % re-nest cell

% map reactions
rxnMNXID(mapRxns) = findMNXrxns(model,mnx,mapRxns);

% find newly mapped rxns
newMapped = mapRxns & ~cellfun(@isempty,rxnMNXID);
results.notes(newMapped) = {'MATCH: ignored H+ and H2O'};

fprintf('Done.\n');

%% Finalize output

fprintf('Finalizing output... ');

results.notes(cellfun(@isempty,rxnMNXID) & mapRxns) = {'NO MATCHES FOUND'};

% retrieve MNX reaction equations for all mapped MNXIDs
rxnMNXeqn = repmat({''},size(model.rxns));
for i = 1:length(rxnMNXID)
    if ~isempty(rxnMNXID{i})
        rxnMNXeqn{i} = mnx.rxnEqnNames(ismember(mnx.rxns,rxnMNXID{i}));
    end
end

% add data to results structure
results.rxnMNXID = rxnMNXID;
results.rxnMNXeqn = rxnMNXeqn;

fprintf('Done.\n');

end

%% Additional functions

function rxnIDs = findMNXrxns(model,mnx,mapRxns)
%Finds MNX rxns with same set of mets as model rxns.

% convert stoich matrix to logicals, where all non-zero coeffs are TRUE
S = (full(model.S) ~= 0);

% exclude reactions that are not to be mapped
S(:,~mapRxns) = [];
model.rxns(~mapRxns) = [];
model.rxnMetsMNX(~mapRxns) = [];

% get number of mets in each reaction, for model and MNX
Nmets_per_rxn_model = sum(S,1)';
Nmets_per_rxn_mnx = cellfun(@numel,mnx.rxnMets);

% initialize output
rxnIDs = repmat({''},size(model.rxns));

% iterate through model reactions, searching for matching MNX reactions
h = waitbar(0,'Scanning reactions...');
for i = 1:length(model.rxns)

    waitbar(i/length(model.rxns),h);

    % find MNX rxns that have the same number of mets as the model rxn
    match = (Nmets_per_rxn_mnx == Nmets_per_rxn_model(i));
    if ~any(match)
        continue
    end

    % find MNX rxns whose mets match at least one of those associated with the model rxn
    match(match) = cellfun(@(m) all(ismember(m,model.rxnMetsMNX{i})),mnx.rxnMets(match));

    % now check if each of the mets in the model rxn are contained in the MNX rxns
    met_inds = find(S(:,i));
    for j = 1:length(met_inds)

        % stop checking metabolites if no further matches remain
        if ~any(match)
            break
        end

        % remove matching MNX rxns that don't contain the current model met
        match(match) = cellfun(@(m) any(ismember(model.metMNXID{met_inds(j)},m)),mnx.rxnMets(match));
    end

    % obtain IDs of all MNX rxns with a matching set of mets as the model rxn
    rxnIDs{i} = mnx.rxns(match);

end
close(h);

end


function w= rsam2waveform(s)
    w = [];
    for c=1:numel(s)
        if numel(s(c).data) > 0
            wc = waveform(s(c).ChannelTag, 1.0/s(c).sampling_interval, s(c).snum, s(c).data, s(c).units);
        else
            wc = waveform(s(c).ChannelTag, 1.0/s(c).sampling_interval, 0, [], s(c).units);
        end
        w = [w wc];
    end
end


function A = double(X)
%DOUBLE Convert tensor to double array.
%
%   A = double(X) converts X to a standard multidimensional array.
%
%   See also TENSOR.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2012) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

A = double(X.data);


% plotAverageWaveforms
%
% Plots average waveforms for all channels and specified units across the
% array. It will prompt for a CMP file to map each channel to its electrode
% representation.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Use plotAverageWaveforms(NEV, units)
%
% NOTE: All input arguments are optional. Input arguments may be in any order.
%
%   NEV:          NEV structure containing all waveforms.
%                 DEFAULT: Will prompt for NEV.
%
%   'units':      Specify the units to plot (i.e. 2 or 0:5 for all).
%                 DEFAULT: will plot all units.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   USAGE EXAMPLE:
%
%   openNEV(NEV, 0:3);
%
%   In the example above, the waveforms in the NEV structure coming from
%   units 0 through 3 will be plotted.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Kian Torab
%   kian@blackrockmicro.com
%   Blackrock Microsystems
%   Salt Lake City, UT
%
%   Version 2.1.0.0

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Version History
%
% 1.0.0.0:
%   - Initial release.
%
% 2.1.0.0:
%   - Added the ability to plot scaled or non-scaled plots. By default, the
%   plots are scaled.
%   - The color of the first unit is always selected at random, so when a
%   channel only has 1 unit, that 1 unit will be a different color
%   (visualization only).
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function plotAverageWaveforms(NEV, units, plottype)

mapfile = 1;
colors = repmat({'magenta', 'cyan', 'red', 'green', 'blue', 'black'}, 1, 3);

if ~exist('NEV', 'var')
    NEV = openNEV('read');
end

if ~exist('units', 'var')
    units = 0:5;
end

if ~exist('plottype', 'var')
    plottype = 'scaled';
end

numberOfElectrodes = length(unique(NEV.Data.Spikes.Electrode));

disp('Select a map file for your array. If none, press cancel or ESC.');
mapFile = KTUEAMapFile;
if ~mapFile.isValid
    disp('Map File was not selected.');
    mapfile = 0;
    plotHeight = floor(sqrt(numberOfElectrodes));
    plotWidth = ceil(numberOfElectrodes/floor(sqrt(numberOfElectrodes)));
end

figure = KTFigure;

figure.EnlargeFigure;
figure.MakeBackgroundWhite;
figure.SetActive;
title('Spikes Average Waveforms for Individual Channels');

for chanIDX = 1:numberOfElectrodes

    if mapfile
try
        mapFile.GenerateChannelSubplot(chanIDX);
catch
    disp('e');
end
    else
        subplot(plotHeight, plotWidth, chanIDX);
    end

    hold on;
    initialColor = round(rand(1)*5);
    for unitIDX = units
        [~, allWaveforms] = findEventTimes(NEV, chanIDX, unitIDX);
        if ~isempty(allWaveforms)
            averageWaveform = mean(allWaveforms, 2);
            plot(averageWaveform, 'color', colors{unitIDX+1+initialColor}, 'LineWidth',2);
        end
    end
    hold off;

    if strcmpi(plottype, 'scaled')
        ylim([-1000, 1000]);
    end
%     if size(allWaveforms,2) ~= 0
%         text(1, 0, num2str(size(allWaveforms,2)), 'color', 'red');
%     end
    mapFile.setAxisBackgroundColor('white');
    set(gca, 'XTick', []);
    set(gca, 'YTick', []);
end


function varargout=kmeanlbg(varargin)
%
% For calling details please see v_kmeanlbg.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_kmeanlbg.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: kmeanlbg.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_kmeanlbg(varargin{:});
else
    v_kmeanlbg(varargin{:});
end


%XYZLABEL Label X, Y and Z axes
%
% XYZLABEL() label the x-, y- and z-axes with 'X', 'Y', and 'Z'
% respectiveley.
%
% XYZLABEL(FMT) as above but pass in a format string where %s is substituted
% for the axis label, eg.
%
%          xyzlabel('This is the %s axis')
%
% See also xlabel, ylabel, zlabel, sprintf.

% Copyright (C) 1993-2019 Peter I. Corke
%
% This file is part of The Spatial Math Toolbox for MATLAB (SMTB).
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
% in the Software without restriction, including without limitation the rights
% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
% of the Software, and to permit persons to whom the Software is furnished to do
% so, subject to the following conditions:
%
% The above copyright notice and this permission notice shall be included in all
% copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
% FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
% COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
% IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
% CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
%
% https://github.com/petercorke/spatial-math
function xyzlabel(fmt)
    if nargin < 1
        fmt = '%s';
    end
    xlabel(sprintf(fmt, 'X'));
    ylabel(sprintf(fmt, 'Y'));
    zlabel(sprintf(fmt, 'Z'));


function gn = g01_size ( )

%*****************************************************************************80
%
%% G01_SIZE returns the size for grid 1.
%
%  Discussion:
%
%    The "grid size" is simply the number of points in the grid.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 January 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer GN, the grid size.
%
  gn = 100;

  return
end


function NewFemFile = fem_mergelayers(FemFile, MergeLayers, MergedLabel)
% FEM_MERGELAYERS: Merge multiple layers from a FEM model
%
% USAGE: NewFemFile = fem_mergelayers(FemFile, MergeLayers=[ask], MergedLabel=[ask])

% @=============================================================================
% 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, 2020

% ===== PARSE INPUTS =====
if (nargin < 3) || isempty(MergedLabel)
    MergedLabel = [];
end
if (nargin < 2) || isempty(MergeLayers)
    MergeLayers = [];
end
NewFemFile = [];

% ===== INPUTS =====
% Load input file
isProgress = bst_progress('isVisible');
if ~isProgress
    bst_progress('start', 'Merge layers', 'Loading FEM mesh...');
end
FemMat = load(FemFile);
% Get subject
[sSubject, iSubject] = bst_get('SurfaceFile', FemFile);

% Check input layers
if (length(FemMat.TissueLabels) == 1)
    error('There is only one layer in the input file.');
elseif ~isempty(MergeLayers) && any(~ismember(MergeLayers, FemMat.TissueLabels))
    error('The requested layers are not available in the file.');
end
% Ask layers to merge
if isempty(MergeLayers)
    isSelect = ismember(FemMat.TissueLabels, {'white', 'gray', 'csf'});
    isSelect = java_dialog('checkbox', 'Select layers to merge:', 'Merge layers', [], FemMat.TissueLabels, isSelect);
    if isempty(isSelect)
        if ~isProgress
            bst_progress('stop');
        end
        return;
    end
    MergeLayers = FemMat.TissueLabels(isSelect == 1);
end
% Check number of layers selected
if (length(MergeLayers) < 2)
    error('You must select at least two layers.');
end
% Get merged tissue indices
iMerged = cellfun(@(c)find(strcmpi(c, FemMat.TissueLabels)), MergeLayers);

% Ask new layer name
if isempty(MergedLabel)
    MergedLabel = java_dialog('input', 'Please enter a name for the new merged layer:', 'Merge layers', [], 'brain');
    if isempty(MergedLabel)
        if ~isProgress
            bst_progress('stop');
        end
        return;
    end
end
% Check that new layer name doesn't exist
nTissueOld = length(FemMat.TissueLabels);
nTissueNew = nTissueOld - length(iMerged) + 1;
if ismember(MergedLabel, FemMat.TissueLabels(setdiff(nTissueOld, iMerged)))
    error(['Label "' MergedLabel '" already exists in file.']);
end

% ===== RELABEL TISSUES =====
% Update tissue labels
FemMat.TissueLabels{iMerged(1)} = MergedLabel;
FemMat.TissueLabels(iMerged(2:end)) = [];
% Relabel all elements
iRelabel = 1:nTissueNew;
iRelabel(iMerged) = iMerged(1);
iKept = setdiff(1:nTissueOld, iMerged(2:end));
iRelabel(iKept) = 1:length(iKept);
FemMat.Tissue = reshape(iRelabel(FemMat.Tissue), [], 1);

% ===== SAVE NEW FILE =====
if ~isProgress
    bst_progress('start', 'Merge layers', 'Saving new FEM mesh...');
end
% Update comment
FemMat.Comment = strrep(FemMat.Comment, sprintf('%d lay', nTissueOld), sprintf('%d lay', nTissueNew));
% Add history
FemMat = bst_history('add', FemMat, 'merge', ['Merged layers:', sprintf(' %s', MergeLayers{:})]);
% Add file tag
NewFemFile = file_unique(strrep(FemFile, '.mat', '_merge.mat'));
% Save new file
bst_save(NewFemFile, FemMat, 'v7');
% Reference file in database
db_add_surface(iSubject, NewFemFile, FemMat.Comment);

if ~isProgress
    bst_progress('stop');
end


% loadeeg() - load a binary data file in Neuroscan .eeg file format.
%
% Usage:
% >> signal = loadeeg(filename);
% >> [signal, accept, typeeeg, rt, response, chan_names, pnts, ...
%      ntrials, srate, xmin, xmax] = loadeeg( filename, chanlist, ...
%        triallist, typerange, accepttype, rtrange, responsetype);
%
% Inputs:
%   filename     - [string] Input Neuroscan .eeg file
%   chanlist     - [integer array] Only import selected channels
%                  Ex: [3,4:10] {default: 'all'}
%   triallist    - [integer array] Only import selected trials {default: import all}
%   typerange    - [integer array] Only import trials of selected type
%                  {default: import all}
%   accepttype   - [integer array] Only import trials with the selected
%                  'accept' field values {default: import all}
%   rtrange      - [float array] [min max] (ms) Only import trials with subject
%                  reaction times in this range {default: import all}
%   responsetype - [integer array] Only import trials with selected
%                  response type values {default: import all}
%   format       - ['short'|'int32'] data format. Neuroscan v4.3+ assume 32-bit data
%                  while older versions assume 16-bit. {default: 'short' = 16-bit}
%
% Outputs:
%   signal       - Output signal of size (trials, points)
%   accept       - [1/0] vector of values for the accept field (one per trial)
%   typeeeg      - [Integer] values for the accept type (size 1,trials)
%   rt           - [float] values for the accept rt (size trials)
%   response     - [Integer] values for the accept response (size 1,trials)
%   chan_names   - ['string' array] channel names
%   pnts         - Number of time points per trial
%   ntrials      - Number of trials
%   srate        - Sampling rate (Hz)
%   xmin         - Trial start latency (ms)
%   xmax         - Trial end latency (ms)
%
% Example:
%   % Load .eeg data into an array named 'signal'
%   >> [signal]=loadeeg( 'test.eeg' );
%   % Plot the signal in the first channel, first trial
%   >> plot( signal(1,:) );
%
% Author: Arnaud Delorme, CNL, Salk Institute, 2001
%
% See also: pop_loadeeg(), eeglab()

% .eeg binary file format
%   data are organised into an array of Number_of_electrode x (Number_of_points_per_trial*Number_of_sweeps)
%   for a file with 32 electrodes, 700 points per trial and 300 sweeps, the resulting array is
%   of 32 collumn and 700*300 rows (300 consecutive blocs of 700 points)

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

function [signal, accept, typeeeg, rt, response, chan_names, pnts, ...
	nsweeps, rate, xmin, xmax]=loadeeg( FILENAME, chanlist, ...
	TrialList, typerange, acceptype, rtrange, responsetype, format)
if nargin<1
	fprintf('Not enought arguments\n');
	help loadeeg
	return;
end;
if nargin<2 chanlist='all'; end;
if nargin<3 TrialList='all'; end;
if nargin<4 typerange='all'; end;
if nargin<5 acceptype='all'; end;
if nargin<6 rtrange  ='all'; end;
if nargin<7 responsetype='all'; end;
if nargin<8 format='short'; end;
format = lower(format);

if ~strcmpi(format, 'short') && ~strcmpi(format, 'int32'), error('loadeeg: format error'); end;

% open file for reading
% ---------------------
fid=fopen(FILENAME,'r','ieee-le');
if fid<0
	fprintf('Error LOADEEG: File %s not found\n', FILENAME);
	return;
end;

% read general part of the erp header and set variables
% -----------------------------------------------------
rev = char(fread(fid, 20, 'uchar'))'; % revision number
erp = fread(fid, 342, 'uchar');	% skip the firsts 362 from BOF (368 bytes in orginal comment?)
nsweeps = fread(fid, 1, 'ushort');	% number of sweeps
erp = fread(fid, 4, 'uchar'); 	% skip 4 bytes
pnts= fread(fid, 1, 'ushort');	% number of point per waveform
chan= fread(fid, 1, 'ushort');  % number of channels
erp = fread(fid, 4, 'uchar'); 	% skip 4 bytes
rate= fread(fid, 1, 'ushort');  % sample rate (Hz)
erp = fread(fid, 127, 'uchar');	% skip 127 bytes
xmin= fread(fid, 1, 'float32'); % in s
xmax= fread(fid, 1, 'float32'); % in s
erp = fread(fid, 387, 'uchar');	% skip 387 bytes

fprintf('number of channels         : %d\n', chan);
fprintf('number of points per trial : %d\n', pnts);
fprintf('sampling rate (Hz)         : %f\n', rate);
fprintf('xmin (s)                   : %f\n', xmin);
fprintf('xmax (s)                   : %f\n', xmax);

% read electrode configuration
% ----------------------------
fprintf('Electrode configuration\n');
for elec = 1:chan
   	channel_label_tmp = fread(fid, 10, 'uchar');
	chan_names(elec,:) = channel_label_tmp';
	for index = 2:9 if chan_names(elec,index) == 0 chan_names(elec,index)=' '; end; end;
	erp = fread(fid, 47-10, 'uchar');
	baseline(elec) = fread(fid, 1, 'ushort');
	erp = fread(fid, 10, 'uchar');
	sensitivity(elec) = fread(fid, 1, 'float32');
	erp = fread(fid, 8, 'uchar');
	calib(elec) = fread(fid, 1, 'float32');
	fprintf('%s: baseline: %d\tsensitivity: %f\tcalibration: %f\n', ...
            char(chan_names(elec,1:4)), baseline(elec), sensitivity(elec), calib(elec));
	factor(elec) = calib(elec) * sensitivity(elec) / 204.8;
end;
%fprintf('Electrode configuration\n');
%for elec = 1:chan
%	erp = fread(fid, 47, 'uchar');
%	baseline(elec) = fread(fid, 1, 'ushort');
%	erp = fread(fid, 10, 'uchar');
%	sensitivity(elec) = fread(fid, 1, 'float32');
%	erp = fread(fid, 8, 'uchar');
%	calib(elec) = fread(fid, 1, 'float32');
%	fprintf('baseline: %d\tsensitivity: %f\tcalibration: %f\n', baseline(elec), sensitivity(elec), calib(elec));
%	factor(elec) = calib(elec) * sensitivity(elec) / 204.8;
%end;

xsize    = chan * pnts;
buf_size = chan * pnts ;			% size in shorts

% set tags for conditions
% -----------------------
if isstr(chanlist) && strcmpi(chanlist, 'all'), chanlist = [1:chan]; end;
if isstr(TrialList) && strcmpi(TrialList, 'all'),	trialtagI     = 1; else trialtagI     = 0; end;
if isstr(acceptype) && strcmpi(acceptype, 'all'),	acceptagI     = 1; else acceptagI     = 0; end;
if isstr(typerange) && strcmpi(typerange, 'all'), 	typetagI      = 1; else typetagI      = 0; end;
if isstr(responsetype) && strcmpi(responsetype, 'all'),	responsetagI  = 1; else responsetagI  = 0; end;
if isstr(rtrange) && strcmpi(rtrange, 'all'), 	rttagI        = 1; else rttagI        = 0; end;

count_selected = 1;
fprintf('Reserving array (can take some time)\n');
if isstr(TrialList)
    signal = zeros( chan, pnts*nsweeps);
else
    signal = zeros( chan, pnts*length(TrialList));
end;
fprintf('Array reserved, scanning file\n');

for sweep = 1:nsweeps

	% read sweeps header
	% ------------------
	s_accept   = fread(fid, 1, 'uchar');
	s_type     = fread(fid, 1, 'ushort');
	s_correct  = fread(fid, 1, 'ushort');
	s_rt       = fread(fid, 1, 'float32');
	s_response = fread(fid, 1, 'ushort');
	s_reserved = fread(fid, 1, 'ushort');

	unreaded_buf = 1;

	% store the sweep or reject the sweep
	% -----------------------------------
	if trialtagI trialtag = 1;        else trialtag = ismember(sweep, TrialList); end;
	if acceptagI acceptag = 1;        else acceptag =  ismember(s_accept, acceptype); end;
	if typetagI  typetag  = 1; 	  else typetag  =  ismember(s_type, typerange); end;
	if responsetagI responsetag  = 1; else responsetag  = ismember(s_response, responsetype); end;
	if rttagI       rttag  = 1; 	  else rttag  =  ismember(s_rt, rtrange); end;

	if typetag
		if trialtag
			if acceptag
				if responsetag
					if rttag

						buf = fread(fid, [chan pnts], format);
						unreaded_buf = 0;

						% copy information to array
						% -------------------------
						accept(count_selected)   = s_accept;
						typeeeg(count_selected)  = s_type;
						rt(count_selected)       = s_rt;
						response(count_selected) = s_response;

						% demultiplex the data buffer and convert to microvolts
						% -----------------------------------------------------
						for elec = 1:chan
							buf(elec, :) = (buf(elec, :)-baseline(elec)-0.0)*factor(elec);
						end;
                        try
                            signal(:,[((count_selected-1)*pnts+1):count_selected*pnts]) = buf;
                            count_selected = count_selected + 1;
                            if not(mod(count_selected,10)) fprintf('%d sweeps selected out of %d\n', count_selected-1, sweep); end;
                        catch,
                            disp('Warning: File truncated, aborting file read.');
                            count_selected = count_selected + 1;
                            break;
                        end;
					end;
				end;
			end;
		end;
	end;

	if unreaded_buf
        if strcmpi(format, 'short'), fseek(fid, buf_size*2, 'cof');
        else                         fseek(fid, buf_size*4, 'cof');
        end;
    end;
end;
nsweeps = count_selected-1;
fclose(fid);

% restrincting array
% ---------------------------------------
fprintf('rereservation of variables\n');
signal = signal(chanlist, 1:(count_selected-1)*pnts);
chan_names = chan_names(chanlist,:);

return;


function writeSTL(filename, V,F)
  % WRITESTL writes an STL file with vertex/face information. Uses single
  % precision.
  %
  % writeSTL(filename,V,F)
  %
  % Input:
  %  filename  path to .stl file
  %  V  #V by 3 list of vertices (Default units are in mm)
  %  F  #F by 3 list of triangle indices
  %
  stlwrite(filename,F,V);
end


function y = pow_p( x, p )

%POW_P   Internal cvx version.

error(nargchk(2,2,nargin));
y = pow_cvx( x, p, 'pow_p' );

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function cmp = yjf_compare ( y1, j1, f1, y2, j2, f2 )

%*****************************************************************************80
%
%% YJF_COMPARE compares two YJF dates.
%
%  Discussion:
%
%    The routine is "generic" and does not assume a particular calendar.
%    However, it does assume that the calendar dates are "normalized".
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 March 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer Y1, J1, real F1,
%    the first YJF date.
%
%    Input, integer Y2, J2, real F2,
%    the second YJF date.
%
%    Output, character CMP:
%    '<' if date 1 precedes date 2;
%    '=' if date 1 equals date 2;
%    '>' if date 1 follows date 2;
%
  if ( y1 < y2 )
    cmp = '<';
  elseif ( y1 > y2 )
    cmp = '>';
  else

    if ( j1 < j2 )
      cmp = '<';
    elseif ( j1 > j2 )
      cmp = '>';
    else

      if ( f1 < f2 )
        cmp = '<';
      elseif ( f1 > f2 )
        cmp = '>';
      else
        cmp = '=';
      end

    end

  end

  return
end


function test_suite = test_bayesoptimization2
    %   Run specific demo, save values and compare the results to the expected.
    %   Works for both xUnit Test Framework package by Steve Eddins and for
    %   the built-in Unit Testing Framework (as of Matlab version 2013b).
    %
    %   See also
    %     TEST_ALL, DEMO_BAYEESOPTIMIZATION
    %
    %  Copyright (c) 2015 Jarno Vanhatalo
    %  Copyright (c) 2017 Eero Siivola

    % This software is distributed under the GNU General Public
    % License (version 3 or later); please refer to the file
    % License.txt, included with the software, for details.

    % Check which package to use
    if exist('initTestSuite', 'file')
    initTestSuite_path = which('initTestSuite');
    else
    initTestSuite_path = '';
    end
    if ~isempty(initTestSuite_path) && ...
     exist([initTestSuite_path(1:end-15) 'runtests'], 'file')
    % xUnit package
    initTestSuite;
    else
    % Built-in package
    % Use all functions except the @setup
    tests = localfunctions;
    tests = tests(~cellfun(@(x)strcmp(func2str(x),'setup'),tests));
    test_suite = functiontests(tests);
    end

end

function testRunDemo(testCase)
  % Run the correspondin demo and save the values. Note this test has to
  % be run at lest once before the other test may succeed.

  % Suppress an expected warning
  Sw = warning('off','MATLAB:nearlySingularMatrix');
  rundemo(getName())
  warning(Sw); % Return the original warning visibility status
end

function testValues(testCase)
  % Test predictive mean and variance
  verifyVarsEqual(testCase, getName(), ...
    {'x'}, ...
    'RelTolElement', 0.01, 'RelTolRange', 0.02)
end

function testEI(testCase)
  % Test predictive mean and variance
  verifyVarsEqual(testCase, getName(), ...
    {'EI'}, ...
    'RelTolElement', 0.01, 'RelTolRange', 0.02)
end

% ------------------------
%     Helper functions
% ------------------------

function testCase = setup
  % Helper function to suply empty array into variable testCase as an
  % argument for each test function, if using xUnit package. Not to be
  % used with built-in test framework.
  testCase = [];
end

function name = getName
  % Helperfunction that returns the name of the demo, e.g. 'binomial1'.
  name = mfilename;
  name = name(6:end);
end


function value = p38_autonomous ( )

%*****************************************************************************80
%
%% P38_AUTONOMOUS reports whether problem P38 is autonomous.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer VALUE, is 1 if the equation is autonomous.
%
  value = 1;

  return
end


function varargout = column_vector(varargin)
%COLUMN_VECTOR returns the given vectors as column vectors
%
%   Usage: [x1,x2,...] = column_vector(x1,x2,...)
%
%   Input parameters:
%       x1,x2,...  - one or more vectors
%
%   Output parameters:
%       x1,x2,...  - input vectors as column vectors
%
%   See also: row_vector

%*****************************************************************************
% The MIT License (MIT)                                                      *
%                                                                            *
% Copyright (c) 2010-2019 SFS Toolbox Developers                             *
%                                                                            *
% Permission is hereby granted,  free of charge,  to any person  obtaining a *
% copy of this software and associated documentation files (the "Software"), *
% to deal in the Software without  restriction, including without limitation *
% the rights  to use, copy, modify, merge,  publish, distribute, sublicense, *
% and/or  sell copies of  the Software,  and to permit  persons to whom  the *
% Software is furnished to do so, subject to the following conditions:       *
%                                                                            *
% The above copyright notice and this permission notice shall be included in *
% all copies or substantial portions of the Software.                        *
%                                                                            *
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
% IMPLIED, INCLUDING BUT  NOT LIMITED TO THE  WARRANTIES OF MERCHANTABILITY, *
% FITNESS  FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT. IN NO EVENT SHALL *
% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
% LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT  OR OTHERWISE, ARISING *
% FROM,  OUT OF  OR IN  CONNECTION  WITH THE  SOFTWARE OR  THE USE  OR OTHER *
% DEALINGS IN THE SOFTWARE.                                                  *
%                                                                            *
% The SFS Toolbox  allows to simulate and  investigate sound field synthesis *
% methods like wave field synthesis or higher order ambisonics.              *
%                                                                            *
% https://sfs.readthedocs.io                            sfstoolbox@gmail.com *
%*****************************************************************************

%% ===== Checking of input  parameters ===================================
isargvector(varargin{:});

%% ===== Computation =====================================================
for ii = 1:nargin
    if size(varargin{ii},2)>size(varargin{ii},1)
        varargout{ii} = varargin{ii}';
    else
        varargout{ii} = varargin{ii};
    end
end


% compile_mex   Compiles mex files required for hctsa package
%
% This script must be run in the Toolboxes directory.
%
% ------------------------------------------------------------------------------
% Copyright (C) 2020, Ben D. Fulcher <ben.d.fulcher@gmail.com>,
% <http://www.benfulcher.com>
%
% If you use this code for your research, please cite the following two papers:
%
% (1) B.D. Fulcher and N.S. Jones, "hctsa: A Computational Framework for Automated
% Time-Series Phenotyping Using Massive Feature Extraction, Cell Systems 5: 527 (2017).
% DOI: 10.1016/j.cels.2017.10.001
%
% (2) B.D. Fulcher, M.A. Little, N.S. Jones, "Highly comparative time-series
% analysis: the empirical structure of time series and their methods",
% J. Roy. Soc. Interface 10(83) 20130048 (2013).
% DOI: 10.1098/rsif.2013.0048
%
% This work is licensed under the Creative Commons
% Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of
% this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send
% a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View,
% California, 94041, USA.
% ------------------------------------------------------------------------------

% ------------------------------------------------------------------------------
% Check we're in the correct directory
% ------------------------------------------------------------------------------

currentDir = pwd;

% Path split using platform-dependent separator
weHere = regexp(currentDir,filesep,'split');

if ~strcmp(weHere{end},'Toolboxes')
    error('This code must be run in the ''Toolboxes'' directory of the HCTSA package...')
end

% Sweet. Toolbox path is:
toolDir = currentDir;

% ------------------------------------------------------------------------------
% Max Little's fastdfa code
% ------------------------------------------------------------------------------
fprintf(1,'fastdfa...');
try
    cd(fullfile(toolDir,'Max_Little','fastdfa'));
	mex ML_fastdfa_core.c
    fprintf(1,' done.\n');
catch emsg
    fprintf(1,'%s\n\n',emsg.message);
    cd(toolDir);
    errMsg = sprintf(['An error occurred while compiling ML_Fastdfa_core C code.\n' ...
        'It appears that mex is not set up to work on this system (cf. ''doc mex'' and ''mex -setup'').\n' ...
        'Get ''mex ML_fastdfa_core.c'' to work, and then re-run compile_mex.m']);
    error(errMsg)
end

% ------------------------------------------------------------------------------
% Max Little's Steps Bumps Toolkit
% ------------------------------------------------------------------------------
fprintf(1,'Max Little''s ''Steps and bumps'' toolkit...');
cd(fullfile(toolDir,'Max_Little','steps_bumps_toolkit'))
anyErrors = false;
try
    mex ML_kvsteps_core.cpp
catch
    fprintf(1,'ERROR: Max Little''s ''Steps and bumps'' C++ code failed to compile correctly.\n');
end
if ~anyErrors
    fprintf(1,' done.\n');
end

% ------------------------------------------------------------------------------
% Max Little's RPDE toolkit
% ------------------------------------------------------------------------------
fprintf(1,'Max Little''s ''RPDE'' code...');
cd(fullfile(toolDir,'Max_Little','rpde'))
anyErrors = false;
try
    mex ML_close_ret.c
catch
    fprintf(1,'ERROR: Max Little''s ''RPDE'' C code failed to compile correctly\n');
end
if ~anyErrors
    fprintf(1,' done.\n');
end

% ------------------------------------------------------------------------------
% Michael Small's code
% ------------------------------------------------------------------------------
fprintf(1,'Michael Small''s code...');
cd(fullfile(toolDir,'Michael_Small'))
anyErrors = false;
try
    mex MS_complexitybs.c % compile Michael Small's complexitybs C code
catch
    fprintf(1,'ERROR: Michael Small''s ''complexitybs'' C code failed to compile correctly\n');
end
try
    mex MS_nearest.c      % compile Michael Small's nearest C code
catch
    fprintf(1,'ERROR: Michael Small''s ''nearest'' C code failed to compile correctly\n');
end
try
    mex MS_shannon.c      % compile Michael Small's shannon C code
catch
    fprintf(1,'ERROR: Michael Small''s ''shannon'' C code failed to compile correctly\n');
end
if ~anyErrors
    fprintf(1,' done.\n');
end

% ------------------------------------------------------------------------------
% Gaussian Process code, gpml
% ------------------------------------------------------------------------------
fprintf(1,'Gaussian Process Toolbox, Carl Edward Rasmussen and Hannes Nickisch...');
cd(fullfile(toolDir,'gpml','util'))
anyErrors = false;
try
    make
catch
    fprintf(1,'ERROR: Gaussian Process Toolbox failed to compile correctly.\n');
end
if ~anyErrors
    fprintf(1,' done.\n');
end

%-------------------------------------------------------------------------------
% Physionet sample entropy code (turned to mex)
%-------------------------------------------------------------------------------
fprintf(1,'Sample entropy...');
cd(fullfile(toolDir,'Physionet'))
anyErrors = false;
try
    mex sampen_mex.c
catch
    fprintf(1,'ERROR: Physionet implementation of sample entropy failed to compile.\n');
end
if ~anyErrors
    fprintf(1,' done.\n');
end

% ------------------------------------------------------------------------------
% TSTOOL routines (such a mess)
% ------------------------------------------------------------------------------
fprintf(1,'TSTOOL...');
cd(fullfile(toolDir,'OpenTSTOOL','mex-dev'))
anyErrors = false;
try
    makemex
    settspath(fullfile(toolDir,'OpenTSTOOL'));
catch emsg
    fprintf(1,'---ERROR: %s\n',emsg.message);
    fprintf(1,'The TSTOOL package failed to compile correctly.\n');
end
if ~anyErrors
    fprintf(1,'Done!\n');
end

% ------------------------------------------------------------------------------
% TISEAN
% ------------------------------------------------------------------------------
fprintf(1,['NB: To use TISEAN routines, you need to compile and install them on your system\n' ...
    'In the commandline, navigate to the Toolboxes%sTisean_3.0.1 directory\n  ''./configure'',' ...
    ' ''make'' and ''make install'' commands\n(cf. Documentation for instructions,' ...
    ' including implementations for Windows)...\n'],filesep);

%-------------------------------------------------------------------------------
% CATCH22
%-------------------------------------------------------------------------------
cd(fullfile(toolDir,'catch22','wrap_Matlab'))
mexAll

% Return to base directory
cd(toolDir);


function GSS = parseScores(inputFile, predictor)
% parseScores
%	Parse the output from a predictor to generate the GSS
%
%	Input:
%	inputFile	a file with the output from the predictor
%	predictor	the predictor that was used. 'wolf' for WoLF PSORT, 'cello'
%               for CELLO, 'deeploc' for DeepLoc (opt, default 'wolf')
%
%	Output:
%	GSS         a gene scoring structure to be used in predictLocalization
%
%	The function normalizes the scores so that the best score for each gene
%	is 1.0.
%
%	Usage: GSS = parseScores(inputFile, predictor)

if nargin<2
    predictor='wolf';
else
    predictor=char(predictor);
end

fid=fopen(inputFile,'r');

if fid<1
    EM='Could not open file';
    dispEM(EM);
end

if strcmpi(predictor,'wolf')
    A=textscan(fid,'%s','Delimiter','\n','CommentStyle','#');

    %Each element should be for one gene, but some of them are on the form
    %"Pc20g11350: treating 9 X's as Glycines". Those should be removed
    I=~cellfun(@any,strfind(A{1},'treating'));

    B=regexp(A{1}(I),' ','split');

    %Reserve space for stuff
    GSS.compartments={};
    GSS.scores=[]; %Do not know number of comps yet
    GSS.genes=cell(numel(B),1);

    %Parsing is a bit cumbersome as ', ' is used as a delimiter in some
    %cases and ' ' in others. Use strrep to get rid of ','
    for i=1:numel(B)
        b=strrep(B{i},',','');
        GSS.genes{i}=b{1};

        %Then go through the compartments and add new ones as they are
        %found
        for j=2:2:numel(b)-1
            [~, J]=ismember(b(j),GSS.compartments);

            %Add new compartment if it does not exist
            if J==0
                GSS.compartments=[GSS.compartments;b(j)];
                J=numel(GSS.compartments);
                GSS.scores=[GSS.scores zeros(numel(B),1)];
            end

            GSS.scores(i,J)=str2double(b(j+1));
        end
    end
elseif strcmpi(predictor,'cello')
    fid=fopen(inputFile,'r');
    %Read the title line and fetch the list of compartments
    tline = fgetl(fid);
    tline=regexprep(tline,'^.+#Combined:\t','');
    tline=regexprep(tline,'\t#Most-likely-Location.+','');
    GSS.compartments=transpose(regexp(tline,'\t','split'));

    %Now iterate through the following lines in the file. Each row
    %corresponds to one gene and it consists of the scores for
    %compartments. Gene name is in the end of each line
    row=0;
    while 1
        row=row+1;
        tline = fgetl(fid);
        if ~ischar(tline)
            break;
        end
        tline=regexprep(tline,'^.+:\t','');
        tline=regexprep(tline,' .+','');
        tline=regexp(tline,'\t','split');
        GSS.scores(row,:)=str2double(tline(1:numel(GSS.compartments)));
        GSS.genes{row,1}=tline{1,end};
    end
elseif strcmpi(predictor,'deeploc')
    fid=fopen(inputFile,'r');
    %Read the title line and fetch the list of compartments
    tline = fgetl(fid);
    GSS.compartments=regexp(tline,'\t','split');
    GSS.compartments=GSS.compartments(3:end);

    %Now iterate through the following lines in the file. Each row
    %corresponds to one gene and it consists of the scores for
    %compartments. Gene name is in the end of each line
    row=0;
    while 1
        row=row+1;
        tline = fgetl(fid);
        if ~ischar(tline)
            break;
        end
        tline=regexp(tline,'\t','split');
        GSS.scores(row,:)=str2double(tline(3:end));
        GSS.genes{row,1}=tline{1,1};
    end
end

%Check if there are duplicate genes
[~, J, K]=unique(GSS.genes);

if numel(J)~=numel(K)
    EM='There are duplicate genes in the input file';
    dispEM(EM,false);
    GSS.genes=GSS.genes(J);
    GSS.scores=GSS.scores(J,:);
end

%Normalize
I=max(GSS.scores,[],2);
GSS.scores=bsxfun(@times, GSS.scores, 1./I);

fclose(fid);
end


%
% Usage:   Y =mexSort(X);
%
% Name: mexSort
%
% Description: sort the elements of X using quicksort
%
% Inputs: X:  double vector of size n
%
% Output: Y: double  vector of size n
%
% Author: Julien Mairal, 2010


%% EBSD Simulation
%
%%
% There is an implementation by Rüdiger Kilian ...


function data_rx = extract_data(symbol_ofdm_rx,v_pilots)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%                                                                       %
%%       Name: extract_data.m                                            %
%%                                                                       %
%%       Description: In this function, the inverse process of the       %
%%        function "createsymbol.m" is realized. That is, we extract     %
%%        the known parts of the symbol that we have received:           %
%%        --> Pilot carriers                                             %
%%        --> Data carriers                                              %
%%        --> Guard carriers                                             %
%%                                                                       %
%%       Result: The data is given back only, since the rest does not    %
%%        interest us.                                                   %
%%                                                                       %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% First, the position of the data is located
 v_data = setxor(1:length(symbol_ofdm_rx),v_pilots);

% Next, the values of the data and pilot carriers are extracted
 data_total = symbol_ofdm_rx (v_data);

% Now the dc carrier must be removed
 data_rx = [data_total(29:124) data_total(126:221)];


function [V,F] = readOBJfast(filename,varargin)
  % readOBJfast
  %
  % reads an OBJ file quickly, but OBJ file should be formated *simply*
  %
  % Input:
  %  filename  path to .obj file
  % Outputs:
  %  V  #V by 3 list of vertices
  %  F  #F by 3 list of triangle indices
  %
  % filename should be a text file containing first vertex positions where each
  % line is:
  % v x y z
  % then a list of faces where each line is:
  % f i j k
  % and exactly that. Any lines before vertices, or after vertices but before
  % faces are ignored. Comments throughout vetex and face lines will surely
  % break this.
  %
  % Copyright 2011, Alec Jacobson (jacobson@inf.ethz.ch)
  %
  % For complete(r) support use readOBJ
  %
  % See also readOBJ
  %

  function file_wrangler()
    error_handler = @final_error;
    if isunix()
      % try to make the file easier to read
      tmpf = tempname();
      escaped_filename = filename;
      escaped_filename = strrep(escaped_filename,' ','\ ');
      escaped_filename = strrep(escaped_filename,'(','\(');
      escaped_filename = strrep(escaped_filename,')','\)');
      cmd = sprintf( ...
        ['grep "^v " %s >%s ; ' ...
          'grep "^f " %s | ' ...
          'sed -e "s/\\([0-9]*\\)\\(\\/[0-9]*\\)*/\\1/g" >>%s'], ...
        escaped_filename,tmpf,escaped_filename,tmpf);
      s = system(cmd);
      if s==0
        readOBJfast_helper(tmpf);
        if any(F<=0)
          final_error();
        end
        %delete(tmpf);
        return;
      end
    end
    final_error();
  end

  function final_error()
    error('Bad format. Try readOBJ...\n');
  end

  function readOBJfast_helper(filename)
    fp = fopen(filename);
    % read in vertices
    V = [];
    while(true)
      V = fscanf(fp,' v %lg %lg %lg ',inf);
      if(prod(size(V)) > 0)
        break;
      else
        line = fgets(fp);
        if(prod(size(line)) == 0)
          fclose(fp);
          error_handler();
          return;
        end
      end
    end
    V = reshape(V,3,size(V,1)/3)';
    % read in faces
    F = [];
    if quads
      format = ' f %d %d %d %d ';
    else
      format = ' f %d %d %d ';
    end
    while(true)
      F = fscanf(fp,format,inf);
      if(numel(F) > 0)
        break;
      else
        line = fgets(fp);
        if(numel(line) == 0 || (isnumeric(line) && line == -1))
          fclose(fp);
          error_handler();
          return;
        end
      end
    end
    if quads
      if mod(size(F,1),4) ~= 0
        fclose(fp);
        error_handler();
        return;
      end
      F = reshape(F,4,size(F,1)/4)';
    else
      if mod(size(F,1),3) ~= 0
        fclose(fp);
        error_handler();
        return;
      end
      F = reshape(F,3,size(F,1)/3)';
    end
    if ~feof(fp)
      fclose(fp);
      error_handler();
      return;
    end
    fclose(fp);
  end

  % default values
  quads = false;
  % Map of parameter names to variable names
  params_to_variables = containers.Map( ...
    {'Quads'}, ...
    {'quads'});
  v = 1;
  while v <= numel(varargin)
    param_name = varargin{v};
    if isKey(params_to_variables,param_name)
      assert(v+1<=numel(varargin));
      v = v+1;
      % Trick: use feval on anonymous function to use assignin to this workspace
      feval(@()assignin('caller',params_to_variables(param_name),varargin{v}));
    else
      error('Unsupported parameter: %s',varargin{v});
    end
    v=v+1;
  end

  error_handler = @file_wrangler;
  readOBJfast_helper(filename)
  if all(F(:)<0)
    F = F+size(V,1)+1;
  elseif any(F(:)<0)
    final_error();
  end
end


function alpha = p05_alpha ( )

%*****************************************************************************80
%
%% P05_ALPHA returns ALPHA for problem 5.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 July 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real ALPHA, the value of ALPHA.
%
  alpha = 2.0;

  return
end


function value = p27_autonomous ( )

%*****************************************************************************80
%
%% P27_AUTONOMOUS reports whether problem P27 is autonomous.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer VALUE, is 1 if the equation is autonomous.
%
  value = 0;

  return
end


function plotMask(mask)
colormap gray
imagesc(abs(mask));
end


function [countV,ktransAll,veAll,kepAll,vpAll] = calcToftsFit(planC)
% Function to generate and write out DCE parameter maps, compute and save statistics to file.
% AI 5/26/16
% AI 7/06/16  Updated to provide option to scale AIF using reference region time course.
% AI 9/08/16  Removed philips scaling by SS to match Kristen's code.
% ------------------------------------------------------------------------------------------------
% INPUTS
% planC : Patient CERR file.
%         This function uses CERR structures if available.
%         Alternatively, user can select DICOM mask files.
%         Masks/ROIs are assumed to be on sequential slices (slStart to slEnd).
%
% Patient parameters are read from user-selected .txt file.
% For a list of valid input parameters, see ReadDCEParameterFile.m
% -------------------------------------------------------------------------------------------------

%% Get inputs

% Get CERR archive
if nargin==0
    [fname,fpath] = uigetfile('*.mat');
    fprintf('\n Loading patient CERR file ....\n');
    load(fullfile(fpath,fname));
    fprintf('\n Load complete.\n');
end
indexS = planC{end};
% Get parameter file input
paramDir = fullfile(getCERRPath,'PlanAnalysis','DCE-MR analysis','sample_param_and_coeff_files');
[inputS,filePath] = ReadDCEParameterFile(paramDir);
outPath = fileparts(filePath);
[paramS,shiftS] = getInputs(inputS);
% Get DCE scan set when multiple series' are available
planD = planC;
scanListC = unique({planD{indexS.scan}.scanType});
if numel(scanListC)>1
    [series,ok] = listdlg('ListString',scanListC,'Name','Select series','ListSize',[300,250],...
        'PromptString','Select DCE series','SelectionMode','Single');
    if ~ok
        return
    end
    scanNumV = strcmp({planD{indexS.scan}.scanType},scanListC{series});
    planD{indexS.scan} = planD{indexS.scan}(scanNumV);
    %Keep structures associated with selected scan
    structNumV = ismember([planD{indexS.structures}.associatedScan],find(scanNumV));
    planD{indexS.structures} =  planD{indexS.structures}(structNumV);
    %Discard empty structures
    emptyStructV = cellfun(@isempty,{planD{indexS.structures}.rasterSegments});
    planD{indexS.structures} =  planD{indexS.structures}(~emptyStructV);
end

%% Display select header info
headerS.manufacturer = planD{indexS.scan}(1).scanInfo(1).DICOMHeaders.Manufacturer;
headerS.xSize = planD{indexS.scan}(1).scanInfo(1).DICOMHeaders.Rows;
headerS.ySize = planD{indexS.scan}(1).scanInfo(1).DICOMHeaders.Columns;
headerS.TRms = planD{indexS.scan}(1).scanInfo(1).DICOMHeaders.RepetitionTime;
tDel = getTDel(planD);
headerS.tDel = double(tDel)/1000 ;                                       % convert time step to seconds from ms
headerS.B0 = planD{indexS.scan}(1).scanInfo(1).DICOMHeaders.MagneticFieldStrength;
headerS.nSlices = size(planD{indexS.scan}(1).scanArray,3);
FA = planD{indexS.scan}(1).scanInfo(1).DICOMHeaders.FlipAngle;
headerS.FA = shiftS.FAF*FA;                                              % correct flip angle by multiplicative factor FAF
if isfield(paramS,'outfileBase')
    outfileBase = paramS.outfileBase;
else
    outfileBase = '';
end

%Get no. frames
switch(headerS.manufacturer)
    case 'GE MEDICAL SYSTEMS'
        userSel = questdlg('Manufacturer: GE MEDICAL SYSTEMS','Scanner check','Continue','Cancel');
        if strcmp(userSel,'Cancel')
            return;
        end
        totalImages = planD{indexS.scan}(1).scanInfo(1).DICOMHeaders.ImagesinAcquisition;
        headerS.frames = totalImages/headerS.nSlices;
    case 'Philips Healthcare'
        headerS.frames = planD{indexS.scan}(1).scanInfo(1).DICOMHeaders.NumberofTemporalPositions;
end

fprintf(['\nVendor: %s\nNo. slices: %d\nNo. frames: %d\nTR(ms): %g\nDel_T(s): %g\n',...
    'Flip angle: %g\nImage Size(rows x cols): %d x %d\nB0: %g\n'],headerS.manufacturer,...
    headerS.nSlices,headerS.frames,headerS.TRms,headerS.tDel,headerS.FA,headerS.xSize,headerS.ySize,headerS.B0);

%% Compute model parameters
% ** Time shift for ROI time course (from input) **
ROIPointShift = shiftS.TROIPointShift * strcmp(paramS.model,'T') + ...
    shiftS.ETROIPointShift * strcmp(paramS.model,'ET');
shiftS.ROIPointShift = ROIPointShift;
% ** r1  (Using relaxivities from Pintaske, et. al. Invest Radiol 2006) **
%     Gd-DTPA, 1.5T   =  3.9 L/(mmol x s)
%     Gd-DTPA, 3.0T   =  3.3 L/(mmol x s)
%     Gd-BOPTA (multihance) 1.5T  = 8.1 L/(mmol x s)
%     Gd-BOPTA (multihance) 3.0T = 6.3 L/(mmol x s)

r1 = 3.9*(headerS.B0 < 2.0)*strcmp(paramS.cAgent,'gd')+ 3.3*(headerS.B0 > 2.0)*strcmp(paramS.cAgent,'gd') + ...
    8.1*(headerS.B0 < 2.0)*strcmp(paramS.cAgent,'mh') + 6.3*(headerS.B0 > 2.0)*strcmp(paramS.cAgent,'mh');
r1 = r1(1);

%** Vector of sampling times (1 x frames size) **
ind = double(0:(headerS.frames-1));                      % ind: vector with elements 0,1,2,3...AIF_frames-1
tsec = ind*headerS.tDel;
tmin = tsec./60;                                         % ktrans, etc. are in /min.  Parker coefs are in  min or /min.
TR = headerS.TRms/1000;                                  % TR from DICOM header is in ms. Change to s.

%**  Parameter array for the concentrarion calculation:
%    pCalcConc(1) = R1 = relaxivity of contrast agent (units are mmolxs)
%    pCalcConc(2) = TR (s)
%    pCalcConc(3) = flip angle (degrees)
%    pCalcConc(4) = pre-contrast T1 for tissue (s)
pCalcConc = [r1, TR, headerS.FA, paramS.T10];

%** Get Parker coefficient file **
[coefFile, fPath] = uigetfile([paramDir '/*.txt'],'Select coefficient file');
coefFile = fullfile(fPath,coefFile);

%% Get 3D mask
mask3M = ones(size(planD{indexS.scan}(1).scanArray));
roiSlicesV = [];
%if strcmp (paramS.maskSource,'MM') % Use CERR ROI (for Kristen)
structListC = cellfun(@lower,{planD{indexS.structures}.structureName},'un',0);
%---- For Kristen Zakian ---
%To Skip reference structures (labeled 'muscle') :
isMuscleC = strfind(structListC,'muscle');
strIdxC = cellfun(@isempty,isMuscleC,'un',0);
strNumV = find([strIdxC{:}]);
structListC = structListC(strNumV);
%--------------------------------
if numel(structListC)>1
    [strSel,ok] = listdlg('ListString',structListC,'Name','Select structure','ListSize',[300,250],...
        'PromptString','Select structure','SelectionMode','Single');
    if ~ok
        return
    end
else
    strSel = 1;
end
strNumV = strNumV(strSel);
structListC = structListC(strSel);
for l  = 1:length(structListC)
    rasterSegments = getRasterSegments(strNumV(l),planD);
    maskSlices = unique(rasterSegments(:,6));
    mask3M(:,:,maskSlices) = rasterToMask(rasterSegments,1, planD);
    roiSlicesV = [roiSlicesV;maskSlices];
end
% For Kristen (to use DICOM masks )
%else
%     % Get mask from file
%     [maskName,maskPathname] = getMaskFiles(paramS.slStart,pathBase);
%     maskFileS = dir([maskPathname,maskName,'*']);
%     numMasks = paramS.slEnd-paramS.slStart+1;
%     readMasks3M = zeros(headerS.xSize,headerS.ySize,numMasks);
%     for k = 1:numMasks
%         readMasks3M(:,:,k) = dicomread(fullfile(maskPathname,maskFileS(k).name));
%     end
%     %Get corresponding cerr file slice nos
%     [~,sliceNoV] = sort([planD{indexS.scan}(1).scanInfo.imageNumber]);
%     roiSlicesV = sliceNoV(paramS.slStart:paramS.slEnd);
%     mask3M(:,:,roiSlicesV) = readMasks3M;
%     % Copy to planD object
%     planD = maskToCERRStructure(mask3M, 0, 1, 'Imported structure', planD);
%     roiSlicesV = sort(roiSlicesV);
%end
%fprintf('ROIslices: %d',roiSlicesV);
paramS.slStart = roiSlicesV(1);
paramS.slEnd = roiSlicesV(end);
workSlices = paramS.slEnd-paramS.slStart+1;

%If using T1 maps, load T1 maps for all slices into a 3D array
if strcmp(paramS.T1Map , 'y')
    T13M = getT1Maps(headerS.xSize, headerS.ySize, headerS.nSlices, paramS.slStart, workSlices);
else
    T13M = [];
end

%% Read scans grouped by slice location & time point
sliceC = cell(1,workSlices);
infoC = cell(1,workSlices);
for k = 1:workSlices
    timeSlices = arrayfun(@(x) x.scanArray(:,:,roiSlicesV(k)),planD{indexS.scan},'un',0);
    sliceC{k} = cat(3,timeSlices{:});
    infoC{k} = planD{indexS.scan}(1).scanInfo(roiSlicesV(k)).DICOMHeaders;
end
if isfield(planD{indexS.scan}(1).scanInfo(1),'scaleSlope') & ~isempty(planD{indexS.scan}(1).scanInfo(1).scaleSlope)
    scaleSlope = planD{indexS.scan}(1).scanInfo(1).scaleSlope;
else
    scaleSlope = 1;
end
sliceTimeCourse4M = cat(4,sliceC{:});
sliceTimeCourse4M = sliceTimeCourse4M *scaleSlope; %To match Kristen's code
sliceTimeCourse4M = uint16(sliceTimeCourse4M);     %To match Kristen's code

%% Generate AIFP
fprintf('\n Generating AIF from Parker Coefficient file...');
AIFP = genAIF(tsec,coefFile,headerS.frames,tmin,paramS,shiftS);
fprintf('\n AIF generation complete.\n');

%% Get reference region (muscle) mask

useRefRegion = questdlg('Use muscle reference to scale AIF?','Reference region','Yes','No','No') ;

if strcmp(useRefRegion, 'No')
    AIFPScaled = AIFP;
else
    %if strcmp (paramS.refMaskSource,'MM') %For Kristen
    structListC = {planD{indexS.structures}.structureName};
    [strNum,ok] = listdlg('ListString',structListC,'SelectionMode','Single',...
                  'PromptString','Select reference structure');
    if ~ok
        return
    end
    muscleRasterSegS = getRasterSegments(strNum,planD);
    [muscleMaskM,muscleROISlice] = rasterToMask(muscleRasterSegS,1, planD);
    %     else
    %         %For Kristen: to read DICOM masks
    %         [refMaskName,refMaskPath] = uigetfile('.dcm','Select muscle mask file');
    %         slNum = strfind(refMaskName,'_SL');
    %         muscleROISlice = str2num(refMaskName(slNum+3:slNum+4));
    %         muscleMaskM = dicomread(fullfile(refMaskPath,refMaskName));
    %         %Copy reference region mask to CERR plan
    %         refMask3M  = zeros(size(planD{indexS.scan}(1).scanArray));
    %         muscleROISlice = sliceNoV(muscleROISlice);
    %         refMask3M(:,:,muscleROISlice) = muscleMaskM;
    %         planD = maskToCERRStructure(refMask3M, 0, 1, 'Muscle', planD);
    %     end
    % Scale AIF using reference region time course
    muscleSliceC = arrayfun(@(x) x.scanArray(:,:,muscleROISlice),planD{indexS.scan},'un',0);
    muscleSliceTimeCourse3M  = cat(3,muscleSliceC{:});
    muscleTimeCourse3M = ROIMaskedSlices(muscleSliceTimeCourse3M,muscleMaskM);
    AIFPScaled = refRegionScale(AIFP,inputS,shiftS,filePath,headerS,muscleTimeCourse3M,muscleMaskM);
end

%% Write DICOM Maps to file
getVals = 'Yes';
nRuns = 1;
while(strcmp(getVals,'Yes'))
    if nRuns~=1                %Runs with value from parameter file if checkShift='n' the first time
     shiftS.checkShift = 'y';  %Automatically set checkShift to 'y' if user chooses to run again with different shift
     [countV,ktransAll,veAll,kepAll,vpAll,dceRsqAll,UserInShift,UserInBase] = ...
     getDCEToftsParams(paramS,shiftS,headerS,roiSlicesV,sliceTimeCourse4M,pCalcConc,...
     mask3M,T13M,tmin,AIFPScaled,outFolder);
    else
     [countV,ktransAll,veAll,kepAll,vpAll,dceRsqAll,UserInShift,UserInBase,outFolder] = ...
     getDCEToftsParams(paramS,shiftS,headerS,roiSlicesV,sliceTimeCourse4M,pCalcConc,...
     mask3M,T13M,tmin,AIFPScaled,outPath);
    end
    getVals = questdlg(sprintf('Current shift = %d.\n Run again with different shift?',UserInShift),...
        'Change shift?','Yes','No','No');
    nRuns = nRuns + 1;
end

%% Store shifts to file
fid = fopen(filePath);
inputC = textscan(fid, '%s %s %n','endofline','\r\n');
fclose(fid);
fieldsC = fieldnames(paramS);
if strcmp(paramS.model,'T') %Tofts
shiftIdx = strcmp(fieldsC,'TROIPointShift');
else  %Extended tofts
shiftIdx = strcmp(fieldsC,'ETROIPointShift');
end
baseIdx = strcmp(fieldsC,'basepts');
inputC{3}(shiftIdx) = UserInShift;
inputC{3}(baseIdx) = UserInBase;
fid = fopen(filePath,'w+');
fmt = '\r\n%s\t%s\t%d';
for lineNum = 1:size(inputC{1},1)
        col1 = inputC{1}(lineNum);
        col2 = inputC{2}(lineNum);
        col3 = inputC{3}(lineNum);
        fprintf(fid,fmt,col1{1},col2{1},col3);
end
fclose(fid);

%% Write statistics to file
keepIdx = dceRsqAll> paramS.cutOff;
ktransAll(~keepIdx) = 0;
veAll(~keepIdx) = 0;
kepAll(~keepIdx) = 0;
vpAll(~keepIdx) = 0;
writeStats(outFolder,outfileBase,paramS.model,paramS.cutOff,countV,ktransAll,veAll,kepAll,vpAll);

ktransAll(ktransAll==100) = nan;
ktransAll(~keepIdx) = nan;
veAll(veAll==100) = nan;
veAll(~keepIdx) = nan;
kepAll(kepAll==100) = nan;
kepAll(~keepIdx) = nan;
vpAll(vpAll==100) = nan;
vpAll(~keepIdx) = nan;

end


function varargout= bbci_acquire_lsl(varargin)
%BBCI_ACQUIRE_lsl - Online data acquisition from labstreaming layer (LSL)
%   This function acquires small blocks of signals including meta
%   information from the LSL. The LSL can hold streams from any common
%   devices that will be accessed by type: 'eeg' or 'marker'. For details
%   see https://code.google.com/p/labstreaminglayer/.
%
%Synopsis:
%  STATE= bbci_acquire_XYZ('init', <PARAM>)
%  [CNTX, MRKTIME, MRKDESC, STATE]= bbci_acquire_XYZ(STATE)
%  bbci_acquire_XYZ('close')
%  bbci_acquire_XYZ('close', STATE)
%
%Arguments:
%  PARAM - Optional arguments, specific to XYZ.
%
%Output:
%  STATE - Structure characterizing the incoming signals; fields:
%     'fs', 'clab', and intern stuff
%  CNTX - 'acquired' signals [Time x Channels]
%  The following variables hold the markers that have been 'acquired' within
%  the current block (if any).
%  MRKTIME - DOUBLE: [1 nMarkers] position [msec] within data block.
%      A marker occurrence within the first sample would give
%      MARTIME= 1/STATE.fs.
%  MRKDESC - CELL {1 nMarkers} descriptors like 'S 52'

% 11-2015 Jan Boelts
% --- --- --- ---

global BTB

% initialization of state structure and LSL streams
if isequal(varargin{1}, 'init'),

    % check whether lsl toolbox is on the path
    if ~isdir('liblsl-Matlab')
        error('LSL Toolbox is not on the path. add it via addpath(genpath(''path_to_LSL/liblsl-Matlab''))')
    end

    % use default electrode setting
    state= opt_proplistToStruct(varargin{2:end});
    default_clab= ...
        {'AF5' 'AF3' 'AF1' 'AFz' 'AF2' 'AF4' 'AF6' ...
        'F5' 'F3', 'F1' 'Fz' 'F2' 'F4' 'F6' ...
        'FC7' 'FC5' 'FC3' 'FC1' 'FCz' 'FC2' 'FC4' 'FC6' 'FC8' ...
        'T7' 'C5' 'C3' 'C1' 'Cz' 'C2' 'C4' 'C6' 'T8' ...
        'CP7' 'CP5' 'CP3' 'CP1' 'CPz' 'CP2' 'CP4' 'CP6' 'CP8' ...
        'P7' 'P5' 'P3' 'P1' 'Pz' 'P2' 'P4' 'P6' 'P8' ...
        'PO5' 'PO3' 'PO1' 'POz' 'PO2' 'PO4' 'PO6' ...
        'O5' 'O3' 'O1' 'Oz' 'O2' 'O4' 'O6' ...
        };
    % set default parameters that may adapted from the stream later on
    props= {'fs'            100            '!DOUBLE[1]'
        'clab'          default_clab   'CELL{CHAR}'
        'blocksize'     40             '!DOUBLE[1]'
        'port'          'COM11'        '!CHAR'
        'timeout'       3              '!DOUBLE[1]'
        'filtHd'        []             'STRUCT'
        'verbose'       true           '!BOOL'
        };
    [state, isdefault]= opt_setDefaults(state, props, 1);

    % set default filter coeffs
    if isdefault.filtHd,
        % Fs/4
        filt1.b= [0.85 0 0.85];
        filt1.a= [1 0 0.7];
        %Fs/2
        filt2.b= [0.8 0.8];
        filt2.a= [1 0.6];
        state.filtHd= procutil_catFilters(filt1, filt2);
        state.filtHd.PersistentMemory= true;
    end
    % set number of channels and corresponding values
    state.nChans= length(state.clab);
    state.nBytesPerPacket= 2+3*state.nChans+4;
    nPacketsPerPoll= ceil(state.blocksize/1000*state.fs);
    state.nBytesPerPoll= nPacketsPerPoll*state.nBytesPerPacket;

    %%%%%  resolve eeg stream from LSL %%%%%
    eeg = {};
    % load a lsl library
    state.lib = lsl_loadlib();
    % look for the stream several times
    for i=1:3
        % look for stream on the network
        eeg = lsl_resolve_byprop(state.lib,'type','EEG');
        if ~isempty(eeg)
            break
        end
        pause(0.1)
    end
    if isempty(eeg)
        error('No LSL EEG stream on the network')
    else
        % create a new inlet
        % save lsl structures to state structure
        state.inlet.x = lsl_inlet(eeg{1});
        [~, state.starttime] = state.inlet.x.pull_sample();
        state.running = 1;
        % get the stream info object for eeg stream
        eeg_info = state.inlet.x.info();

        % set sampling rate of current stream
        if not(state.fs==eeg_info.nominal_srate)
            state.fs = eeg_info.nominal_srate;
            warning('EEG sampling rate is different from default: was adapted from 100 to %i', state.fs)
        end
        % check number of channels
        if not(state.nChans==eeg_info.channel_count())
            state.nChans = eeg_info.channel_count();
            warning('EEG nChans is different from default')
        end
        state.packetNo=[];
        state.buffer= [];
        state.lastx= zeros(1, state.nChans);
        state.scale= 1000000/2^24;
    end

    % resolve marker stream, try several times
    mrks = {};
    for i=1:3
        mrks = lsl_resolve_byprop(state.lib, 'name', 'MyMarkerStream', 1, 1);
        if ~isempty(mrks)
            break
        end
        pause(0.1)
    end
    if isempty(mrks)
        error('No LSL marker stream with name ''MyMarkerStream'' on the network, did set up the marker stream?')
    else
        state.inlet.mrk = lsl_inlet(mrks{1});
        state.lastMrkDesc= 256;
    end

    if isempty(state.filtHd),
        reset(state.filtHd);
    end
    output= {state};
% close condition needs the 'state' structure.
elseif isequal(varargin{1}, 'close') && length(varargin)==1
    error('Please use ''close'' option with ''state'' variable as second argument: bbci_lsl_acquire(close, state)');
elseif isequal(varargin{1}, 'close') && isstruct(varargin{2}),
    % close inlets and libraries
    state = varargin{2};
    state.inlet.x.delete();
    state.inlet.mrk.delete();
    %state.lib.delete();
    output= {state};

elseif length(varargin)~=1,
    error('Except for INIT/CLOSE case, only one input argument expected');
else % this is the running condition that receives and returns the samples
    if ~isstruct(varargin{1}),
        error('First input argument must be ''init'', ''close'', or a struct');
    end
    state= varargin{1};

    % get data sample from the inlet
    % set timeout to zero to prevent blocking if there is no marker in the
    % current sample.
    timeout = 0; % in seconds
    [cntx, ~] = state.inlet.x.pull_sample();

    % get marker and time
    [mrkDesc, mrkTime] = state.inlet.mrk.pull_sample(timeout);
    % lsl gives mrkTime in relation to the total time of the stream, not
    % the recording. therefore we reset the time to the beginning of the
    % recording. Maybe unneccessary and might be removed?
    mrkTime = mrkTime-state.starttime;

    state.lastMrkDesc= mrkDesc;

    % check whether streams are still on
    % if the timeout was exceeded mrkTime will be empty
    state.running = not(isempty(cntx));

    % save most recent sample
    state.lastx= cntx;

    output = {cntx, mrkTime, mrkDesc, state};
end
varargout= output(1:nargout);


% Get number of space dimensions ("space dimension" field) according to the
% space descriptor, following the format definition at
% http://teem.sourceforge.net/nrrd/format.html#spacedirections.
%
% Returns 3 if "space" field is one of
% "right-anterior-superior" or "RAS"
% "left-anterior-superior" or "LAS"
% "left-posterior-superior" or "LPS"
% "scanner-xyz"
% "3D-right-handed"
% "3D-left-handed"
%
% Returns 4 if "space" field is one of
% "right-anterior-superior-time" or "RAST"
% "left-anterior-superior-time" or "LAST"
% "left-posterior-superior-time" or "LPST"
% "scanner-xyz-time"
% "3D-right-handed-time"
% "3D-left-handed-time"
%
% Date: October 25, 2017
% Author: Gaetan Rensonnet
function sd = nrrd_getSpaceDimensions(spacedescriptor)

if any(strcmpi(spacedescriptor,...
        {'right-anterior-superior', 'RAS',...
        'left-anterior-superior', 'LAS',...
        'left-posterior-superior', 'LPS',...
        'scanner-xyz',...
        '3D-right-handed',...
        '3D-left-handed'}...
        ))
    sd = 3;

elseif any(strcmpi(spacedescriptor,...
        {'right-anterior-superior-time', 'RAST',...
        'left-anterior-superior-time', 'LAST',...
        'left-posterior-superior-time', 'LPST', ...
        'scanner-xyz-time', ...
        '3D-right-handed-time', ...
        '3D-left-handed-time'}...
        ))
    sd = 4;

else
    sd = -1;
    % Unrecognized nrrd space descriptor (grace under fire)
end
end


% pop_importegimat() - import EGI Matlab segmented file
%
% Usage:
%   >> EEG = pop_importegimat(filename, srate, latpoint0);
%
% Inputs:
%   filename    - Matlab file name
%   srate       - sampling rate
%   latpoint0   - latency in sample ms of stimulus presentation.
%                 When data files are exported using Netstation, the user specify
%                 a time range (-100 ms to 500 ms for instance). In this
%                 case, the latency of the stimulus is 100 (ms). Default is 0 (ms)
%
% Output:
%   EEG        - EEGLAB dataset structure
%
% Authors: Arnaud Delorme, CERCO/UCSD, Jan 2010

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

function [EEG com] = pop_importegimat(filename, srate, latpoint0, dataField);

    EEG = [];
    com = '';
    if nargin < 3, latpoint0 = 0; end;
    if nargin < 4, dataField = 'Session'; end;
    if nargin < 1
        % ask user
        [filename, filepath] = uigetfile('*.mat', 'Choose a Matlab file from Netstation -- pop_importegimat()');
        if filename == 0 return; end;
        filename = fullfile(filepath, filename);
        tmpdata = load('-mat', filename);
        fieldValues = fieldnames(tmpdata);
        sessionPos = strmatch('Session', fieldValues);
        posFieldData = 1;
        if ~isempty(sessionPos), posFieldData = sessionPos; end;

        if ~isfield(tmpdata, 'samplingRate'), srate = 250; else srate = tmpdata.samplingRate; end;
        % epoch data files only
        promptstr    = { { 'style' 'text'       'string' 'Sampling rate (Hz)' } ...
                         { 'style' 'edit'       'string'  int2str(srate) } ...
                         { 'style' 'text'       'string' 'Sample latency for stimulus (ms)' } ...
                         { 'style' 'edit'       'string' '0' } ...
                         { 'style' 'text'       'string' 'Field containing data' } ...
                         { 'style' 'popupmenu'  'string' fieldValues 'value' posFieldData } ...
                         };
        geometry = { [1 1] [1 1] [1 1] };
        result       = inputgui( 'geometry', geometry, 'uilist', promptstr, ...
                                 'helpcom', 'pophelp(''pop_importegimat'')', ...
                                 'title', 'Import a Matlab file from Netstation -- pop_importegimat()');

        if length(result) == 0 return; end;
        srate = str2num(result{1});
        latpoint0 = str2num(result{2});
        dataField = fieldValues{result{3}};
        if isempty(latpoint0), latpoint0 = 0; end;
    end;

    EEG = eeg_emptyset;
    fprintf('Reading EGI Matlab file %s\n', filename);
    tmpdata = load('-mat', filename);
    if isfield(tmpdata, 'samplingRate') % continuous file
        srate = tmpdata.samplingRate;
    end;

    fieldValues = fieldnames(tmpdata);
    if all(cellfun(@(x)isempty(findstr(x, 'Segment')), fieldValues))
        EEG.srate = srate;
        indData = strmatch(dataField, fieldValues);
        EEG.data = tmpdata.(fieldValues{indData(1)});
        EEG = eeg_checkset(EEG);
        EEG = readegilocs(EEG);

        com = sprintf('EEG = pop_importegimat(''%s'');', filename);
    else
        % get data types
        % --------------
        allfields = fieldnames(tmpdata);
        for index = 1:length(allfields)
            allfields{index} = allfields{index}(1:findstr(allfields{index}, 'Segment')-2);
        end;
        datatypes = unique_bc(allfields);
        datatypes(cellfun(@isempty, datatypes)) = [];

        % read all data
        % -------------
        counttrial = 1;
        EEG.srate  = srate;
        latency = (latpoint0/1000)*EEG.srate+1;
        for index = 1:length(datatypes)
            tindex = 1;
            for tindex = 1:length(allfields)
                if isfield(tmpdata, sprintf('%s_Segment%d', datatypes{index}, tindex))
                    datatrial = getfield(tmpdata, sprintf('%s_Segment%d', datatypes{index}, tindex));
                    if counttrial == 1
                        EEG.pnts = size(datatrial,2);
                        EEG.data = repmat(single(0), [size(datatrial,1), size(datatrial,2), 1000]);
                    end;
                    EEG.data(:,:,counttrial) = datatrial;

                    EEG.event(counttrial).type    = datatypes{index};
                    EEG.event(counttrial).latency = latency;
                    EEG.event(counttrial).epoch   = counttrial;

                    counttrial = counttrial+1;
                    latency = latency + EEG.pnts;
                end;
            end;
        end;
        fprintf('%d trials read\n', counttrial-1);
        EEG.data(:,:,counttrial:end) = [];

        EEG.setname  = filename(1:end-4);
        EEG.nbchan   = size(EEG.data,1);
        EEG.trials   = counttrial-1;
        if latpoint0 ~= 1
            EEG.xmin     = -latpoint0/1000;
        end;
        EEG = eeg_checkset(EEG);

        % channel location
        % ----------------
        if all(EEG.data(end,1:10) == 0)
            disp('Deleting empty data reference channel (reference channel location is retained)');
            EEG.data(end,:)   = [];
            EEG.nbchan        = size(EEG.data,1);
            EEG = eeg_checkset(EEG);
        end;
        EEG = readegilocs(EEG);

        com = sprintf('EEG = pop_importegimat(''%s'', %3.2f, %3.2f, %d);', filename, srate, latpoint0, dataField);
    end;


function row_num = file_row_count ( input_file_name )

%*****************************************************************************80
%
%% FILE_ROW_COUNT counts the number of row records in a file.
%
%  Discussion:
%
%    Each input line is a "RECORD".
%
%    The records are divided into three groups:
%
%    * BLANK LINES (nothing but blanks)
%    * COMMENT LINES (begin with a '#')
%    * DATA RECORDS (anything else)
%
%    The value returned by the function is the number of data records.
%
%    By the way, if the MATLAB routine FGETS is used, instead of
%    FGETL, then the variable LINE will include line termination
%    characters, which means that a blank line would not actually
%    have zero characters.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    31 December 2006
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILE_NAME, the name of the input file.
%
%    Output, integer ROW_NUM, the number of rows found.
%
  input_unit = fopen ( input_file_name );

  if ( input_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'FILE_ROW_COUNT - Error!\n' );
    fprintf ( 1, '  Could not open the file "%s".\n', input_file_name );
    error ( 'FILE_ROW_COUNT - Error!' );
    row_num = -1;
    return;
  end

  blank_num = 0;
  comment_num = 0;
  row_num = 0;

  record_num = 0;

  while ( 1 )

    line = fgetl ( input_unit );

    if ( line == -1 )
      break;
    end

    record_num = record_num + 1;
    record_length = s_len_trim ( line );

    if ( record_length <= 0 )
      blank_num = blank_num + 1;
    elseif ( line(1) == '#' )
      comment_num = comment_num + 1;
    else
      row_num = row_num + 1;
    end

  end

  fclose ( input_unit );

  return
end


function L = log_prior(CPD)
% LOG_PRIOR Return log P(theta) for a generic CPD  - we return 0
% L = log_prior(CPD)

L = 0;


function i4_seed_advance_test ( )

%*****************************************************************************80
%
%% I4_SEED_ADVANCE_TEST tests I4_SEED_ADVANCE.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    21 May 2008
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'I4_SEED_ADVANCE_TEST\n' );
  fprintf ( 1, '  I4_SEED_ADVANCE advances the seed.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Step        SEED input       SEED output\n' );
  fprintf ( 1, '\n' );

  seed_new = 12345;

  for step = 1 : 10

    seed = seed_new;
    seed_new = i4_seed_advance ( seed );

    fprintf ( 1, '  %4d  %16d  %16d\n', step, seed, seed_new );

  end

  return
end


% performs argument checks/transformations similar to those found in
% gp.m from GPML, but Hessian friendly

% Copyright (c) 2014--2015 Roman Garnett.
% Modified 2016 Luigi Acerbi.

% function gpstruct = gpset(gpstruct, hyp, inf, mean, cov, lik, prior, bounds, x, y)
function gpstruct = gpset(gpstruct, varargin)

% Input arguments
args = {'hyp', 'inf', 'mean', 'cov', 'lik', 'prior', 'bounds'};

for idx = 1:numel(varargin)
    % Inputs are x and y
    if isnumeric(varargin{idx})
        if numel(varargin) ~= idx+1 || ~isnumeric(varargin{idx+1})
            error('gpstruct:trainingdata', ...
                'Training data X and Y need to be the last two inputs of GPSET.');
        end
        gpstruct.x = varargin{idx};
        gpstruct.y = varargin{idx+1};
        break;
    end

    if idx > numel(varargin)
        error('gpstruct:inputarguments', ...
            'Too many input arguments.');
    end

    % Assign input to struct if different than skip placeholder
    if ~strcmp(varargin{idx}, '~')
        gpstruct.(args{idx}) = varargin{idx};
    end
end

% Default gp values
defaultstruct = struct( ...
    'hyp', struct('cov',[],'lik',[],'mean',[]), ...
    'inf',{@exact_inference}, ...
    'cov', {@isotropic_sqdexp_covariance}, ...
    'lik',{@likGauss}, ...
    'mean', {@zero_mean}, ...
    'x', [], ...
    'y', [], ...
    's', [], ...
    'prior', [], ...
    'bounds', [] ...
    );

% Assign default values
for field = fields(defaultstruct)'
    if ~isfield(gpstruct,field{:}) || isempty(gpstruct.(field{:}))
        gpstruct.(field{:}) = defaultstruct.(field{:});
    end
end

% Allow string/function handle input; convert to cell arrays if necessary
for field = {'inf', 'cov', 'lik', 'mean'}
    if ischar(gpstruct.(field{:})) || isa(gpstruct.(field{:}), 'function_handle')
        gpstruct.(field{:}) = {gpstruct.(field{:})};
    end
end

% If HYP is a cell array, convert to struct array
if iscell(gpstruct.hyp) && isstruct(gpstruct.hyp{1})
    hyptemp = struct('cov','lik','mean');
    for i = 1:length(gpstruct.hyp)
        hyptemp(i) = gpstruct.hyp{i};
    end
    gpstruct.hyp = hyptemp;
end

% Ensure all hyperparameter fields exist
for field = {'cov', 'lik', 'mean'}
    for i = 1:numel(gpstruct.hyp)
        if (~isfield(gpstruct.hyp(i), field{:}))
            gpstruct.hyp(i).(field{:}) = [];
        end
    end
end

% Check dimension of hyperparameter fields if X is available
D = size(gpstruct.x, 2);
if D > 0
    shortfields = {'cov','lik','mean'};
    longfields = {'covariance','likelihood','mean'};
    for ifield = 1:numel(shortfields)
        field = shortfields{ifield};
        expression = feval(gpstruct.(field){:});
        for i = 1:numel(gpstruct.hyp)
            nparams = numel(gpstruct.hyp(i).(field));
            if (nparams ~= eval(expression))
                error('gpstruct:incorrect_specification', ...
                      'wrong number of %s hyperparameters (%i given, %s expected)', ...
                      longfields{ifield}, ...
                      nparams, ...
                      expression);
            end
        end
    end
end

% Check prior and bounds
for field = {'cov', 'lik', 'mean'}
    % Ensure all prior fields exist
    if (~isfield(gpstruct.prior, field{:}))
        gpstruct.prior.(field{:}) = [];
    end
    % Ensure all bounds fields exist
    if (~isfield(gpstruct.bounds, field{:}))
        gpstruct.bounds.(field{:}) = [];
    end
    % Assign [-Inf;Inf] bounds by default
    num_entries = numel(gpstruct.hyp(1).(field{:}));
    for i = 1:num_entries
        if numel(gpstruct.prior.(field{:})) < i
            gpstruct.prior.(field{:}){i} = [];
        end
        if numel(gpstruct.bounds.(field{:})) < i || ...
                isempty(gpstruct.bounds.(field{:}){i})
            gpstruct.bounds.(field{:}){i} = [-Inf,Inf];
        end
    end
end

% Add field with (empty) posterior
if ~isfield(gpstruct,'post'); gpstruct.post = []; end


function a = r8cvv_rinc ( mn, a, m, roff, i, dai )

%*****************************************************************************80
%
%% R8CVV_RINC increments row I in an R8CVV.
%
%  Discussion:
%
%    An R8CVV is a "vector of vectors" of R8's.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 November 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer MN, the size of the cell array.
%
%    Input, real A(MN), the cell array.
%
%    Input, integer M, the number of rows in the array.
%
%    Input, integer ROFF(M+1), the row offsets.
%
%    Input, integer I, the row.
%    1 <= I <= M.
%
%    Input, real DAI(NR(I)), the increment for A(I,*).
%
%    Output, real A(MN), the cell array.
%
  k1 = roff(i) + 1;
  k2 = roff(i+1);
  nv = k2 + 1 - k1;
  a(k1:k2) = a(k1:k2) + dai(1:nv);

  return
end


function DataSet = prtDataGenManual
%prtDataGenManual Manually specify 2-D data via mouse clicking
%
%   dataSet = prtDataGenManual outputs data X and labels Y defined
%   interactively by clicking on a figure.  Left clickes place points on
%   the figure, and right clicks change the labels for the points to be
%   placed.  To finish, close the figure, or click the small "Done" button
%   on the bottom left of the figure.
%
%   Example:
%
%   dataSet = prtDataGenManual;
%
%   See also: prtDataSetClass, prtDataGenBiModal, prtDataGenIris,
%   prtDataGenManual, prtDataGenMary, prtDataGenNoisySinc,
%   prtDataGenOldFaithful,prtDataGenProtate, prtDataGenSprial,
%   prtDataGenSpiral3Regress, prtDataGenUnimodal, prtDataGenSwissRoll,
%   prtDataGenUnimodal, prtDataGenXor

hF = figure;
X = zeros(0,2);
Y = zeros(0,1);
currentLabel = 0;
maxLabel = 0;

hA = axes;
set(hA,'buttondownfcn',@prtDataGenManualAxesButtonDownFcn);
hB = uicontrol('style','pushbutton','string','Done','callback',@(o,e) close(hF),'units','normalized','Position',[0.05 0.05 0.05 0.05]);
dataManualTitle;

DataSet = prtDataSetClass(X,Y,'name','Manualy Defined DataSet');

uiwait(hF);

    function dataManualTitle
        title(sprintf('Left-click to add an H_{%d} observation. Right-click to change hypothesis.',currentLabel));
    end

    function prtDataGenManualAxesButtonDownFcn(o,e)
        persistent previous;
        sType = get(hF,'selectionType');
        previous = sType;
        point = get(gca,'CurrentPoint');

        switch sType
            case 'normal'
                DataSet = catObservations(DataSet,prtDataSetClass(point(2,1:2),currentLabel));
                V = axis;
                hP = plot(DataSet);
                set(hP,'hittest','off');
                set(gca,'buttondownfcn',@prtDataGenManualAxesButtonDownFcn);
                axis(V);
                if currentLabel == maxLabel
                    maxLabel = maxLabel + 1;
                end
                dataManualTitle;
            case 'alt'
                currentLabel = currentLabel + 1;
                if currentLabel > maxLabel
                    currentLabel = 0;
                end
                dataManualTitle;
            %this happens when double-clicking *either* mouse button, so
            %it's impossible to say which mouse button was pushed.  Which
            %is not really cool.  In either casel clicking too fast results
            %in no changes to the GUI.
            % case 'open'
            %      disp('No double clicks allowed');
            %      % keyboard
        end
    end

end


function chrpak_test026 ( )

%*****************************************************************************80
%
%% TEST026 tests CH_TO_ROT13.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    10 June 2007
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST026\n' );
  fprintf ( 1, '  CH_TO_ROT13 "encodes" characters using ROT13\n' );
  fprintf ( 1, '  (and digits using ROT5).\n' );
  fprintf ( 1, '  A second application of the function returns the\n' );
  fprintf ( 1, '  original character.\n' );

  s1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  for i = 1 : length ( s1 )
    s2(i) = ch_to_rot13 ( s1(i) );
    s3(i) = ch_to_rot13 ( s2(i) );
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, '            CH  : %s\n', s1 );
  fprintf ( 1, '      ROT13(CH) : %s\n', s2 );
  fprintf ( 1, 'ROT13(ROT13(CH)): %s\n', s3 );

  s1 = 'CH_TO_ROT13 "encodes" characters using ROT13';
  for i = 1 : length ( s1 )
    s2(i) = ch_to_rot13 ( s1(i) );
    s3(i) = ch_to_rot13 ( s2(i) );
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, '            CH  : %s\n', s1 );
  fprintf ( 1, '      ROT13(CH) : %s\n', s2 );
  fprintf ( 1, 'ROT13(ROT13(CH)): %s\n', s3 );

  return
end


function data_num = p03_data_num ( )

%*****************************************************************************80
%
%% P03_DATA_NUM returns the number of data points for problem p03.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 August 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer DATA_NUM, the number of data points.
%
  data_num = 11;

  return
end


%FILE2DSET Load and convert dataset from disk file
%
%  A = FILE2DSET(NAME,M,N)
%
% The function was previously named PRDATASET. It has to be renamed for the
% renaming of DATASET into PRDATASET in PRTOOLS version 5. It may also be
% called by A = PRDATASET(NAME,M,N), both, in version 4 as well as in
% version 5.
%
% The dataset given in NAME is loaded from a .mat file and converted
% to the current PRTools definition. Objects and features requested
% by the index vectors M and N are returned.
%
% See PRDATA for loading arbitrary data into a PRTools dataset.
% See PRDATASETS for an overview of datasets.

% Copyright: R.P.W. Duin, duin@ph.tn.tudelft.nl
% Faculty of Applied Sciences, Delft University of Technology
% P.O. Box 5046, 2600 GA Delft, The Netherlands

% $Id: prdataset.m,v 1.3 2009/12/21 10:35:12 duin Exp $

% function a = prdataset(name,M,N,no_message)

function a = file2dset(name,varargin)

	persistent FIRST;
	if isempty(FIRST), FIRST = 1; end
  [M,N,no_message] = setdefaults(varargin,[],[],0);
	if exist([name '.mat']) ~= 2
		error([newline '---- Dataset ''' name ''' not available ----'])
	end

	s = warning;
	warning off
	b = load(name);
	warning(s);
	% Try to find out what data we actually loaded:
	names = fieldnames(b);
	eval(['a = b.' names{1} ';']);

	if ~isdataset(a) & ndims(a) > 2
		% We loaded an image?
		a = im2feat(a);
		prwarning(2,'Assumed that a feature image is loaded')
	else
		a = prdataset(a);
	end
	[m,k] = size(a);
	% Maybe a subset of the features is requested:
	if ~isempty(N)
		if min(size(N)) ~= 1
			error([newline 'Feature indices should be stored in vector'])
		end
		if max(N) > k
			error([newline 'Dataset has not the requested features'])
		end
		a = a(:,N);
	end

	% Maybe a subset of the objects are requested:
	if ~isempty(M)
		if min(size(M)) ~= 1
			error([newline 'Object indices should be stored in vector'])
		end
		if max(M) > m
			error([newline 'Dataset has not the requested objects'])
		end
		a = a(M,:);
	end

	if FIRST & ~no_message
		disp(' ')
		disp('*** You are using one of the datasets distibuted by PRTools. Most of them')
		disp('*** are publicly available on the Internet and converted to the PRTools')
		disp('*** format. See the Contents of the datasets directory (HELP PRDATASETS)')
		disp('*** or the load routine of the specific dataset to retrieve its source.')
		disp(' ')
		FIRST = 0;
	end
	return