function spm_voice_P300
% Illustrate voice recognition with lexical priors
% FORMAT spm_voice_P300
%
% loads the global variable VOX.mat
%
% VOX.LEX(w,k) -  structure array for k variants of w words
% VOX.PRO(p)   -  structure array for p aspects of prosody
% VOX.WHO(w)   -  structure array for w aspects of idenity
%
% This routine demonstrates the basic functionality of voice recognition or
% active listening with a special focus on segmentation and the simulated
% neurophysiological correlates of belief updating. It starts by
% demonstrating segmentation; either in response to some spoken sentences
% (read from prompts in the script or by loading exemplar sentences). It
% then moves on to demonstrating the effect of changing the precision of
% prior beliefs about lexical content and how this is expressed in terms of
% simulated belief updating via the minimisation of variational free
% energy.
%
% This routine assumes the necessary files are located in a particular
% (Sound files) directory; that can be specified by editing the script
% below.
%__________________________________________________________________________
% Copyright (C) 2019 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_voice_P300.m 7750 2019-12-05 17:54:29Z spm $

%% demo mode loads sentence (.mat) files
%==========================================================================
DEMO = 1;

% get lexical and prosody arrays in sound file directory
%--------------------------------------------------------------------------
clear global VOX
global VOX

NAME  = which('VOX.mat');
PATH  = fileparts(NAME);
load(NAME)

VOX.analysis = 0;
VOX.graphics = 0;
VOX.interval = 0;
VOX.mute     = 0;
VOX.onsets   = 0;
VOX.depth    = 0;

%% set up priors a succession of 'triangle' or 'square'
%==========================================================================
nw    = numel(VOX.LEX);                                   % number of words
[i,P] = spm_voice_i(repmat({{'triangle','square'}},1,6)); % prior words

% record corresponding sequence and save - or load a preprepared sentence
%--------------------------------------------------------------------------
if DEMO

    load(fullfile(PATH,'triangle_square.mat'))

else

    % SAY: {'triangle','square','triangle','square','triangle','square'};
    %----------------------------------------------------------------------
    spm_voice_read
    Y  = getaudiodata(VOX.audio);
    save(fullfile(PATH,'triangle_square.mat'),'Y');
    [FS,read] = spm_voice_FS(wfile)

end

% illustrate candidate intervals (and F0) for the first word
%--------------------------------------------------------------------------
VOX.FS       = spm_voice_FS;
VOX.IT       = 1;
VOX.onsets   = 1;
VOX.interval = 1;
spm_voice_get_word(Y);
VOX.interval = 0;
spm_voice_fundamental(Y,VOX.FS);
VOX.onsets   = 0;

% segment without priors
%--------------------------------------------------------------------------
VOX.depth    = 0;
spm_figure('GetWin','Segmentation: no priors');  clf;
SEG0 = spm_voice_read(Y);
EEG0 = spm_voice_segmentation(Y,SEG0);

% segment with priors
%--------------------------------------------------------------------------
VOX.depth    = 1;
spm_figure('GetWin','Segmentation: with priors'); clf;
SEG1 = spm_voice_read(Y,P);
EEG1 = spm_voice_segmentation(Y,SEG1);
VOX.depth    = 0;

% illustrate the role of prior precision
%==========================================================================

%% lexical priors; i.e., plausible sequence of words
%--------------------------------------------------------------------------
str{1} = {'is'};
str{2} = {'there'};
str{3} = {'a'};
str{4} = {'triangle','square'};
str{5} = {'below','above','there'};
[i,P]  = spm_voice_i(str);                   % get priors
P      = spm_softmax(log(P));                % and double their precision

% record corresponding sequence and save - or load a preprepared sentence
%--------------------------------------------------------------------------
if DEMO

    load(fullfile(PATH,'sentence.mat'))

else

    % SAY: {'is','there','a','square','above'};
    %----------------------------------------------------------------------
    spm_voice_read
    Y  = getaudiodata(VOX.audio);
    save(fullfile(PATH,'sentence.mat'),'Y');

end

%% change VOX.noise to simulate speech in noise (e.g., VOX.noise = 2)
%--------------------------------------------------------------------------
VOX.noise = 1;                                  % noise level (default: 1)
s         = 3;                                  % index of surprising word

%% segment with priors
%--------------------------------------------------------------------------
spm_figure('GetWin','Segmentation (P300): with priors'); clf;
SEG1  = spm_voice_read(Y,P);
EEG1  = spm_voice_segmentation(Y,SEG1);

% segment without priors
%--------------------------------------------------------------------------
spm_figure('GetWin','Segmentation (P300): no priors'); clf;
SEG0  = spm_voice_read(Y);
EEG0  = spm_voice_segmentation(Y,SEG0);

% add evoked responses with priors, to highlight more exuberant ERPs
%--------------------------------------------------------------------------
subplot(4,1,4), hold on
plot(VOX.PST,EEG1,'-.');

% remove priors from a single word (s)
%--------------------------------------------------------------------------
spm_figure('GetWin','Segmentation: Bayesian surprise'); clf;
Q     = P; Q(:,s) = ones(nw,1)/nw;
SEG2  = spm_voice_read(Y,Q);
EEG2  = spm_voice_segmentation(Y,SEG2);

% illustrate surprise responses (e.g.,P300)
%==========================================================================

% simulations of P300: responses to a single word (s)
%--------------------------------------------------------------------------
spm_figure('GetWin','P300'); clf;
i   = spm_voice_i(SEG1(s).str);
E0  = EEG0(:,i);
E1  = EEG1(:,i);
E2  = EEG2(:,i);

% peristimulus time for plotting (250 ms before and after offset)
%--------------------------------------------------------------------------
t   = SEG2(s).IT/VOX.FS - 1/4;
x   = [t,t + 1/2,t + 1/2,t];
y   = [-1,-1,1,1];
c   = spm_softmax(rand(3,1))';

% responses with and without priors - all words
%--------------------------------------------------------------------------
subplot(3,2,1), plot(VOX.PST,E0,'-.',VOX.PST,E1)
xlabel('time (sec)'), ylabel('amplitude'), title('Waveforms','FontSize',16)
axis square, spm_axis tight, set(gca,'YLim',[-1 1]), box off

% response differentials - all words
%--------------------------------------------------------------------------
subplot(3,2,3), plot(VOX.PST,E0 - E1)
xlabel('time (sec)'), ylabel('amplitude'), title('Differences','FontSize',16)
axis square, spm_axis tight, set(gca,'YLim',[-1 1]/3), box off

% responses with and without priors - one word
%--------------------------------------------------------------------------
subplot(3,2,2), plot(VOX.PST,E2,'-.',VOX.PST,E1)
xlabel('time (sec)'), ylabel('amplitude'), title('Waveforms','FontSize',16)
axis square, spm_axis tight, set(gca,'YLim',[-1 1]), box off

% show peristimulus time
%--------------------------------------------------------------------------
hold on, h = fill(x,y,c); hold off
set(h,'Facealpha',1/8,'EdgeAlpha',1/8);

% response differentials - one word
%--------------------------------------------------------------------------
subplot(3,2,4), plot(VOX.PST,E2 - E1)
xlabel('time (sec)'), ylabel('amplitude'), title('Differences','FontSize',16)
axis square, spm_axis tight, set(gca,'YLim',[-1 1]/3), box off

% show peristimulus time
%--------------------------------------------------------------------------
hold on, h = fill(x,y/3,c); hold off
set(h,'Facealpha',1/8,'EdgeAlpha',1/8);

%% illustrate the relationship between belief updating and RMS responses
%==========================================================================
for i = 1:numel(SEG2)
    q     = spm_softmax(SEG2(i).L{1});
    p     = SEG2(i).p;
    KL(i) = q'*(log(q + exp(-8)) - log(p + exp(-8)));
end

% show RMS responses as a function of time
%--------------------------------------------------------------------------
spm_figure('GetWin','Segmentation: Bayesian surprise');
RMS  = var(EEG2,[],2);
RMS  = 4*RMS/max(RMS);
subplot(4,2,3), hold off, plot(VOX.PST,RMS), hold on
xlabel('time (sec)'), ylabel('Power/KL (nats)')
title('Evoked power','FontSize',16)
spm_axis tight

% and overlay associated belief updating in terms of KL divergence
%--------------------------------------------------------------------------
for i = 1:numel(SEG2)
    t = SEG2(i).IT/VOX.FS + 1/8;
    plot([t,t],[0 KL(i)],'r','LineWidth',4)
end

i     = find(diff(RMS(1:end - 1)) > 0 & diff(RMS(2:end)) < 0);
[R,i] = sort(RMS(i),'descend');
R     = R(1:numel(KL));
KL    = sort(KL,'descend');
B     = [ones(numel(KL),1) KL(:)]\R;

subplot(4,2,4), plot(KL,R,'.r','MarkerSize',16), hold on
kl    = -1:4;
plot(kl,B(1) + kl*B(2),':r','MarkerSize',16)
xlabel('Bayesian suprise (KL - nats)'), ylabel('Evoked power')
title('Belief updating','FontSize',16)
spm_axis square


function [curInputs, curLabel] = PrepareInputFeatures(curImgsLDR, curExpo, curLabel, isTest)

if(~exist('isTest', 'var'))
    isTest = false;
end

numImgs = length(curImgsLDR);

curInLDR = curImgsLDR;

%%% handling the boundary regions where flow is not valid
nanInds1 = isnan(curInLDR{1});
curInLDR{1}(nanInds1) = LDRtoLDR(curInLDR{2}(nanInds1), curExpo(2), curExpo(1));

nanInds2 = isnan(curInLDR{3});
curInLDR{3}(nanInds2) = LDRtoLDR(curInLDR{2}(nanInds2), curExpo(2), curExpo(3));

if(~isTest)
    darkRef = curInLDR{2} < 0.5;
    badRef = (darkRef & nanInds2) | (~darkRef & nanInds1);
    curLabel(badRef) = (LDRtoHDR(curInLDR{2}(badRef), curExpo(2)));
end

%%% concatenating inputs in the LDR and HDR domains
curLabel = (curLabel);
curInputs = (curInLDR{1});
for k = 2 : numImgs
    curInputs = cat(3, curInputs, (curInLDR{k}));
end

for k = 1 : numImgs
    curInputs = cat(3, curInputs, (LDRtoHDR(curInLDR{k}, curExpo(k))));
end


function srf = readBESAsrf(filename)

% This method reads surface files from BESA Research/MRI. For more
% information on the srf file format also see the file format description
% provided by the BrainVoyager support site:
% http://support.brainvoyager.com
%
% Parameters:
%     [filename]
%         In the case that the current folder is not the folder containing
%         the file it should be the full path including the name of the
%         elp file else only the name of the file should be specified.
%
% Return:
%     srf
%         Cell array containing info on surface points stored in file.
%
% Copyright (C) 2013, BESA GmbH
%
% File name: readBESAsrf.m
%
% Author: Robert Spangler
% Created: 2013-11-26

% Check default parameters
% no default parameters so far...

% Ouput parameter
srf = [];

% Try to open file.
FileID = fopen(filename, 'r');
if(FileID < 0)
	printf('Error opening file.\n');
	return
end

% Read version number
srf.VerNo = fread(FileID, 1, 'float');

% Read reserved bytes, must be '0'
srf.Reserved = fread(FileID, 1, 'int');

% Read number of vertices and triangles
srf.NoVertices = fread(FileID, 1, 'int');
srf.NoTriangles = fread(FileID, 1, 'int');

% Read mesh center (X,Y,Z), default (128.0, 128.0, 128.0)
srf.MeshCenterCoord = fread(FileID, 3, 'float');

% Read sequence of (X,Y,Z) coordinates of all vertices
srf.CoordsVertices = [];
% 1. Read NrVertices X coordinates
srf.CoordsVertices(:,1) = fread(FileID, srf.NoVertices, 'float');
% 2. Read NrVertices Y coordinates
srf.CoordsVertices(:,2) = fread(FileID, srf.NoVertices, 'float');
% 3. Read NrVertices Z coordinates
srf.CoordsVertices(:,3) = fread(FileID, srf.NoVertices, 'float');

% Read normal (X,Y,Z) components of all vertices
% Note: For historical reasons, normals do not point outward, but inward.
%       Multiply each normal by "-1.0" for custom rendering.
srf.ComponentsVertices = [];
% 1. Read NrVertices X components
srf.ComponentsVertices(:,1) = fread(FileID, srf.NoVertices, 'float');
% 2. Read NrVertices Y components
srf.ComponentsVertices(:,2) = fread(FileID, srf.NoVertices, 'float');
% 3. Read NrVertices Z components
srf.ComponentsVertices(:,3) = fread(FileID, srf.NoVertices, 'float');

% Read convex curvature color (R,G,B,A), default (0.322, 0.733, 0.98, 1.0)
srf.ConvCurvCol = fread(FileID, 4, 'float');

% Read concave curvature color (R,G,B,A), default (0.1, 0.24, 0.32, 1.0)
srf.ConcCurvCol = fread(FileID, 4, 'float');

% Read mesh color (sequence of color indices, one for each vertex)
srf.MeshCol = fread(FileID, srf.NoVertices, 'int32');

% Read nearest neighbour data for each vertex
srf.NrNeighbours = [];
srf.Neighbours = [];
for CurrVertex=1:srf.NoVertices
    srf.NrNeighbours(CurrVertex) = fread(FileID, 1, 'int32');
    CurrNeighs = fread(FileID, srf.NrNeighbours(CurrVertex), 'int32');
    srf.Neighbours = [srf.Neighbours; CurrNeighs];
end

% Read sequence of three indices to define vertices of each triangle
srf.Triangles = [];
srf.Triangles = fread(FileID, srf.NoTriangles * 3, 'int32');
srf.Triangles = reshape(srf.Triangles, 3, [])';

% Read number of triangle strip elements
srf.NoTriangleStripElems = fread(FileID, [1 1], 'int');

% Read sequence of strip elements
if srf.NoTriangleStripElems > 0
    srf.SequenceStripElements = fread(...
        FileID, [1 NrOfTriangleStripElements], 'int32');
end;

% Read name of MTC file
srf.MTCfile = []; % FIXME

% Close file.
fclose(FileID);
end


problemToSolve = 'test2d_triangle';
origin = 'P1';
variable = 'd_u';
projectDestination = 'P0';


function y = vl_nndropout_wrapper(x, mask, test, dzdy)
%VL_NNDROPOUT_WRAPPER AutoNN wrapper for MatConvNet's vl_nndropout
%   This wrapper bypasses the dropout operation when in test mode.

% Copyright (C) 2017 Joao F. Henriques.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).

  if test
    % pass-through input unchanged, when in test-mode
    if nargin < 4
      y = x ;
    else  % test-mode backward pass
      y = dzdy ;
    end
  else
    if nargin < 4
      y = vl_nndropout(x, 'mask', mask) ;
    else  % backward pass
      y = vl_nndropout(x, dzdy, 'mask', mask) ;
    end
  end
end


classdef TrueAnomalyOptimizationVariable < AbstractOptimizationVariable
    %TrueAnomalyOptimizationVariable Summary of this class goes here
    %   Detailed explanation goes here

    properties
        varObj(1,1) TrueAnomalyTermCondition = TrueAnomalyTermCondition(0);

        lb(1,1) double = 0;
        ub(1,1) double = 0;

        useTf(1,1) = false;
    end

    methods
        function obj = TrueAnomalyOptimizationVariable(varObj)
            obj.varObj = varObj;
            obj.varObj.optVar = obj;

            obj.id = rand();
        end

        function x = getXsForVariable(obj)
            x = [];

            if(obj.useTf)
                x = obj.varObj.tru;
            end
        end

        function [lb, ub] = getBndsForVariable(obj)
            lb = obj.lb(obj.useTf);
            ub = obj.ub(obj.useTf);
        end

        function [lb, ub] = getAllBndsForVariable(obj)
            lb = obj.lb;
            ub = obj.ub;
        end

        function setBndsForVariable(obj, lb, ub)
            obj.lb = lb;
            obj.ub = ub;
        end

        function useTf = getUseTfForVariable(obj)
            useTf = obj.useTf;
        end

        function setUseTfForVariable(obj, useTf)
            obj.useTf = useTf;
        end

        function updateObjWithVarValue(obj, x)
            obj.varObj.tru = x;
        end

        function nameStrs = getStrNamesOfVars(obj, evtNum, varLocType)
            nameStrs = {sprintf('Event %i True Anomaly Termination Condition', evtNum)};
        end

        function varsStoredInRad = getVarsStoredInRad(obj)
            varsStoredInRad = true;
        end
    end
end


function [rxnList, metList, Stats] = reactionCompare(CmodelIn, TmodelIn, scoreIn, varargin)
% This is the function front end for `autoMatchReactions` and
% the `reactionCompareGUI`. Loads `CMODEL`, `TMODEL`, `Score` and `ScoreTotal` from
% globals if they are not provided. If `rxnList` is not provided then it is
% generated with `autoMatchReactions`. If you are continuing comparison,
% include the optional inputs.
% Called by `optimalScores`, `autoMatchReactions`, `reactionCompareGUI`, calls `mergeModelsBorg`, `driveModelBorgifier`.
%
% USAGE:
%
%    [rxnList, metList, Stats] = reactionCompare(CmodelIn, TmodelIn, scoreIn, [rxnList, metList, Stats])
%
% INPUTS:
%    CmodelIn:    Comparison model
%    TmodelIn:    Template model
%    scoreIn:     Score
%
% OPTIONAL INPUTS:
%    rxnList:     Array pairs reactions in `CMODEL` with matches from `TMODEL` or
%                 declares them as new.
%    metList:     Array pairs metabolites in `CMODEL` with matches from `TMODEL`,
%                 new metabolites are given their new met number in `TMODEL`.
%    Stats:       Stats array that contains weighting information from previous
%                 scoring work.
%
% OUTPUTS:
%    rxnList:     reactions' list
%    metList:     metabolites' list
%    Stats:       Structure of information regarding the merging and also stats
%                 on the combined model.
%
% Please cite:
% `Sauls, J. T., & Buescher, J. M. (2014). Assimilating genome-scale
% metabolic reconstructions with modelBorgifier. Bioinformatics
% (Oxford, England), 30(7), 1036?8`. http://doi.org/10.1093/bioinformatics/btt747
%
% ..
%    Edit the above text to modify the response to help addMetInfo
%    Last Modified by GUIDE v2.5 06-Dec-2013 14:19:28
%    This file is published under Creative Commons BY-NC-SA.
%
%    Correspondance:
%    johntsauls@gmail.com
%
%    Developed at:
%    BRAIN Aktiengesellschaft
%    Microbial Production Technologies Unit
%    Quantitative Biology and Sequencing Platform
%    Darmstaeter Str. 34-36
%    64673 Zwingenberg, Germany
%    www.brain-biotech.de

global CMODEL TMODEL SCORE % Declare variables
% Make the inputs variables so they can be easily accessed by downstream
% scripts. None of these variables are edited by any of these scripts.
CMODEL = CmodelIn ;
TMODEL = TmodelIn ;
SCORE = scoreIn ;

% Need scoreTotal now to create rxnList if Stats is not provided.
if nargin <= 5
%     Stats = optimalScores(CMODEL,TMODEL,SCORE) ;
    Stats = optimalScores ;
else
    Stats = varargin{3} ;
end

% Was metList supplied?
if nargin >= 5
    metList = varargin{2} ;
else
    metList = zeros(length(CMODEL.mets),1) ;
end

% How 'bout rxnList?
if nargin > 3
    rxnList = varargin{1} ;
else
    rxnList = ones(length(CMODEL.rxns),1)*-1 ;
end

%% Manual reaction comparison.

% Create information structure to pass to reactionCompareGUI
InfoBall.rxnList = rxnList ;
InfoBall.metList = metList ;
InfoBall.CmodelName = CMODEL.description ;
InfoBall.Stats = Stats ;
InfoBall.S = CMODEL.S ;

% Launch GUI.
[rxnList, metList, Stats] = reactionCompareGUI(InfoBall) ;


function clkeysel()
% provides a interface for some selection options by a polygon
% works on the equivalent events for a cluster catalog(complete,swarms,etc)
% selects clusters which equivalent events are inside selection area
%
%A.Allmann
 % turned into function by Celso G Reyes 2017

ZG=ZmapGlobal.Data; % used by get_zmap_globals
global x y clu mess plot1_h plot2_h clust file1
global  h5 xcordinate ycordinate newclcat clsel
global equi_button backbgevent original backcat backequi
global decc

xcordinate=0;
ycordinate=0;
axes(h5)
x = [];
y = [];

%n = 0;

figure(mess);
set(gcf,'visible','off')
clf;
cla;
set(gca,'visible','off');
set(gcf, 'Name','Polygon Input Parameters');

%creates dialog box to input some parameters
%

inp1_field=uicontrol('Style','edit',...
    'Position',[.70 .60 .17 .10],...
    'Units','normalized','String',num2str(xcordinate),...
    'callback',@callbackfun_001);

inp2_field=uicontrol('Style','edit',...
    'Position',[.70 .40 .17 .10],...
    'Units','normalized','String',num2str(ycordinate),...
    'callback',@callbackfun_002);

more_button=uicontrol('Style','Pushbutton',...
    'Position', [.60 .05 .15 .15],...
    'Units','normalized',...
    'callback',@callbackfun_003,...
    'String','More');
last_button=uicontrol('Style','Pushbutton',...
    'Position',[.40 .05 .15 .15],...
    'Units','normalized',...
    'Callback',@(~,~) clpickp('LAST'),...
    'String','Last');

mouse_button=uicontrol('Style','Pushbutton',...
    'Position',[.20 .05 .15 .15],...
    'Units','normalized',...
    'Callback',@(~,~)clpickp('MOUSE'),...
    'String','Mouse');

load_button=uicontrol('Style','Pushbutton',...
    'Position',[.80 .05 .15 .15],...
    'Units','normalized',...
    'Callback',@(~,~)clpickp('LOAD'),...
    'String','load');
cancel_button=uicontrol('Style','Pushbutton',...
    'Position',[.05 .80 .15 .15],...
    'Units','normalized',...
    'callback',@callbackfun_004,...
    'String','Cancel');
txt1 = text(...
    'Position',[0. 0.65 0 ],...
    'FontSize',12,...
    'String','Longitude:');
txt2 = text(...
    'Position',[0. 0.45 0 ],...
    'FontSize',12,...
    'String','Latitude:');

set(mess,'visible','on')

function callbackfun_001(mysrc,myevt)

  callback_tracker(mysrc,myevt,mfilename('fullpath'));
  xcordinate=str2double(inp1_field.String);
  inp1_field.String=num2str(xcordinate);
end

function callbackfun_002(mysrc,myevt)

  callback_tracker(mysrc,myevt,mfilename('fullpath'));
  ycordinate=str2double(inp2_field.String);
  inp2_field.String=num2str(ycordinate);
end

function callbackfun_003(mysrc,myevt)

  callback_tracker(mysrc,myevt,mfilename('fullpath'));
  set(mouse_button,'visible','off');
  set(load_button,'visible','off');
  clpickp('MORE');
end

function callbackfun_004(mysrc,myevt)

  callback_tracker(mysrc,myevt,mfilename('fullpath'));
  close
end

end


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


function calcmcg( config )
rmpath(genpath([pwd '/dependencies/structuredEdges/release']));
images = dir(config.imageLocation);
images = regexpi({images.name}, '.*jpg|.*jpeg|.*png|.*bmp', 'match');
images = [images{:}];

if(~exist([config.outputLocation '/mcg'], 'dir'))
        mkdir(config.outputLocation,'/mcg')
end

for i=1:length(images)
    imname = char(images(i));
    impath = fullfile(config.imageLocation, imname);
    im=imread(impath);

    fprintf('Calculating MCG proposals for %s\n', imname);
    proposals=calcmcgForIm(im,config.mcg);
    saveFile=[imname '.mat'];
    save([config.outputLocation '/mcg/' saveFile], 'proposals');
end
addpath(genpath([pwd '/dependencies/structuredEdges/release']));
end


function tc_meanAmpsPlusTcs(tc);
% tc_meanAmpsPlusTcs(tc);
%
% Provide a quick summary of ROI response
% to different conditions, by plotting both
% the mean time courses and mean amplitudes
% to each condition. Combines the
% routines from tc_plotMeanTrials and
% tc_barMeanAmplitudes.
%
%
% ras 03/05.

% delete existing large legend
otherAxes = findobj('Parent', gcf, 'Type', 'axes');
delete(otherAxes);

%%%%%%%%%%%%%%%%%%%
% mean amplitudes %
%%%%%%%%%%%%%%%%%%%
axes('Parent', tc.ui.plot, 'Position',[.1 .2 .35 .6]);
hold on

h1 = gca;

tc_barMeanAmplitudes(tc, h1, 'difference');  % Rory prefers it this way

%%%%%%%%%%%%%%%%%%%%%
% mean time courses %
%%%%%%%%%%%%%%%%%%%%%
h2 = axes('Parent', tc.ui.plot, 'Position', [.55 .2 .4 .6]);
tc_plotMeanTrials(tc, h2, 2);

return


function vl_figaspect(a)
% VL_FIGASPECT  Set figure aspect ratio
%   VL_FIGASPECT(A) sets the current figure aspect ratio to A. It
%   leaves the length of the shortest side unaltered. Both the
%   screen and paper positions are affected.
%
%   See also: VL_PRINTSIZE(), VL_HELP().

% Authors: Andrea Vedaldi

% Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).

pos = get(gcf, 'Position') ;

if a >= 1
  pos(3) = a * pos(4) ;
else
  pos(4) = pos(3) / a ;
end

set(gcf,'Position',pos) ;

pos = get(gcf, 'PaperPosition') ;

if a >= 1
  pos(3) = a * pos(4) ;
else
  pos(4) = pos(3) / a ;
end

set(gcf,'PaperPosition', pos) ;


function pf = minus(pf1,pf2)
% implements pf1 - pf2
%
% overload the - operator, i.e. one can now write pf1 - pf2 in order to
% subtract two pole figures from each other
%
% See also
% PoleFigure/PoleFigure PoleFigure/plus PoleFigure/mtimes

pf = pf1 + (-pf2);


%kkexprn 'Output = Function(Input1, Input2)'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros kexprn.pane file
%
% Parameters:
% InputFile: i1 ' i1 ', required: 'input data object 1'
% InputFile: i2 ' i2 ', optional: 'input data object 2'
% InputFile: i3 ' i3 ', optional: 'input data object 3'
% InputFile: i4 ' i4 ', optional: 'input data object 4'
% InputFile: i5 ' i5 ', optional: 'input data object 5'
% InputFile: i6 ' i6 ', optional: 'input data object 6'
% String: expr ' ', default: ' ': 'arithmetic expression'
% OutputFile: o ' o ', required: 'resulting output data object'
%
% Example: o = kkexprn({i1, i2, i3, i4, i5, i6}, {'i1','';'i2','';'i3','';'i4','';'i5','';'i6','';'expr',' ';'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% kexprn - Output = Function(Input1, Input2)
%
%  DESCRIPTION
% .I kgexpr
% allows you to generate
% 1D, 2D, 3D, 4D, or 5D datasets of any data type.  For dataset generation,
% you must specify double precision "begin" and \fIend\fP values, as well
% as an integer "size" value, for each of width, height, depth, time, and
% elements, as relevant to the desired dimensionality of the dataset to be
% created.
% .PP
% The function that will define the dataset is specified as:
% f(w,h,d,t,e) = <expression>
% Where "w, h, d, t," and \fIe\fP are double precision values ranging from
% "begin" to \fIend\fP with the number of values to be generated determined by\fIsize\fP.
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

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

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


function n = nrow(x)

%	function n = nrow(x)
%	Return number of rows in x.

	n = size(x); n = n(1);


function experiments = stack_vot2019()

set_global_variable('bundle', 'http://data.votchallenge.net/vot2019/main/description.json');

baseline.name = 'baseline';
baseline.converter = [];
baseline.type = 'supervised';
baseline.tags = {'camera_motion', 'illum_change', 'occlusion', 'size_change', 'motion_change', 'empty'};

baseline.parameters.repetitions = 15;
baseline.parameters.burnin = 10;
baseline.parameters.skip_initialize = 5;
baseline.parameters.failure_overlap = 0;

baseline.analysis = {'expected_overlap', 'ar', 'speed'};

unsupervised.name = 'unsupervised';
unsupervised.converter = [];
unsupervised.type = 'unsupervised';
unsupervised.tags = {'camera_motion', 'illum_change', 'occlusion', 'size_change', 'motion_change', 'empty'};

unsupervised.parameters.repetitions = 1;
unsupervised.parameters.burnin = 0;

unsupervised.analysis = {'overlap', 'speed'};

realtime.name = 'realtime';
realtime.converter = [];
realtime.type = 'realtime';
realtime.tags = {'camera_motion', 'illum_change', 'occlusion', 'size_change', 'motion_change', 'empty'};

realtime.parameters.repetitions = 1;
realtime.parameters.default_fps = 20;
realtime.parameters.grace = 3;
realtime.parameters.burnin = 10;
realtime.parameters.override_fps = true;
realtime.parameters.skip_initialize = 5;
realtime.parameters.realtime_type = 'real';

realtime.analysis = {'expected_overlap'};

experiments = {baseline, unsupervised, realtime};

end


function experiments = stack_vot2017()

set_global_variable('bundle', 'http://data.votchallenge.net/vot2017/main/description.json');

baseline.name = 'baseline';
baseline.converter = [];
baseline.type = 'supervised';
baseline.tags = {'camera_motion', 'illum_change', 'occlusion', 'size_change', 'motion_change', 'empty'};

baseline.parameters.repetitions = 15;
baseline.parameters.burnin = 10;
baseline.parameters.skip_initialize = 5;
baseline.parameters.failure_overlap = 0;

baseline.analysis = {'ar', 'expected_overlap', 'speed'};

unsupervised.name = 'unsupervised';
unsupervised.converter = [];
unsupervised.type = 'unsupervised';
unsupervised.tags = {'camera_motion', 'illum_change', 'occlusion', 'size_change', 'motion_change', 'empty'};

unsupervised.parameters.repetitions = 1;
unsupervised.parameters.burnin = 0;

unsupervised.analysis = {'overlap', 'speed'};

realtime.name = 'realtime';
realtime.converter = [];
realtime.type = 'realtime';
realtime.tags = {'camera_motion', 'illum_change', 'occlusion', 'size_change', 'motion_change', 'empty'};

realtime.parameters.repetitions = 1;
realtime.parameters.default_fps = 20;
realtime.parameters.grace = 3;
realtime.parameters.burnin = 10;
realtime.parameters.override_fps = true;
realtime.parameters.skip_initialize = 5;
realtime.parameters.realtime_type = 'real';

realtime.analysis = {'expected_overlap'};

experiments = {baseline, unsupervised, realtime};

end


function tagS = patient_module_tags_subset
%"patient_module_tags_subset"
%   Return a subset of the tags specified in C.7.1.1 in PS3.3 of the
%   2006 DICOM specification required for distinguishing patients.
%
% Tags are returned in a struct array with 3 fields:
%   Tag: String containing hex DICOM tag of a field.
%  Type: String describing type of field, with 5 options:
%         '1' Field must exist, data must exist and be valid.
%         '2' Field must exist, data can exist and be valid, or be NULL.
%         '3' Field is optional, if the field exists data can exist and be
%             valid or be NULL.
%         '1C' Field must exist under certain conditions and contain valid
%             data.
%         '2C' Field must exist under certain conditions and can contain
%             valid data or be NULL.
%Children: For sequences, a tagS with the same format as this struct array.
%
% AI 11/20/2020
%
%Usage:
%   tagS = patient_module_tags_subset
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

% Tags: {Patient's Name, PatientID}

tagC = {'00100010','00100020'};

tagDecC = {1048592,1048608};

tagTypeC = {'2','2'};

childC = {[],[]};

tagS = struct('tag', tagC, 'tagdec', tagDecC, 'type', tagTypeC, 'children', childC);


classdef prtBrvDpHmm < prtBrvHmm

    methods
        function self = prtBrvDpHmm(varargin)
            self.transitionProbabilities = prtBrvDiscreteStickBreaking;
            self.initialProbabilities = prtBrvDiscreteStickBreaking;

            self = prtUtilAssignStringValuePairs(self, varargin{:});
        end
    end
end


function plotRow(asObj, pos)

currImg = asObj.getSelectedImages(false);
figure;
cPlot(currImg(pos(1),:)');

% create plot title
title(['Row ', num2str(pos(1))]);

% create plot figure title
set(gcf,'name',['Row-Plot: ',asObj.getFigureTitle()]);

end


classdef TestSeamlessClone
    %TestSeamlessClone

    methods (Static)
        function test_1
            img = imread(fullfile(mexopencv.root(),'test','balloon.jpg'));
            dst = img;
            mask = zeros(size(img,1), size(img,2), 'uint8');
            mask(20:120, 5:100) = 255;
            p = [400 200];

            out = cv.seamlessClone(img, dst, mask, p, 'Method','NormalClone');
            validateattributes(out, {class(img)}, {'size',size(img)});
        end

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

end


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


% STD_FILECHECK - Check if ERSP or SPEC file contain specific parameters.
%                  This file must contain a Matlab structure with a field
%                  named 'parameter'. The content of this field will be
%                  compared to the 'params' input. If they are identical
%                  the output flag will indicate that recomputing this
%                  file is not necessary. If they are different, the user
%                  is queried ('guion' option) to see if he wishes to use
%                  the new parameters and recompute the file (not done in
%                  this function) or if he wishes to use the parameters
%                  of the file on disk.
%
% Usage:
% >> [ recompflag params ] = std_filecheck(filename, params, mode, ignorefields);
%
% Inputs:
%   filename     - [string] file containing a given measure (ERSP data for
%                  instance).
%   params       - [cell array or structure] cell array of parameters or
%                  structure. This is compared to the 'parameters' field
%                  in the data file.
%   mode         - ['guion'|'usedisk'|'recompute'] 'guion' query the user
%                  if the disk and input parameters are different. The
%                  outcome may be either 'usedisk' or 'recompute'. See
%                  recompflag output for more information.
%   ignorefields - [cell array] list fields to ignore
%
% Outputs:
%   recompflag - ['same'|'different'|'recompute'|'usedisk'|'cancel'] 'same'
%                (resp. 'different') indicates that the parameters in the
%                data file are identical (resp. different). 'recompute'
%                indicate that the measure should be recomputed and the
%                file has been erased. 'usedisk' indicate that the user
%                wishes (from the GUI) to use the version on disk.
%   params     - [structure] final parameter. This is usually identical
%                to the 'params' input unless the user choose to use
%                parameters from the file on disk. These are then
%                copied to this output structure.
%
% Authors: Arnaud Delorme, 2006-

% Copyright (C) Arnaud Delorme, SCCN, INC, UCSD, 2006, arno@sccn.ucsd.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [ res, params2 ] = std_filecheck(filename, params2, guiflag, ignorefields);

    if nargin < 2
        help std_filecheck;
        return;
    end
    if nargin < 3
        guiflag = 'guion';
    end
    if nargin < 4
        ignorefields = {};
    end

    if ~exist( filename ), res = guiflag; return; end

    params1 = load('-mat', filename, 'parameters');
    params1 = finputcheck( params1.parameters, { 'tmp' 'real' [] NaN}, '', 'ignore'); % allow to tackle duplicate fields
    params1 = rmfield(params1, 'tmp');
    if iscell(params2), params2 = struct(params2{:}); end

    % test if the fields are different
    % --------------------------------
    params1 = orderfields(params1);
    params2 = orderfields(params2);
    fields1 = fieldnames( params1 ); fields1 = setdiff_bc( fields1, ignorefields);
    fields2 = fieldnames( params2 ); fields2 = setdiff_bc( fields2, ignorefields);
    allfields = union_bc(fields1, fields2);

    % make fields the same
    % --------------------
    res = 'same';
    if ~isequal( fields1, fields2 ),
        for ind = 1:length(allfields)
            if strcmpi(allfields{ind}, 'plotitc'), adsfads; end
            if ~isfield( params1, allfields{ind})
                if ischar(getfield(params2, allfields{ind}))
                     params1 = setfield(params1, allfields{ind}, '');
                else params1 = setfield(params1, allfields{ind}, []);
                end
                res = 'different';
            end
            if ~isfield( params2, allfields{ind})
                if ischar(getfield(params1, allfields{ind}))
                     params2 = setfield(params2, allfields{ind}, '');
                else params2 = setfield(params2, allfields{ind}, []);
                end
                res = 'different';
            end
        end
    end

    % data type
    % ---------
    if ~isempty(strmatch('cycles', allfields)), strcom = 'ERSP';
    else                                        strcom = 'SPECTRAL';
    end

    % compare fields
    % --------------
    txt = {};
    for ind = 1:length(allfields)
        if ~strcmp(allfields{ind},'baseline')
            val1 = getfield(params1, allfields{ind});
            val2 = getfield(params2, allfields{ind});
            val1str = fastif(isempty(val1), 'not set', vararg2str({val1(1:min(3, length(val1)))}));
            val2str = fastif(isempty(val2), 'not set', vararg2str({val2(1:min(3, length(val2)))}));

            tmptxt = sprintf('        ''%s'' is %s in the file (vs. %s)', allfields{ind}, val1str, val2str);
            if length(val1) ~= length(val2)
                res        = 'different';
                txt{end+1} = tmptxt;
            elseif ~isequal(val1, val2)
                if ~isnan(val1) && ~isnan(val2)
                    res        = 'different';
                    txt{end+1} = tmptxt;
                end
            end
        end
    end

    % build gui or return
    % -------------------
    if strcmpi(guiflag, 'usedisk'),
        if isempty(txt)
            params2 = params1;
            res     = 'usedisk';
            disp(['Using file on disk: ' filename ]);
            return;
        else
            strvcat(txt{:})
            error([ 'Two ' strcom ' files had different parameters and the ' strcom ' function' 10 ...
                          'cannot handle that. We suggest that you delete all files. See command line details' ]);
        end
    elseif strcmpi(guiflag, 'recompute'),
        res     = 'recompute';
        disp(['Deleting and recomputing file: ' filename ]);
        return;
    elseif strcmpi(res, 'same') && ( strcmpi(guiflag, 'guion') || strcmpi(guiflag, 'same') )
        disp(['Using file on disk: ' filename ]);
        return;
    end

    set_yes = [ 'set(findobj(''parent'', gcbf, ''tag'', ''ersp_no''), ''value'', 0);'];
    set_no  = [ 'set(findobj(''parent'', gcbf, ''tag'', ''ersp_yes''), ''value'', 0);' ];
    textgui1 = strvcat( [  upper(strcom)  ' info exists in file: ' filename ], ...
                'However, as detailed below, it does not fit with the requested values:');
    textgui2 = strvcat(txt{:});

    %textgui2 = ['wavelet cycles - [' num2str(params1.cycles(1)) ' ' num2str(params2.cycles(2)) ...
    %                '] instead of [' num2str(params1.cycles(1)) ' ' num2str(params2.cycles(2)) ...
    %            '], padratio - ' num2str(params1.padratio) ' instead of ' num2str(param2.padratio) ...
    %            ', and bootstrap significance - ' num2str(params1.alpha) ' instead of ' num2str(params2.alpha) ];

    uilist = { {'style' 'text' 'string' textgui1 } ...
               {'style' 'text' 'string' textgui2 } {} ...
               {'style' 'text' 'string' ['Would you like to recompute ' upper(strcom) ' and overwrite those values?' ]} ...
               {'style' 'checkbox' 'tag' 'ersp_yes' 'string' 'Yes, recompute' 'value' 1 'Callback' set_yes }  ...
               {'style' 'checkbox' 'tag' 'ersp_no' 'string' 'No, use data file parameters (and existing ERSP info)' 'value' 0 'Callback' set_no } };

    ersp_ans = inputgui('geometry', {[1] [1] [1] [1] [0.5 1] }, 'geomvert', [2 max(length(txt),1)*0.7 1 1 1 1], 'uilist', uilist, ...
                        'helpcom', '', 'title', ['Recalculate ' upper(strcom) ' parameters -- part of std_ersp()']);

    if isempty(ersp_ans), res = 'cancel'; return; end
    if find(celltomat(ersp_ans))  == 2 % use existing ERSP info from this dataset
        disp(['Using file on disk: ' filename ]);
        params2 = params1;
        res              = 'usedisk';
    else % Over write data in dataset
        disp(['Deleting and recomputing file: ' filename ]);
        res              = 'recompute';
        %delete(filename);
    end


import matlab.unittest.TestSuite
import matlab.unittest.TestRunner
import matlab.unittest.plugins.CodeCoveragePlugin
import matlab.unittest.plugins.TestReportPlugin

clc;
suite = TestSuite.fromFile('coverage/CMatrixTest.m');
runner = TestRunner.withTextOutput;
runner.addPlugin(CodeCoveragePlugin.forFile({'include/ddouble.m', 'include/AdaptiveChol.m'}))
result = runner.run(suite);


% MATLAB script that add the PhysioNet Cardiovascular Signal Toolbox to
% Matlab path, aslo check Matlab version

% --- Check Matlab version
if verLessThan('matlab', '9.3.0')
    warning('Matlab:Version', 'Your version of Matlab is too old. R2017b or higher is requested.\n');
    return;
end

fprintf('Adding the PhysioNet Cardiovascular Signal Toolbox to Matlab path\n')
try
    ss = ['..' filesep 'PhysioNet-Cardiovascular-Signal-Toolbox'];
    addpath(genpath(ss));
    fprintf('PhysioNet Cardiovascular Signal Toolbox successfully added to Matlab path\n')
catch
    try
        ss = ['..' filesep 'PhysioNet-Cardiovascular-Signal-Toolbox-master'];
        addpath(genpath(ss));
        fprintf('PhysioNet Cardiovascular Signal Toolbox successfully added to Matlab path\n')
    catch
    end
end


% ismember_bc - ismember backward compatible with Matlab versions prior to 2013a

% Copyright (C) 2013 Arnaud Delorme
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [C,IA] = ismember_bc(A,B,varargin)

errorFlag = error_bc;

v = version;
indp = find(v == '.');
v = str2num(v(1:indp(2)-1));
if v > 7.19, v = floor(v) + rem(v,1)/10; end

if nargin > 2
    ind = strmatch('legacy', varargin);
    if ~isempty(ind)
        varargin(ind) = [];
    end
end

if v >= 7.14
    [C,IA] = ismember(A,B,varargin{:},'legacy');
    if errorFlag
        [C2,IA2] = ismember(A,B,varargin{:});
        if (~isequal(C, C2) || ~isequal(IA, IA2))
            warning('backward compatibility issue with call to ismember function');
        end
    end
else
    [C,IA] = ismember(A,B,varargin{:});
end


function Tmodel = cleanTmodel(Tmodel, varargin)
% Reorganizes and checks `Tmodel` for completeness. To be used
% immediately after `addToTmodel`. Called by `addToTmodel`, `mergeModelsBorg`, `mergeTrxns`, calls `TmodelFields`, `buildRxnEquations`, `removeDuplicateNames`, `makeNamesUnique`, `charpos`, `removeProblematicCharacters`.
%
% USAGE:
%
%    Tmodel = cleanTmodel(Tmodel)
%
% INPUTS:
%    Tmodel:       Template model.
%
% OPTIONAL INPUTS:
%    'Verbose':    Ask when performing certain operations.
%
% OUTPUTS:
%    Tmodel:       Cleaned template model
%
% Please cite:
% `Sauls, J. T., & Buescher, J. M. (2014). Assimilating genome-scale
% metabolic reconstructions with modelBorgifier. Bioinformatics
% (Oxford, England), 30(7), 1036?8`. http://doi.org/10.1093/bioinformatics/btt747
%
% ..
%    Edit the above text to modify the response to help addMetInfo
%    Last Modified by GUIDE v2.5 06-Dec-2013 14:19:28
%    This file is published under Creative Commons BY-NC-SA.
%
%    Correspondance:
%    johntsauls@gmail.com
%
%    Developed at:
%    BRAIN Aktiengesellschaft
%    Microbial Production Technologies Unit
%    Quantitative Biology and Sequencing Platform
%    Darmstaeter Str. 34-36
%    64673 Zwingenberg, Germany
%    www.brain-biotech.de

verbose = false ; % Declare variables.
if ~isempty(varargin)
    if sum(strcmp('Verbose', varargin))
        verbose = true ;
    end
end

% Grab fields names.
fields = TmodelFields ;

% Reaction related cell field names.
rxnFields = fields{1} ;
% Reaction related double Fields (which are kept model specific).
rNumFields = fields{2} ;
% Metabolite related cell field names.
metFields = fields{3} ;
% Metabolite related double field names.
mNumFields = fields{4} ;

% Model names.
moNames = fieldnames(Tmodel.Models) ;

% Number of reactions and number of metabolites.
nRxns = length(Tmodel.rxns) ;
nMets = length(Tmodel.mets) ;

% Set flags for if Verbose mode is on
if isempty(varargin)
    mergeRxns = 'y' ;
    askeverytime = 0 ;
    beautifynames = 'y' ;
    askeverytimeb = 0 ;
else
    if verbose
        mergeRxns = input(['Should I try merging identical reactions? ' char(10) ...
                               'y...yes in all cases' char(10) ...
                               'a...ask me every time' char(10) ...
                               'n...no thanks (default)' char(10)], 's') ;
        askeverytime = strcmpi(mergeRxns, 'a') ;

        beautifynames = input(['Should I try to replace cryptic names by nicer ones? ' char(10) ...
                           'y...yes in all cases' char(10) ...
                           'a...ask me every time' char(10) ...
                           'n...no thanks (default)' char(10)], 's') ;
        askeverytimeb = strcmpi(beautifynames,'a') ;
    else
        mergeRxns = 'y' ;
        askeverytime = 0 ;
        beautifynames = 'y' ;
        askeverytimeb = 0 ;
    end
end

%% Lengthen rev, lb, ub, and c arrays for old models.
for iField = 1:length(rNumFields)
    for iMo = 1:length(moNames)
        nowArray = Tmodel.(rNumFields{iField}).(moNames{iMo}) ;
        if length(nowArray) ~= nRxns
            nowArray(end:nRxns) = 0 ;
            Tmodel.(rNumFields{iField}).(moNames{iMo}) = nowArray;
        end
    end
end

%% Lengthen reaction and metabolite identity arrays, convert to logicals.
for iMo = 1:length(moNames)
    % Reactions.
    rxnsArray = Tmodel.Models.(moNames{iMo}).rxns ;
    if length(rxnsArray) ~= nRxns
        rxnsArray(end+1:nRxns) = 0 ;
    end
    Tmodel.Models.(moNames{iMo}).rxns = logical(rxnsArray) ;

    % Metabolites.
    metsArray = Tmodel.Models.(moNames{iMo}).mets ;
    if length(metsArray) ~= nMets
        metsArray(end+1:nMets) = 0 ;
    end
    Tmodel.Models.(moNames{iMo}).mets = logical(metsArray) ;
end

%% Check for accidently duplicated reactions and metabolites
Sfind = zeros(size(Tmodel.S)) ;
Sfind(Tmodel.S ~= 0) = 1 ;
metpos = cell(1, nRxns) ;
metposstr = cell(1, nRxns) ;
for i = 1:nRxns
    metpos{i} = find(Sfind(:, i)) ;
    metposstr{i} = num2str(metpos{i}') ;
end
[~, a, b] = unique(metposstr) ;
mergerxns = {} ; mergerxnratio = [] ;
modelnames = fieldnames(Tmodel.Models)' ;
for im = 1:length(modelnames)
    rxnNowPresent(:, im) = Tmodel.Models.(modelnames{im}).rxns ;
end

if ismember(mergeRxns, {'y', 'a', 'Y', 'A'})
    for i = 1:nRxns
        if ~ismember(i, a) % rxns that use the same metabolites
            eqset = find(b == b(i)) ;
            stoicheck = 1 ;
            for ie = 2:length(eqset)
                rxnratio = unique(Tmodel.S(metpos{i}, eqset(1)) ./ Tmodel.S(metpos{i}, eqset(ie))) ;
                if length(rxnratio) == 1 && ~isnan(rxnratio)  && ...
                        sum(rxnNowPresent(eqset(1), :) .* rxnNowPresent(eqset(ie), :)) == 0
                    if askeverytime
                    % if reactions have the same stoichiometry, maybe with a factor
                    disp([Tmodel.rxns{eqset(1)} '(' strjoin(modelnames(rxnNowPresent(eqset(1), :)), '|') ')' ' and ' ...
                          Tmodel.rxns{eqset(ie)}  '(' strjoin(modelnames(rxnNowPresent(eqset(ie), :)), '|') ')'  ...
                          ' seem to have the same stoichiometry' char(10) ...
                         Tmodel.rxnEquations{eqset(1)} '  VS  ' Tmodel.rxnEquations{eqset(ie)} char(10) ])
                    shouldmerge = input('Do you want to merge them? [Y/n] ' ,'s') ;
                    elseif strcmpi(mergeRxns, 'y')
                        shouldmerge = 'y' ;
                    end
                    if ~strcmp(shouldmerge, 'n')
                        mergerxns{end + 1} = eqset ;
                        mergerxnratio(end + 1) = rxnratio ;
                        disp(['merging ' Tmodel.rxns{eqset(1)} '(' strjoin( modelnames(rxnNowPresent(eqset(1), :)), '|') ')' ' and ' ...
                             Tmodel.rxns{eqset(ie)}  '(' strjoin( modelnames(rxnNowPresent(eqset(ie), :)), '|') ')' ])
                    end
                end
            end
        end
    end
    if length(mergerxns) ~= 0
        Tmodel = mergeTrxns(Tmodel, mergerxns, mergerxnratio) ;
        disp(char(10))
    end
end

% Re-count number of reactions and number of metabolites.
nRxns = length(Tmodel.rxns) ;
nMets = length(Tmodel.mets) ;

%% Prefer biologist-friendly names for reactions and metabolites
if ismember(beautifynames,{'y', 'a', 'Y', 'A'})
    for im = 1:nMets
        nowIDsep = {Tmodel.mets{im}(1:end-3)} ;
        nowcomp = Tmodel.mets{im}(end-2:end) ;
        % parse alternative metIDs
        nowIDs = Tmodel.metID{im};
        nowdelim1 = strfind(nowIDs,':') ;
        nowdelim2 = [strfind(nowIDs,'|') strfind(nowIDs,':') length(nowIDs) + 1] ;
        for ii = 1:length(nowdelim1)
            nowIDsep{ii + 1} = nowIDs(nowdelim1(ii) + 1:min(nowdelim2(nowdelim2 > nowdelim1(ii))) - 1) ;
            nowIDsep{ii + 1} = lower(nowIDsep{ii + 1}(1:min([strfind(nowIDsep{ii + 1},'[') - 1, length(nowIDsep{ii + 1})]))) ;
            nowIDsep{ii + 1} = removeProblematicCharacters(nowIDsep{ii + 1}) ;
        end
        [nowIDalt, ~, freq] = unique(nowIDsep) ;
        nowIDalt = nowIDalt(~cellfun(@isempty, nowIDalt)) ;
        tailnum = [] ; idfreq = [] ;
        if length(nowIDalt) == 1
            % no alternative name found, keep the current one
        else
            for ii = 1:length(nowIDalt)
                tailnum(ii) = length(nowIDalt{ii}(max(find(charpos(nowIDalt{ii}))):end)) - 1 ;
                idfreq(ii) = sum(freq == ii) ;
            end
            [~, goodids] = min((tailnum + 2)./(2*idfreq)) ;
            % if leading character is a number in original name but "a" in new
            % name, then do nothing
            nowcharpos = charpos(Tmodel.mets{im}) ;
            if ~strcmp(nowIDalt{goodids}, Tmodel.mets{im}(1:end - 3)) && ...
                    ~(~nowcharpos(1) && strcmp(nowIDalt{goodids}(1), 'a')) && ...
                   length(Tmodel.mets{im}(max(find(charpos(Tmodel.mets{im}(1:end - 3)) ) ):end - 3)) > 4
                if askeverytimeb
                    replacethistime = input(['Should I rename ' Tmodel.mets{im} ' to '...
                                             nowIDalt{goodids} nowcomp ' (y/n)?'], 's') ;
                end
                if ~askeverytimeb || strcmpi(replacethistime, 'y')
                    disp(['renaming ' Tmodel.mets{im} ' to ' nowIDalt{goodids} nowcomp])
                    Tmodel.mets{im} = [nowIDalt{goodids} nowcomp] ;
                end
            end
        end
    end
    for ir = 1:nRxns
        % transport to extracellular reaction
        if numel(find(Tmodel.S(:, ir))) == 1
            if strcmp(Tmodel.mets{(Tmodel.S(:, ir))~=0}(end - 2:end), '[e]')
                newrxnname = ['ex_' lower(Tmodel.mets{(Tmodel.S(:, ir))~=0}(1:end - 3)) '_e'] ;
                if ~strcmp(newrxnname, Tmodel.rxns{ir})
                    if askeverytimeb
                        replacethistime = input(['Should I rename '  Tmodel.rxns{ir}  ' to '...
                                             newrxnname ' (y/n)?'], 's') ;
                    end
                    if ~askeverytimeb || strcmpi(replacethistime, 'y')
                        disp(['correcting ' Tmodel.rxns{ir} ' to ' newrxnname])
                        Tmodel.rxns{ir} = newrxnname ;
                    end
                end
            end
        else % normal reactions
            nowIDsep = Tmodel.rxns(ir) ;
            if strcmp(nowIDsep{1}(end - 1),'_')
                % this reaction has probably been already renamed to ensure
                % unique reaction names. Therefore do nothing.
                continue
            end
            % parse alternative rxnIDs
            nowIDs = Tmodel.rxnID{ir} ;
            nowdelim1 = strfind(nowIDs, ':') ;
            nowdelim2 = [strfind(nowIDs, '|') strfind(nowIDs, ':') length(nowIDs) + 1] ;
            for ii = 1:length(nowdelim1)
                nowIDsep{ii+1} = nowIDs(nowdelim1(ii) + 1:min(nowdelim2(nowdelim2 > nowdelim1(ii))) - 1) ;
                nowIDsep{ii+1} = lower(nowIDsep{ii + 1}(1:min([strfind(nowIDsep{ii + 1},'[') - 1, length(nowIDsep{ii + 1})]))) ;
                nowIDsep{ii+1} = removeProblematicCharacters(nowIDsep{ii + 1}) ;
            end
            [nowIDalt, ~, freq] = unique(nowIDsep) ;
            tailnum = [] ; idfreq = [] ;
            if length(nowIDalt) == 1
                % no alternative name found, keep the current one
            else
                for ii = 1:length(nowIDalt)
                    tailnum(ii) = length(nowIDalt{ii}(max(find(charpos(nowIDalt{ii}))):end)) - 1 ;
                    idfreq(ii) = sum(freq == ii) ;
                end
                [~, goodids] = min((tailnum + 2) ./ (2 * idfreq)) ;
                % check that the name is not already taken
                if sum(strcmp(Tmodel.rxns, nowIDalt{goodids})) == 0 && ...
                   length(Tmodel.rxns{ir}(max(find(charpos(Tmodel.rxns{ir}))):end)) > 4
                    if askeverytimeb
                        replacethistime = input(['Should I rename '  Tmodel.rxns{ir}  ' to '...
                                             nowIDalt{goodids} ' (y/n)?'], 's') ;
                    end
                    if ~askeverytimeb || strcmpi(replacethistime, 'y')
                        disp(['replacing ' Tmodel.rxns{ir} ' by ' nowIDalt{goodids}])
                        Tmodel.rxns{ir} = nowIDalt{goodids} ;
                    end
                end
            end
        end
    end
end

%% Make sure all names are unique before reorganizing.
% Rebuild reaction equations so there is a hint for renaming rxns.
Tmodel = buildRxnEquations(Tmodel) ;
if verbose ; fprintf('Checking if reaction IDs (.rxns) are unique.\n') ; end
Tmodel.rxns = makeNamesUnique(Tmodel.rxns, Tmodel.rxnEquations) ;
if verbose ; fprintf('Checking if metabolite IDs (.mets) are unique.\n') ; end
Tmodel.mets = makeNamesUnique(Tmodel.mets, Tmodel.metNames) ;

% Remove duplicate met IDs.
Tmodel.metID = removeDuplicateNames(Tmodel.metID) ;

% Rebuild reaction equations.
Tmodel = buildRxnEquations(Tmodel) ;

%% Reorder reactions and metabolites alphabetically.
% Reorder reaction related lists.
[~, rxnI] = sort(Tmodel.rxns) ;
for iField = 1:length(rxnFields)
    Tmodel.(rxnFields{iField}) = Tmodel.(rxnFields{iField})(rxnI) ;
end
for iField = 1:length(rNumFields)
    for iMo = 1:length(moNames)
        Tmodel.(rNumFields{iField}).(moNames{iMo}) = ...
            Tmodel.(rNumFields{iField}).(moNames{iMo})(rxnI) ;
    end
end

% Reorder metabolite related lists.
[~, metI] = sort(Tmodel.mets) ;
for iField = 1:length(metFields)
    Tmodel.(metFields{iField}) = Tmodel.(metFields{iField})(metI) ;
end
for iField = 1:length(mNumFields)
    Tmodel.(mNumFields{iField}) = ...
        Tmodel.(mNumFields{iField})(metI) ;
end

% Reorder identity arrays.
for iMo = 1:length(moNames)
    Tmodel.Models.(moNames{iMo}).rxns = ...
        Tmodel.Models.(moNames{iMo}).rxns(rxnI) ;
    Tmodel.Models.(moNames{iMo}).mets = ...
        Tmodel.Models.(moNames{iMo}).mets(metI) ;
end

% Reorder S matrix.
Tmodel.S = Tmodel.S(:, rxnI) ;
Tmodel.S = Tmodel.S(metI, :) ;

%% Share information between the same metabolite in different compartments.
% Metabolite fields to share information between
share = {'metNames' 'metFormulas' 'metKEGGID' 'metSEEDID' 'metChEBIID' ...
         'metPubChemID' 'metInChIString'} ;

metsNoComp = cell(nMets,1) ;
for iMet = 1:nMets
    metsNoComp{iMet} = Tmodel.mets{iMet}(1:end - 3) ;
end
uniqMets = unique(metsNoComp,'first') ;

% Create combined formation fields for each metabolite and redistribute.
for iMet = 1:length(uniqMets)
  % Find sister metabolites
  sMets = find(strcmp(uniqMets{iMet}, metsNoComp)) ;
  if length(sMets) > 1
    % Create combined information for each field.
    for iF = 1:length(share)
      info = {''} ;
      for iSis = 1:length(sMets)
        % If the field is not empty, break information into parts
        % (as seperated by pipes), and add that information in if
        % it is not already present.
        if ~isempty(Tmodel.(share{iF}){sMets(iSis)})
          pipePos = [0 ...
                     strfind(Tmodel.(share{iF}){sMets(iSis)}, '|') ...
                     length(Tmodel.(share{iF}){sMets(iSis)}) + 1] ;
          for j = 1:length(pipePos) - 1
            nowInfo = Tmodel.(share{iF}){sMets(iSis)} ...
                      (pipePos(j) + 1:pipePos(j + 1) - 1) ;
            % If the info does not already exist.
            if isempty(strfind(info{1}, nowInfo))
              % If it is the first piece of information or additional.
              if isempty(info{1})
                info{1} = nowInfo ;
              else
                info{1} = strcat(info{1}, '|', nowInfo) ;
              end
            end
          end
        end
      end
      for iSis = 1:length(sMets)
          Tmodel.(share{iF}){sMets(iSis)} = info{1} ;
      end
      clear info
    end
  end
end

% Now remove duplicate information which may have snuck in.
for iField = 1:length(share)
    Tmodel.(share{iField}) = removeDuplicateNames(Tmodel.(share{iField})) ;
end

%% Remove duplicate reaction longnames and IDs
Tmodel.rxnNames = removeDuplicateNames(Tmodel.rxnNames) ;
Tmodel.rxnID = removeDuplicateNames(Tmodel.rxnID) ;

%% Clear leftover fields from the matching process
deleteFields = {'rxnNamesFix' 'rxnComp' 'metNums' 'rxnMetNames'} ;
existFields = isfield(Tmodel, deleteFields) ;
for iF = 1:length(existFields)
    if existFields(iF)
        Tmodel = rmfield(Tmodel,deleteFields{iF}) ;
    end
end


1     % GMRES/Bicgstab(2)
1e-6  % tolerance
100   % maximum number of iterations
3     % lst sqrs commutator preconditioner
1     % ideal
0     % Print to (existing) Figure
5     %                     4
4     % Color

% Data file for it_solve for NS2


function [found] = findUndirectedEdge(edge, edges_id)

id1 = edge(1);
id2 = edge(2);

foundForward = find(edges_id(:,1)==id1 & edges_id(:,2)==id2);
if length(foundForward) == 1
  found = 1;
  return;
end

foundBack = find(edges_id(:,2)==id1 & edges_id(:,1)==id2);
if length(foundBack) == 1
  found = 1;
  return;
end

if length(foundForward) > 1 || length(foundBack) > 1
  error('Multiple edge!')
end

found = 0;

end


function asa005_test ( )

%*****************************************************************************80
%
%% ASA005_TEST tests ASA005.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 January 2008
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ASA005_TEST\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the ASA005 library.\n' );

  asa005_test01 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ASA005_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


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


function objHandle = drawSegmentsObject(O,color,lineWidth)

% DRAWSEGMENTSOBJECT  Draw segments object.
%   DRAWSEGMENTSOBJECT(O)  plots all the segments in object O.
%
%   DRAWSEGMENTSOBJECT(O,C,L) uses segments of color C and width L.
%
%   H = DRAWSEGMENTSOBJECT(...) returns a vector H of line handles to each
%   segment in O.
%
%   See also HOUSE, DRAWSEGMENTSIMAGE.

%   Copyright 2008-2009 Joan Sola @ LAAS-CNRS.

X = O([1 4],:);
Y = O([2 5],:);
Z = O([3 6],:);

if nargin < 3
     lineWidth = 1;
     if nargout < 2
         color = 'b';
     end
end

if nargout == 1

    objHandle = line(X,Y,Z,'color',color,'lineStyle','-','linewidth',lineWidth);

else

    line(X,Y,Z,'color',color,'lineStyle','-','linewidth',lineWidth);

end

% ========== End of function - Start GPL license ==========

%   # START GPL LICENSE

%---------------------------------------------------------------------
%
%   This file is part of SLAMTB, a SLAM toolbox for Matlab.
%
%   SLAMTB is free software: you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation, either version 3 of the License, or
%   (at your option) any later version.
%
%   SLAMTB 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 SLAMTB.  If not, see <http://www.gnu.org/licenses/>.
%
%---------------------------------------------------------------------

%   SLAMTB is Copyright:
%   Copyright (c) 2008-2010, Joan Sola @ LAAS-CNRS,
%   Copyright (c) 2010-2013, Joan Sola,
%   Copyright (c) 2014-2015, Joan Sola @ IRI-UPC-CSIC,
%   SLAMTB is Copyright 2009
%   by Joan Sola, Teresa Vidal-Calleja, David Marquez and Jean Marie Codol
%   @ LAAS-CNRS.
%   See on top of this file for its particular copyright.

%   # END GPL LICENSE


function prior = priorExpandParam(prior, params)

% PRIOREXPANDPARAM Expand the prior model's parameters from params vector.
% FORMAT
% DESC returns a prior structure filled with the parameters in the
% given vector. This is used as a helper function to enable
% parameters to be optimised in, for example, the NETLAB
% optimisation functions.
% ARG prior : the prior structure in which the parameters are to be
% placed.
% ARG param : vector of parameters which are to be placed in the
% prior structure.
% RETURN prior : prior structure with the given parameters in the
% relevant locations.
%
% As well as extracting the parameters, some transformation of
% parameters is also undertaken in this file. If the field
% transforms is not empty, it dictactes how the prior parameters
% are to be transformed (for example by a exponential to keep them
% positive).
%
% SEEALSO : priorExtractParam, scg, conjgrad
%
% COPYRIGHT : Neil D. Lawrence, 2003, 2004

% PRIOR

if isfield(prior, 'transforms')
  for i = 1:length(prior.transforms)
    index = prior.transforms(i).index;
    fhandle = str2func([prior.transforms(i).type 'Transform']);
    params(index) = fhandle(params(index), 'atox');
  end
end

fhandle = str2func([prior.type 'PriorExpandParam']);
prior = fhandle(prior, params);


function [nodes, edges2] = grRemoveEdge(nodes, edges, edge)
%GRREMOVEEDGE Remove an edge in a graph.
%
%   [NODES2 EDGES2] = grRemoveEdge(NODES, EDGES, EDGE2REMOVE)
%   Remove an edge in the edges list, and return the modified graph.
%   The NODES array is not modified.
%
%   -----
%
%   author : David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 13/08/2003.
%

%   HISTORY
%   10/02/2004 doc

dim = size(edges);
edges2 = zeros(dim(1)-1, 2);
edges2(1:edge-1, :) = edges(1:edge-1, :);
edges2(edge:dim(1)-1, :) = edges(edge+1:dim(1), :);


function disp( x, prefix )
if nargin < 2,
    prefix = '';
end
str = [ prefix, 'cvx: ', cvx_class( x, true, true, true ) ];
if numel( x ) > 1,
    str = [ str, ' ', type( x ) ];
elseif any( strcmp( str(end-5:end), { 'nstant', ': zero' } ) ),
    str = [ prefix, 'cvx: ', num2str(cvx_constant(x)) ];
end
disp( str );
dual = cvx_getdual( x );
if ~isempty( dual ) && isstruct( dual ),
    disp( [ prefix, '   tied to dual variable: ', dual.subs ] );
end

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function mrk= mrk_defineClasses(mk, classDef, varargin)
%MRK_DEFINECLASSES - Convert BV Markers to class defining marker structure
%
%Synopsis:
% MRK_OUT= mrk_defineClasses(MRK_IN, CLASS_DEF, <OPT>)
%
%Arguments:
% MRK_IN: Marker structure as received by file_readBVmarkers.
%  MarkerFormat can be numeric or string.
% CLASS_DEF: Class array of size {2 x nClasses}. The first row
%  specifies the markers of each class, each cell being either
%  a cell array of strings (for MarkerFormat='string') or a vector
%  of integers (for MarkerFormat='numeric').
%  The second row specifies the class names, each cell begin a string.
%  (If the second row does not exist, generic class names are defined.)
% OPT: struct or property/value list of optional properties:
%  'RemoveVoidClasses': Void classes are removed from the list of classes,
%     default 0.
%  'KeepAllMarkers': Keep also for markers, which do not belong to any
%     of the specified classes, default 0.
%
%Returns:
% MRK_OUT: Marker structure with classes defined by labels
%     (fields 'y' and 'className')
%
%Example:
% file= 'Gabriel_01_07_24/selfpaced1sGabriel';
% [cnt,mk]= file_readBV(file);
% classDef= {[65 70], [74 192]; 'left','right'};
% mrk= mrk_defineClasses(mk, classDef);
%
% [cnt,mk]= file_readBV(file, 'MarkerFormat','string');
% classDef= {{'S 65','S 70'},{'S 74', 'S192'}; 'left','right'}
% mrk= mrk_defineClasses(mk, classDef);
% %% does the same

props= {'KeepAllMarkers'     0  'BOOL'
        'RemoveVoidClasses'  0  'BOOL'};
props_selectEvents= mrk_selectEvents;

if nargin==0,
  mrk= opt_catProps(props, props_selectEvents);
  return
end

opt= opt_proplistToStruct(varargin{:});
opt= opt_setDefaults(opt, props);
opt_checkProplist(opt, props);

misc_checkType(mk, 'STRUCT(time event)');
misc_checkType(mk.event, 'STRUCT(desc)', 'mk.event');
misc_checkType(classDef, 'CELL');

nClasses= size(classDef,2);
if iscell(mk.event.desc),
  mrk= struct('time', mk.time, 'event',struct('desc',{mk.event.desc}));
else
  mrk= struct('time', mk.time, 'event',struct('desc',mk.event.desc));
end

mrk.y= zeros(nClasses, numel(mrk.time));
for cc= 1:nClasses,
  if isnumeric(classDef{1,cc}),
    % vector as in {[10 11], [20:26];  'target', 'nontarget'}
    mrk.y(cc,:)= ismember(mk.event.desc, classDef{1,cc});
  elseif iscell(classDef{1,cc}),
    % cell of strings as in {{'S 10','S 11'}, {'S 20','S 21'};
    %                        'target',        'nontarget'}
    mrk.y(cc,:)= ismember(mk.event.desc, classDef{1,cc});
  else
    % single string as in {'S10', 'S20';  'target', 'nontarget'}
    mrk.y(cc,:)= ismember(mk.event.desc, classDef(1,cc));
  end
end

if size(classDef,1)>1,
  mrk.className= classDef(2,:);
else
  mrk.className= str_cprintf('class %d', 1:nClasses);
end

if ~opt.KeepAllMarkers,
  opt_selectEvents= opt_substruct(opt, props_selectEvents(:,1));
  mrk= mrk_selectEvents(mrk, 'valid', opt_selectEvents);
end
if opt.RemoveVoidClasses,
  mrk= mrk_removeVoidClasses(mrk);
end


function [stack] = fiff_read_mri(fname,read_data)
%
% [stack] = fiff_read_mri(fname,read_data)
%
% read_data argument is optional, if set to false the pixel data are
% not read. The default is to read the pixel data
%
% Read a fif format MRI description file
%

%
%   Author : Matti Hamalainen, MGH Martinos Center
%   License : BSD 3-clause
%
%
%   Revision 1.5  2009/04/05 13:56:28  msh
%   Fixed a typo in the log messages
%
%   Revision 1.4  2009/04/05 13:50:08  msh
%   Added voxel -> MRI coordinate transform
%
%   Revision 1.3  2009/01/18 23:50:52  msh
%   Handle ushort embedded data correctly
%
%   Revision 1.2  2008/11/17 00:23:51  msh
%   Fixed error in the coordinate system transformation between voxel and RAS coordinates
%
%   Revision 1.1  2006/04/26 19:50:58  msh
%   Added fiff_read_mri
%

global FIFF;
if isempty(FIFF)
    FIFF = fiff_define_constants();
end

me='MNE:fiff_read_mri';

if nargin == 1
    read_data = true;
elseif nargin ~= 2
    error(me,'Incorrect number of arguments');
end
%
%   Try to open the file
%
[ fid, tree ] = fiff_open(fname);
%
%   Locate the data of interest
%   Pick the first MRI set within the first MRI data block
%
mri = fiff_dir_tree_find(tree,FIFF.FIFFB_MRI);
if length(mri) == 0
    fclose(fid);
    error(me,'Could not find MRI data');
end
mri = mri(1);
%
set = fiff_dir_tree_find(mri,FIFF.FIFFB_MRI_SET);
if length(set) == 0
    fclose(fid);
    error(me,'Could not find MRI stack');
end
set = set(1);
%
slices = fiff_dir_tree_find(set,FIFF.FIFFB_MRI_SLICE);
if length(slices) == 0
    fclose(fid);
    error(me,'Could not find MRI slices');
end
%
%   Data ID
%
tag = find_tag(mri,FIFF.FIFF_BLOCK_ID);
if ~isempty(tag)
    stack.id = tag.data;
end
%
%   Head -> MRI coordinate transformation
%   MRI (surface RAS) -> MRI (RAS) transformation
%
stack.trans = [];
stack.ras_trans = [];
for p = 1:set.nent
    kind = set.dir(p).kind;
    if kind == FIFF.FIFF_COORD_TRANS
        tag = fiff_read_tag(fid,set.dir(p).pos);
        if tag.data.to == FIFF.FIFFV_COORD_MRI && tag.data.from == FIFF.FIFFV_COORD_HEAD
            stack.trans = tag.data;
        elseif tag.data.to == FIFF.FIFFV_MNE_COORD_RAS && tag.data.from == FIFF.FIFFV_COORD_MRI
            stack.ras_trans = tag.data;
        end
    end
end
if isempty(stack.trans)
    stack.trans.from  = FIFF.FIFFV_COORD_HEAD;
    stack.trans.to    = FIFF.FIFFV_COORD_MRI;
    stack.trans.trans = eye(4,4);
end
if isempty(stack.ras_trans)
    stack.ras_trans.from   = FIFF.FIFFV_COORD_MRI;
    stack.ras_trans.to     = FIFF.FIFFV_MNE_COORD_RAS;
    stack.ras_trans.trans = eye(4,4);
end
stack.voxel_trans = [];
stack.nslice = length(slices);
if read_data
    fprintf(1,'\tReading slice information and pixel data.');
else
    fprintf(1,'\tReading slice information.');
end
for k = 1:stack.nslice
    try
        stack.slices(k) = read_slice(slices(k));
    catch
        fclose(fid);
        error(me,'%s',mne_omit_first_line(lasterr));
    end
    if mod(k,50) == 0
        fprintf(1,'.%d.',k);
    end
end
fprintf(1,'.%d..[done]\n',k);

add_voxel_transform

fclose(fid);

return;

    function add_voxel_transform

        if stack.nslice < 2
            fprintf(1,'\tOnly one slice in the stack. Voxel transformation will not be included\n');
            return;
        end
        %
        %   Check that the slices really form a stack
        %
        for k = 1:stack.nslice-1
            d = stack.slices(k+1).trans.trans(1:3,4)-stack.slices(k).trans.trans(1:3,4);
            d = sqrt(d'*d);
            if k == 1
                d0 = d;
                r0 = stack.slices(k).trans.trans(1:3,4);
                n0 = stack.slices(k).trans.trans(1:3,3);
            else
                if abs(stack.slices(k).pixel_width-stack.slices(1).pixel_width) > 1e-4 || abs(stack.slices(k).pixel_height-stack.slices(1).pixel_height) > 1e-4
                    fprintf(1,'\tPixel sizes are not equal. Voxel transformation will not be included\n');
                    return;
                end
                if stack.slices(k).width ~= stack.slices(1).width || stack.slices(k).height ~= stack.slices(1).height
                    fprintf(1,'\tImage sizes are not equal. Voxel transformation will not be included\n');
                    return;
                end
                if abs(d-d0) > 1e-4
                    fprintf(1,'\tThe slices are not equally spaced. Voxel transformation will not be included\n');
                    return;
                end
                %
                %   Rectangular volume?
                %
                r1 = r0 + (k-1)*d0*n0;
                d = stack.slices(k).trans.trans(1:3,4) - r1;
                d = sqrt(d'*d);
                if abs(d) > 1e-4
                    fprintf(1,'\tThe slices do not form a rectangular volume. Voxel transformation will not be included\n');
                    return;
                end
            end
        end
        %
        %   Ready to proceed
        %
        voxel_trans = stack.slices(1).trans;
        t = eye(4);
        t(1,1) = stack.slices(1).pixel_width;
        t(2,2) = stack.slices(1).pixel_height;
        d = stack.slices(2).trans.trans(1:3,4)-stack.slices(1).trans.trans(1:3,4);
        t(3,3) = sqrt(d'*d);
        voxel_trans.trans = voxel_trans.trans*t;
        voxel_trans.from  = FIFF.FIFFV_MNE_COORD_MRI_VOXEL;
        stack.voxel_trans = voxel_trans;

        fprintf(1,'\tVoxel transformation added\n');

    end

    function [slice] = read_slice(node)
        %
        %   Read all components of a single slice
        %
        tag = find_tag(node,FIFF.FIFF_COORD_TRANS);
        if isempty(tag)
            error(me,'Could not find slice coordinate transformation');
        end
        slice.trans = tag.data;
        if slice.trans.from ~= FIFF.FIFFV_COORD_MRI_SLICE || ...
                slice.trans.to ~= FIFF.FIFFV_COORD_MRI
            error(me,'Illegal slice coordinate transformation');
        end
        %
        %   Change the coordinate transformation so that
        %   ex is right
        %   ey is down (up in the fif file)
        %   ez steps to the next slice in the series
        %
        slice.trans.trans(1:3,2) = -slice.trans.trans(1:3,2);
        %
        %   Pixel data info
        %
        tag = find_tag(node,FIFF.FIFF_MRI_PIXEL_ENCODING);
        if isempty(tag)
            error(me,'Pixel encoding tag missing');
        end
        slice.encoding = tag.data;
        %
        %    Offset in the MRI data file if not embedded
        %
        tag = find_tag(node,FIFF.FIFF_MRI_PIXEL_DATA_OFFSET);
        if isempty(tag)
            slice.offset = -1;
        else
            slice.offset = tag.data;
        end
        %
        %    Format of the MRI source file
        %
        tag = find_tag(node,FIFF.FIFF_MRI_SOURCE_FORMAT);
        if isempty(tag)
            slice.source_format = 0;
        else
            slice.source_format = tag.data;
        end
        %
        %   Suggested scaling for the pixel values
        %   (not applied here)
        %
        tag = find_tag(node,FIFF.FIFF_MRI_PIXEL_SCALE);
        if isempty(tag)
            slice.scale = 1.0;
        else
            slice.scale = tag.data;
        end
        %
        %   Width and height in pixels
        %
        tag = find_tag(node,FIFF.FIFF_MRI_WIDTH);
        if isempty(tag)
            error(me,'Slice width missing');
        end
        slice.width = tag.data;
        %
        tag = find_tag(node,FIFF.FIFF_MRI_HEIGHT);
        if isempty(tag)
            error(me,'Slice height missing');
        end
        slice.height = tag.data;
        %
        %   Pixel sizes
        %
        tag = find_tag(node,FIFF.FIFF_MRI_WIDTH_M);
        if isempty(tag)
            error(me,'Pixel width missing');
        end
        slice.pixel_width = double(tag.data)/double(slice.width);
        %
        tag = find_tag(node,FIFF.FIFF_MRI_HEIGHT_M);
        if isempty(tag)
            error(me,'Pixel height missing');
        end
        slice.pixel_height = double(tag.data)/double(slice.height);
        %
        %   Are the data here or in another file?
        %
        tag = find_tag(node,FIFF.FIFF_MRI_SOURCE_PATH);
        if isempty(tag)
            slice.offset = -1;
            slice.source = [];
            %
            %   Pixel data are embedded in the fif file
            %
            if read_data
                tag = find_tag(node,FIFF.FIFF_MRI_PIXEL_DATA);
                if isempty(tag)
                    error(me,'Embedded pixel data missing');
                end
                if slice.encoding == FIFF.FIFFV_MRI_PIXEL_WORD
                    if tag.type ~= slice.encoding && tag.type ~= FIFF.FIFFT_USHORT
                        error(me,'Embedded data is in wrong format (expected %d, got %d)',...
                            slice.encoding,tag.type);
                    end
                else
                    if tag.type ~= slice.encoding
                        error(me,'Embedded data is in wrong format (expected %d, got %d)',...
                            slice.encoding,tag.type);
                    end
                end
                if length(tag.data) ~= slice.width*slice.height
                    error(me,'Wrong length of pixel data');
                end
                %
                %   Reshape into an image
                %
                slice.data = reshape(tag.data,slice.width,slice.height)';
            end
        else
            if slice.offset < 0
                error(me,'Offset to external file missing');
            end
            slice.source = tag.data;
            %
            %   External slice reading follows
            %
            if read_data
                pname = search_pixel_file(slice.source,fname);
                if isempty(pname)
                    error(me,'Could not locate pixel file %s',slice.source);
                else
                    try
                        slice.data   = read_external_pixels(pname,...
                            slice.offset,slice.encoding,slice.width,slice.height);
                    catch
                        error(me,'%s',mne_omit_first_line(lasterr));
                    end
                end
            end
        end
    end

    function [name] = search_pixel_file(pname,sname)
        %
        %   First try the file name as it is
        %
        if exist(pname,'file') == 2
            name = pname;
        else
            %
            %   Then <set file dir>/../slices/<slice file name>
            %
            a = findstr(sname,'/');
            if isempty(a)
                d = pwd;
            else
                d = sname(1:a(length(a))-1);
            end
            a = findstr(pname,'/');
            if ~isempty(a)
                pname = pname(a(length(a))+1:length(pname));
            end
            pname = sprintf('%s/../slices/%s',d,pname);
            if exist(pname,'file') == 2
                name = pname;
            else
                name = [];
            end
        end
        return;

    end

    function [pixels] = read_external_pixels(pname,offset,encoding,width,height)
        %
        %   Read pixel data from an external file
        %
        if (encoding == FIFF.FIFFV_MRI_PIXEL_SWAP_WORD)
            sfid = fopen(pname,'rb','ieee-le');
        else
            sfid = fopen(pname,'rb','ieee-be');
        end
        if sfid < 0
            error(me,'Could not open pixel data file : %s',pname);
        end
        try
            fseek(sfid,double(offset),'bof');
        catch
            error(me,'Could not position to pixel data @ %d',offset);
            fclose(sfid);
        end
        %
        %   Proceed carefully according to the encoding
        %
        switch encoding

            case FIFF.FIFFV_MRI_PIXEL_BYTE
                pixels = fread(sfid,double(width*height),'uint8=>uint8');
            case FIFF.FIFFV_MRI_PIXEL_WORD
                pixels = fread(sfid,double(width*height),'int16=>int16');
            case FIFF.FIFFV_MRI_PIXEL_SWAP_WORD
                pixels = fread(sfid,double(width*height),'int16=>int16');
            case FIFF.FIFFV_MRI_PIXEL_FLOAT
                pixels = fread(sfid,double(width*height),'single=>double');
            otherwise
                fclose(sfid);
                error(me,'Unknown pixel encoding : %d',encoding);
        end
        fclose(sfid);
        %
        %   Reshape into an image
        %
        pixels = reshape(pixels,width,height)';
    end

    function [tag] = find_tag(node,findkind)

        for p = 1:node.nent
            kind = node.dir(p).kind;
            pos  = node.dir(p).pos;
            if kind == findkind
                tag = fiff_read_tag(fid,pos);
                return;
            end
        end
        tag = [];
        return

    end

end


%
% FILE NAME:    curateLipidPools.m
%
% PURPOSE: This script revises the formulation of reactions involving lipid
%          and cholesterol-ester pool formation and breakdown in HumanGEM
%          to achieve a more generic and mass-balanced model. In the
%          process, the following changes were made:
%             - 6 new pool reactions
%             - 2 new transport reaction
%             - 16 new pool metabolites (3 unique, ignoring compartment)
%             - 23 pool metabolites were updated to the new metabolites
%
%          Full details on model changes can be found in the generated
%          model change log files (lipidPool_modelChanges_mets.tsv and
%          lipidPool_modelChanges_rxns.tsv)
%
%          This script also removes 3 model fields that are now deprecated:
%             1. proteins
%             2. prRules
%             3. rxnProtMat
%
%          The protein-related fields can simply be regenerated using the
%          translateGrRules function.
%

%% Load Human-GEM and annotation files

% load Human-GEM model
load('HumanGEM.mat');
ihuman_orig = ihuman;  % keep copy of original version

% load metabolite and reaction annotation data
metAssoc = jsondecode(fileread('humanGEMMetAssoc.JSON'));
rxnAssoc = jsondecode(fileread('humanGEMRxnAssoc.JSON'));
changeNotes = {};

% verify that HumanGEM and annotation structures are aligned
if ~isequal(ihuman.mets, metAssoc.mets) || ~isequal(ihuman.rxns, rxnAssoc.rxns)
    error('HumanGEM is not synced with the metAssoc and/or rxnAssoc structure!');
end

%% Remove three deprecated model fields

ihuman = rmfield(ihuman, {'proteins';'prRules';'rxnProtMat'});

%% Add new metabolites

% first need to rename an existing "fatty acid pool" metabolite to avoid confusion
ihuman.metNames(ismember(ihuman.metNames,'fatty acid pool')) = {'fatty acid biomass pool'};

% load new metabolite information from file
fid = fopen('../../ComplementaryData/modelCuration/lipidPools/newLipidPoolMets.tsv');
metData = textscan(fid,'%s%s%s%s%d%s%s%s%s%s%s','Delimiter','\t','Headerlines',1);
fclose(fid);

% verify that none of the metabolite IDs (ignoring compartment) exist in the current model
if any(startsWith(ihuman.mets, regexprep(metData{1},'.$','')))
    error('One or more metabolite IDs to be added already exist in the model.');
end

% add metabolites to the model
metsToAdd = {};
metsToAdd.mets = metData{1};
metsToAdd.metNames = metData{2};
metsToAdd.compartments = metData{3};
metsToAdd.metFormulas = metData{4};
metsToAdd.metCharges = metData{5};
ihuman = addMets(ihuman, metsToAdd);

% add metabolites to the metAssoc structure
numOrigMets = numel(metAssoc.mets);
numNewMets = numel(metData{1});
newMetInd = (numOrigMets+1:numOrigMets+numNewMets)';
f = fieldnames(metAssoc);
for i = 1:numel(f)
    % initialize structure with empty entries
    metAssoc.(f{i})(newMetInd) = {''};
end
metAssoc.mets(newMetInd) = metData{1};
metAssoc.metsNoComp(newMetInd) = regexprep(metData{1},'.$','');
metAssoc.metKEGGID(newMetInd) = metData{6};
metAssoc.metBiGGID(newMetInd) = metData{7};
metAssoc.metChEBIID(newMetInd) = metData{8};
metAssoc.metMetaNetXID(newMetInd) = metData{9};
metAssoc.metLipidMapsID(newMetInd) = metData{10};

changeNotes = [changeNotes; [metsToAdd.mets, metData{11}]];

%% Add new pool reactions

% load new reaction information from file
fid = fopen('../../ComplementaryData/modelCuration/lipidPools/newLipidPoolRxns.tsv');
rxnData = textscan(fid,'%s%s%s%s','Delimiter','\t','Headerlines',1);
fclose(fid);

% verify that none of the reactions exist in the current model
if any(ismember(rxnData{1},ihuman.rxns))
    error('One or more reactions to be added already exist in the model.');
end

% add reactions to the model
rxnsToAdd = {};
rxnsToAdd.rxns = rxnData{1};
rxnsToAdd.rxnNames = rxnData{2};
rxnsToAdd.subSystems = cellfun(@(s) {{s}},rxnData{3});
rxnsToAdd.equations = rxnData{4};
ihuman = addRxns(ihuman, rxnsToAdd, 3);
ihuman.priorCombiningGrRules(end+1:end+numel(rxnsToAdd.rxns)) = {''};

% add reactions to the rxnAssoc structure
numOrigRxns = numel(rxnAssoc.rxns);
numNewRxns = numel(rxnData{1});
newRxnInd = (numOrigRxns+1:numOrigRxns+numNewRxns)';
f = fieldnames(rxnAssoc);
for i = 1:numel(f)
    % initialize structure with empty entries
    rxnAssoc.(f{i})(newRxnInd) = {''};
end
rxnAssoc.rxns(newRxnInd) = rxnData{1};

%% Update cholesterol-ester pool metabolites
% The "cholesterol-ester pool" metabolites will be updated to the new
% "cholesterol-ester plasma pool" metabolites ONLY in the old cholesterol-
% ester pool formation/degradation reactions (HMR_3537 and HMR_3622). All
% other instances of the "cholesterol-ester pool" metabolite will remain
% unchanged.

% HMR_3537 (lysosome)
oldMetInd = getIndexes(ihuman, 'cholesterol-ester pool[l]', 'metscomps');
newMetInd = getIndexes(ihuman, 'cholesterol-ester plasma pool[l]', 'metscomps');
rxnInd = getIndexes(ihuman,'HMR_3537','rxns');
ihuman.S(oldMetInd, rxnInd) = 0;
ihuman.S(newMetInd, rxnInd) = -1;

% HMR_3622 (endoplasmic reticulum)
oldMetInd = getIndexes(ihuman, 'cholesterol-ester pool[r]', 'metscomps');
newMetInd = getIndexes(ihuman, 'cholesterol-ester plasma pool[r]', 'metscomps');
rxnInd = getIndexes(ihuman,'HMR_3622','rxns');
ihuman.S(oldMetInd, rxnInd) = 0;
ihuman.S(newMetInd, rxnInd) = -1;

%% Update fatty acid, 1-acylglycerol-3P, and acyl-CoA pool metabolites
% The old version of these pool metabolites will be updated to their new
% versions in ALL reactions EXCEPT those that involve their formation/
% degradation. The formation/degradation reactions involving the old pool
% metabolites will remain unchanged.

% load list of existing pool reactions related to lipid pools
fid = fopen('../../ComplementaryData/modelCuration/lipidPools/oldLipidPoolRxns.tsv');
filedata = textscan(fid,'%s','Headerlines',1);
fclose(fid);
oldPoolRxns = filedata{1};
oldPoolRxnInd = getIndexes(ihuman, oldPoolRxns, 'rxns');

% load array specifying the conversion from old lipid pool mets to new mets
fid = fopen('../../ComplementaryData/modelCuration/lipidPools/lipidPoolMetReplacements.tsv');
filedata = textscan(fid,'%s%s','Delimiter','\t','Headerlines',1);
fclose(fid);
poolMets = [filedata{1}, filedata{2}];

% replace old pool metabolites with new pool metabolites
for i = 1:size(poolMets,1)
    metComps = unique(ihuman.metComps(ismember(ihuman.metNames, poolMets(i,1))));
    for j = 1:numel(metComps)
        oldMetInd = find(ismember(ihuman.metNames,poolMets(i,1)) & ihuman.metComps == metComps(j));
        newMetInd = find(ismember(ihuman.metNames,poolMets(i,2)) & ihuman.metComps == metComps(j));
        rxnInd = setdiff(find(ihuman.S(oldMetInd,:) ~= 0), oldPoolRxnInd);
        if ~isempty(rxnInd)
            stoichCoeffs = ihuman.S(oldMetInd, rxnInd);
            ihuman.S(oldMetInd, rxnInd) = 0;
            ihuman.S(newMetInd, rxnInd) = stoichCoeffs;
        end
    end
end

% Rename the old pool metabolites, specifying that their composition is
% specific to liver tissue (see Mardinoglu et al. Nat Commun 2014, PMID:24419221)
for i = 1:size(poolMets,1)
    metInd = getIndexes(ihuman, poolMets(i,1), 'metnames');
    ihuman.metNames(metInd) = regexprep(ihuman.metNames(metInd), 'pool$', 'pool (liver tissue)');
end

% Remove old pool metabolites that are no longer used
ihuman = removeReactions(ihuman,[],true);

% Remove 23 unused pool (12 unique) mets from the metAssoc structure
removedMets = setdiff(metAssoc.mets, ihuman.mets);
removedMetsIdx = find(ismember(metAssoc.mets, removedMets));
f = fieldnames(metAssoc);
for i = 1:numel(f)
    metAssoc.(f{i})(removedMetsIdx) = [];
end

%% Identify and document changes to the model

% verify that HumanGEM and annotation structures are aligned
if ~isequal(ihuman.mets, metAssoc.mets) || ~isequal(ihuman.rxns, rxnAssoc.rxns)
    error('HumanGEM is not synced with the metAssoc and/or rxnAssoc structure!');
end

% export reaction and metabolite annotation structures to JSON
jsonStr = jsonencode(rxnAssoc);
fid = fopen('../../ComplementaryData/annotation/humanGEMRxnAssoc.JSON', 'w');
fwrite(fid, prettyJson(jsonStr));
fclose(fid);
jsonStr = jsonencode(metAssoc);
fid = fopen('../../ComplementaryData/annotation/humanGEMMetAssoc.JSON', 'w');
fwrite(fid, prettyJson(jsonStr));
fclose(fid);

% determine and document model changes
modelChanges = docModelChanges(ihuman_orig,ihuman,changeNotes);
writeModelChanges(modelChanges,'../../ComplementaryData/modelCuration/lipidPools/lipidPool_modelChanges.tsv');

% export HumanGEM
exportHumanGEM(ihuman,'HumanGEM','../../',{'mat','yml'},false,false);

% clear unneeded variables
clearvars -except ihuman_orig ihuman modelChanges