function shim = cvx_glpk( shim )

% CVX_SOLVER_SHIM	GLPK interface for CVX.
%   This procedure returns a 'shim': a structure containing the necessary
%   information CVX needs to use this solver in its modeling framework.

if ~isempty( shim.solve ),
    return
end
if isempty( shim.name ),
    fname = 'glpk.m';
    ps = pathsep;
    shim.name = 'GLPK';
    shim.config = struct( 'dualize', 1, 'nonnegative', 1, ...
    	'integer', 1, 'binary', 1 );
    flen = length(fname);
    fpaths = which( fname, '-all' );
    if ~iscell(fpaths),
      fpaths = { fpaths };
    end
    old_dir = pwd;
    oshim = shim;
    shim = [];
    for k = 1 : length(fpaths),
        fpath = fpaths{k};
        if ~exist( fpath, 'file' ) || any( strcmp( fpath, fpaths(1:k-1) ) ),
            continue
        end
        new_dir = fpath(1:end-flen-1);
        cd( new_dir );
        tshim = oshim;
        tshim.fullpath = fpath;
        tshim.version = 'unknown';
        tshim.location = new_dir;
        if isempty( tshim.error ),
            tshim.solve = @solve;
            if k ~= 1,
                tshim.path = [ new_dir, ps ];
            end
        end
        shim = [ shim, tshim ]; %#ok
    end
    cd( old_dir );
    if isempty( shim ),
        shim = oshim;
        shim.error = 'http://glpkmex.sourceforge.net/';
    end
else
    shim.solve = @solve;
end

function [ x, status, tol, iters, y, z ] = solve( At, b, c, nonls, quiet, prec, settings )

n  = length( c );
m  = length( b );
lb = -Inf(n,1);
ub = +Inf(n,1);
vtype = 'C';
vtype = vtype(ones(n,1));
ctype = 'S';
ctype = ctype(ones(m,1));
rr = zeros(0,1);
cc = rr;
vv = rr;
zinv = rr;
is_ip = false;
for k = 1 : length( nonls ),
    temp = nonls( k ).indices;
    tt = nonls( k ).type;
    switch tt,
    case 'nonnegative',
      lb(temp) = 0;
    case 'integer',
      is_ip = true;
      vtype(temp) = 'I';
    case 'binary',
      is_ip = true;
      vtype(temp) = 'I';
      lb(temp) = 0;
      ub(temp) = 1;
    otherwise,
      cvx_throw( 'GLPK does not support nonlinear constraints.' );
    end
end
if ~isempty(rr),
  znorm = [1:n]';
  znorm(zinv) = [];
  rr = [ rr ; znorm ];
  cc = [ cc ; znorm ];
  vv = [ vv ; ones(size(znorm)) ];
  reord = sparse( rr, cc, vv, n, n );
  At = reord' * At;
  c  = reord' * c;
end
if quiet,
  param.msglev = 0;
else
  param.msglev = 2;
end
param.scale = 128;
param.tolbnd = prec(1);
param.toldj = prec(1);
param.tolobj = prec(1);
[ xx, fmin, errnum, extra ] = cvx_run_solver( @glpk, c, At', b, lb, ub, ctype, vtype, 1, param, 'xx', 'fmin', 'errnum', 'extra', settings, 9 ); %#ok
iters = [];
x = full( xx );
y = full( extra.lambda );
z = full( extra.redcosts );
if ~isempty( rr ),
  x = reord * x;
  z = reord * z;
  z(zinv) = z(zinv) * 0.5;
end
status = 'Failed';
switch errnum,
case 0,
  switch extra.status,
  case 2,
    if is_ip,
      status = 'Suboptimal';
    elseif errnumn == 0,
      status = 'Solved';
    else
      status = 'Inaccurate/Solved';
    end
  case {3,4},
    status = 'Infeasible';
  case 5,
    status = 'Solved';
  case 6,
    status = 'Unbounded';
  end
case 10,
  status = 'Infeasible';
case 11,
  status = 'Unbounded';
case {5,17,15,19}
  status = 'Failed';
case {6,7,8,9,13,14},
  switch extra.status,
  case {2,5}
    if is_ip,
      status = 'Suboptimal';
    else
      status = 'Inaccurate/Solved';
    end
  case { 3,4 },
    status = 'Inaccurate/Infeasible';
  case 6,
    status = 'Inaccurate/Unbounded';
  end
end
if strcmp(status,'Failed'),
  tol = Inf;
elseif strncmp(status,'Inaccurate/',11),
  tol = prec(3);
else
  tol = prec(2);
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 output = picker(condition, input1, input2)
    if condition
        output = input1;
    else
        output = input2;
    end
end


function p07_default ( dim_num )

%*****************************************************************************80
%
%% P07_DEFAULT sets default values for problem 07.
%
%  Discussion:
%
%    If a problem uses vector parameters, then the spatial dimension
%    DIM_NUM is needed as input, so that the vector parameters can be
%    properly dimensioned.
%
%    Every problem keeps a count of the number of function calls.  Calling
%    this routine causes that count to be reset to 0.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the dimension of the problem.
%
  i4 = 0;
  p07_i4 ( 'D', '*', i4 );

  return
end


function ChangeBinaryGain(filename,varargin)

%ChangeBinaryGain - Change gain in a multiplexed binary file.
%
%  USAGE
%
%    ChangeBinaryGain(filename,<options>)
%
%    filename       file to read
%    <options>      optional list of property-value pairs (see table below)
%
%    =========================================================================
%     Properties    Values
%    -------------------------------------------------------------------------
%     'output'      output file name (default = append '-gains')
%     'nChannels'   number of data channels in the file (default = 1)
%     'gains'       list of gains for each channel, or one value for all
%     'precision'   sample precision (default = 'int16')
%     'skip'        number of bytes to skip after each value is read
%                   (default = 0)
%    =========================================================================

% Copyright (C) 2004-2011 by Michaël Zugaro
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 3 of the License, or
% (at your option) any later version.

% Default values
nChannels = 1;
precision = 'int16';
warning(['this function assumes int16 precision, if your file is not int16 use load/resample.m'])
skip = 0;
gains = [];
output = [filename '-gains'];

if nargin < 1 | mod(length(varargin),2) ~= 0,
  error('Incorrect number of parameters (type ''help ChangeBinaryGain'' for details).');
end

% Parse options
for i = 1:2:length(varargin),
	if ~ischar(varargin{i}),
		error(['Parameter ' num2str(i+3) ' is not a property (type ''help ChangeBinaryGain'' for details).']);
	end
	switch(lower(varargin{i})),
		case 'output',
			output = varargin{i+1};
			if ~isstring_FMAT(output),
				error('Incorrect value for property ''output'' (type ''help ChangeBinaryGain'' for details).');
			end
		case 'nchannels',
			nChannels = varargin{i+1};
			if ~isiscalar(nChannels,'>0'),
				error('Incorrect value for property ''nChannels'' (type ''help ChangeBinaryGain'' for details).');
			end
		case 'gains',
			gains = varargin{i+1};
			if ~isdvector(gains,'>=0'),
				error('Incorrect value for property ''gains'' (type ''help ChangeBinaryGain'' for details).');
			end
		case 'precision',
			precision = varargin{i+1};
			if ~isstring_FMAT(precision),
				error('Incorrect value for property ''precision'' (type ''help ChangeBinaryGain'' for details).');
			end
		case 'skip',
			skip = varargin{i+1};
			if ~isiscalar(skip,'>=0'),
				error('Incorrect value for property ''skip'' (type ''help ChangeBinaryGain'' for details).');
			end
		otherwise,
			error(['Unknown property ''' num2str(varargin{i}) ''' (type ''help ChangeBinaryGain'' for details).']);
	end
end

% Check output file
f = fopen(output,'r');
if f ~= -1,
	error(['Output file ''' output ''' exists.']);
end

% Check gains
gains = gains(:)';
nGains = length(gains);
if nGains == 1,
	gains = repmat(gains,1,nChannels);
	nGains = nChannels;
elseif nGains ~= nChannels,
	error('Incorrect number of gains (type ''help ChangeBinaryGain'' for details).');
end

% Read in chunks, apply gains and save
offset = 0;
nSamples = floor(100000/nChannels);
while true,
	data = bz_LoadBinary(filename,'nChannels',nChannels,'offset',offset,'samples',nSamples,'precision',precision,'skip',skip);
	data = data .* repmat(gains,size(data,1),1);
	SaveBinary(output,data,'precision',precision,'mode','append');
	offset = offset + nSamples;
	if size(data,1) < nSamples, break; end
end


function out=ctranspose(x)

out=conj(transpose(x));

%%%x=conj(x);
%%%precision=x(1).precision;
%%%out_rval=cell(fliplr(size(x)));
%%%out_ival=cell(fliplr(size(x)));
%%%
%%%xs=size(x)
%%%foo=1;
%%%for jj=1:xs(2)
%%% for ii=1:xs(1)
%%%  [xrval,xrexp,xival,xiexp]=getVals(x,foo);
%%%  out_rval{jj,ii}=xrval;
%%%  out_rexp{jj,ii}=xrexp;
%%%  out_ival{jj,ii}=xival;
%%%  out_iexp{jj,ii}=xiexp;
%%%  foo=foo+1;
%%% end
%%%end
%%%out=class(struct('rval',out_rval,...
%%%                 'rexp',out_rexp,...
%%%                 'ival',out_ival,...
%%%                 'iexp',out_iexp,...
%%%                 'precision',precision),'mp');


function mm_io_test10 ( )

%*****************************************************************************80
%
%% MM_IO_TEST10 tests MM_FILE_READ.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 May 2004
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'MM_IO_TEST10:\n' );
  fprintf ( 1, '  MM_VALUE_READ reads the value records \n' );
  fprintf ( 1, '  of a Matrix Market file.\n' );

  input_filename = 'mm_io_test09.mm';

  input_unit = fopen ( input_filename );

  if ( input_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'MM_IO_TEST10 - Fatal error!\n' );
    fprintf ( 1, '  Could not open the input file.\n' );
    error ( 'MM_IO_TEST10 - Fatal error!' );
  end

  [ id, type, rep, field, symm, nrow, ncol, nnz, indx, jndx, value ) ...
    = mm_file_read ( input_unit );

  fclose ( input_unit );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Here is the information read from the file:\n' );
  fprintf ( 1, '\n' );

  mm_header_print ( input_file, id, type, rep, field, symm );

  mm_size_print ( input_filename, rep, symm, nrow, ncol, nnz );

  mm_values_print ( rep, field, nnz, indx, jndx, value );

  fprintf ( 1, '\n' );
  fprintf ( 1, 'MM_IO_TEST10:\n' );
  fprintf ( 1, '  The MM file "%s" containing \n', input_filename );
  fprintf ( 1, '  the header, comments, size and values, has been read.\n' );
  fprintf ( 1, '\n' );

  return
end


function value = p20_r8_store ( action, name, value )

%*****************************************************************************80
%
%% P20_R8_STORE sets or gets the value of a real parameter for problem 20.
%
%  Discussion:
%
%    The only legal input name is 'hold_value', which indicates the
%    value of the variable to be held fixed.  This variable is given
%    the default value of pi/8.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 October 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string ACTION, either 'get' or 'set'.
%
%    Input, string NAME, the name of the variable.
%
%    Input, real VALUE, the value of the variable to be set,
%    if ACTION is 'set'.
%
%    Output, real VALUE, the value of the variable to get,
%    if ACTION is 'get'
%
  persistent hold_value;

  if ( s_eqi ( action, 'get' ) )

    if ( isempty ( hold_value ) )
      hold_value = 0.39269908169872415481;
    end

    if ( s_eqi ( name, 'hold_value' ) )
      value = hold_value;
    else
      value = [];
      fprintf ( 1, '\n' );
      fprintf ( 1, 'P20_R8_STORE - Fatal error!\n' );
      fprintf ( 1, '  Unexpected "get" of NAME = "%s".\n', name );
      error ( 'P20_R8_STORE - Fatal error!' );
    end

  else if ( s_eqi ( action, 'set' ) )

    if ( s_eqi ( name, 'hold_value' ) )
      hold_value = value;
    else
      fprintf ( 1, '\n' );
      fprintf ( 1, 'P20_R8_STORE - Fatal error!\n' );
      fprintf ( 1, '  Unexpected "set" of NAME = "%s".\n', name );
      error ( 'P20_R8_STORE - Fatal error!' );
    end

  else

    value = [];
    fprintf ( 1, '\n' );
    fprintf ( 1, 'P20_R8_STORE - Fatal error!\n' );
    fprintf ( 1, '  Unexpected ACTION = "%s".\n', action );
    error ( 'P20_R8_STORE - Fatal error!' );

  end

  return
end


%% compare behavior detections for different wild-type strains

%% set up path

if ispc,
  addpath ../../FlyBowlAnalysis;
else
  addpath /groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis;
end
addpath ../perframe;
addpath ../perframe/compute_perframe_features;
addpath ../misc;
addpath ../filehandling;
outfigdir = '../figures/WildtypeOut';
if ~exist(outfigdir,'dir'),
  mkdir(outfigdir);
end

[~,computername] = system('hostname');
computername = strtrim(computername);

switch computername,

  case 'kabram-ws.janelia.priv',
    rootdatadir= '/groups/branson/home/bransonk/behavioranalysis/code/Jdetect/Jdetect/experiments/wildtype/results';

  otherwise,

    rootdatadir = '../experiments/wildtype/results';

end

if ispc,
  addpath C:\Code\FlyBowlAnalysis;
else
  addpath /groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis;
end

%% data locations

expnames = dir(fullfile(rootdatadir,'*201206*'));
expnames(~[expnames.isdir]) = [];
expnames = {expnames.name};
expdirs = cellfun(@(x) fullfile(rootdatadir,x),expnames,'UniformOutput',false);
nexps = numel(expdirs);

scoresfilestrs = dir(fullfile(expdirs{1},'*cores*.mat'));
scoresfilestrs = {scoresfilestrs.name};
scoresfns = cellfun(@(x) x(1:end-4),scoresfilestrs,'UniformOutput',false);
labelfns = regexprep(scoresfns,'scores','labels','preservecase','once');
nbehaviors = numel(labelfns);

%% parameters

linenamecodes = {
  'EXT_CSMH'             'CantonS MH'
  'EXT_CantonS_1220002'  'CantonS UH'
  'EXT_DL'               'Dickinson'
  'FCF_cantons_1500002'  'CantonS GR'
  'UAH_R-1220001'        'OregonR'
  'UAH_R-1220003'        'Berlin'
  };

behaviorcodes = {
  'labels_Walk'          'Walk'
  'labels_Stops'         'Stop'
  'labels_Jump'          'Jump'
  'labels_Righting'      'Righting'
  'labelsWingGrooming'   'Wing grooming'
  'labelsCrabwalk'       'Crabwalk'
  'labelsBackup'         'Backup'
  'labels_pivot_tail'    'Tail pivot turn'
  'labelsTouch'          'Touch'
  'labels_Chasev7'       'Chase'
  };

print_linenames_order = {'Berlin','CantonS MH','CantonS UH','CantonS GR','Dickinson','OregonR'};

%% compute statistics of behavior detections

meanfractime = nan(nexps,nbehaviors);
meanfractime_male = nan(nexps,nbehaviors);
meanfractime_female = nan(nexps,nbehaviors);

for expi = 1:nexps,

  % current experiment
  try
    trx = Trx('trxfilestr','registered_trx.mat','moviefilestr','movie.ufmf','perframedir','perframe');
    trx.AddExpDir(expdirs{expi},'openmovie',false);
  catch ME
    warning(getReport(ME));
    continue;
  end

  % number of frames analyzed
  nframes_total_perfly = trx.nframes;
  nframes_total = sum(nframes_total_perfly);
  nframes_male_perfly = cellfun(@(x) nnz(strcmp(x,'M')),trx.sex);
  nframes_female_perfly = cellfun(@(x) nnz(strcmp(x,'F')),trx.sex);
  nframes_male = sum(nframes_male_perfly);
  nframes_female = sum(nframes_female_perfly);

  % in per-fly std computation, ignore trajectories that are short
  ignoreidx = nframes_total_perfly <= 500;

  fprintf('%s:\n',expnames{expi});

  for behi = 1:nbehaviors,

    % mean, both sexes
    nframes_pos = nnz(cell2mat(trx.(labelfns{behi})));
    nframes_pos_perfly = cellfun(@nnz,trx.(labelfns{behi}));
    fractime_perfly = nframes_pos_perfly ./ nframes_total;
    meanfractime(expi,behi) = nframes_pos / nframes_total;

    % mean, per sex
    nframes_male_pos_perfly = nan(1,trx.nflies);
    nframes_female_pos_perfly = nan(1,trx.nflies);
    for fly = 1:trx.nflies,
      idxmale = strcmp(trx(fly).sex,'M');
      idxfemale = strcmp(trx(fly).sex,'F');
      nframes_male_pos_perfly(fly) = nnz(trx(fly).(labelfns{behi})(idxmale));
      nframes_female_pos_perfly(fly) = nnz(trx(fly).(labelfns{behi})(idxfemale));
    end
    nframes_male_pos = sum(nframes_male_pos_perfly);
    nframes_female_pos = sum(nframes_female_pos_perfly);
    meanfractime_male(expi,behi) = nframes_male_pos / nframes_male;
    meanfractime_female(expi,behi) = nframes_female_pos / nframes_female;

    % std TODO

    fprintf('%s: b = %f, m = %f, f = %f\n',labelfns{behi},...
      meanfractime(expi,behi),...
      meanfractime_male(expi,behi),meanfractime_female(expi,behi));

  end
end

%% z-score the data so that we can plot on the same axes

zmu = nanmean(meanfractime,1);
zsigma = nanstd(meanfractime,1,1);
zmeanfractime = bsxfun(@rdivide,bsxfun(@minus,meanfractime,zmu),zsigma);
zmu_male = nanmean(meanfractime_male,1);
zsigma_male = nanstd(meanfractime_male,1,1);
zmeanfractime_male = bsxfun(@rdivide,bsxfun(@minus,meanfractime_male,zmu_male),zsigma_male);
zmu_female = nanmean(meanfractime_female,1);
zsigma_female = nanstd(meanfractime_female,1,1);
zmeanfractime_female = bsxfun(@rdivide,bsxfun(@minus,meanfractime_female,zmu_female),zsigma_female);

%% compute per-strain data

for i = 1:nexps,
  metadatacurr = parseExpDir(expdirs{i});
  if i == 1,
    metadata = repmat(metadatacurr,[1,nexps]);
  else
    metadata(i) = metadatacurr;
  end
end

line_names = {metadata.line};
[unique_linenames,~,lineidx] = unique(line_names);

nlines = numel(unique_linenames);

meanfractime_line = nan(nlines,nbehaviors);
meanfractime_male_line = nan(nlines,nbehaviors);
meanfractime_female_line = nan(nlines,nbehaviors);
stdfractime_line = nan(nlines,nbehaviors);
stdfractime_male_line = nan(nlines,nbehaviors);
stdfractime_female_line = nan(nlines,nbehaviors);

for linei = 1:nlines,
  meanfractime_line(linei,:) = nanmean(meanfractime(lineidx==linei,:),1);
  stdfractime_line(linei,:) = nanstd(meanfractime(lineidx==linei,:),1,1);
  meanfractime_male_line(linei,:) = nanmean(meanfractime_male(lineidx==linei,:),1);
  stdfractime_male_line(linei,:) = nanstd(meanfractime_male(lineidx==linei,:),1,1);
  meanfractime_female_line(linei,:) = nanmean(meanfractime_female(lineidx==linei,:),1);
  stdfractime_female_line(linei,:) = nanstd(meanfractime_female(lineidx==linei,:),1,1);
end

zmeanfractime_line = bsxfun(@rdivide,bsxfun(@minus,meanfractime_line,zmu),zsigma);
zmeanfractime_male_line = bsxfun(@rdivide,bsxfun(@minus,meanfractime_male_line,zmu_male),zsigma_male);
zmeanfractime_female_line = bsxfun(@rdivide,bsxfun(@minus,meanfractime_female_line,zmu_female),zsigma_female);
zstdfractime_line = bsxfun(@rdivide,stdfractime_line,zsigma);
zstdfractime_male_line = bsxfun(@rdivide,stdfractime_male_line,zsigma_male);
zstdfractime_female_line = bsxfun(@rdivide,stdfractime_female_line,zsigma_female);

%% plot

hfig = 1;
figure(hfig);
clf;
set(hfig,'Position',[80 94 1716 854]);
colors = jet(nlines)*.7;

behaviornames = regexprep(labelfns,'(labels_)|(Labels_)|(labels)|(Labels)','');

combinedzmeanfractime = reshape([zmeanfractime;zmeanfractime_male;zmeanfractime_female],[nexps,nbehaviors*3]);
combinedzmeanfractime_line = reshape([zmeanfractime_line;zmeanfractime_male_line;zmeanfractime_female_line],[nlines,nbehaviors*3]);
combinedzstdfractime_line = reshape([zstdfractime_line;zstdfractime_male_line;zstdfractime_female_line],[nlines,nbehaviors*3]);
combinedbehaviornames = [behaviornames
  cellfun(@(x) [x,'_male'],behaviornames,'UniformOutput',false)
  cellfun(@(x) [x,'_female'],behaviornames,'UniformOutput',false)];
combinedbehaviornames = reshape(combinedbehaviornames,[1,nbehaviors*3]);

hdata = nan(1,nlines);
hold on;
for i = 1:nlines,
  plot((1:3*nbehaviors)-.025+.05*(i-1),combinedzmeanfractime(lineidx==i,:),'.','Color',colors(i,:)*.5+.5);
end
for i = 1:nlines,
  plot(repmat(1:3*nbehaviors,[2,1])-.025+.05*(i-1),...
    bsxfun(@plus,combinedzmeanfractime_line(i,:),[combinedzstdfractime_line(i,:);-combinedzstdfractime_line(i,:)]),...
    '-','Color',colors(i,:));
end
for i = 1:nlines,
  hdata(i) = plot((1:3*nbehaviors)-.025+.05*(i-1),combinedzmeanfractime_line(i,:),'o',...
    'Color',colors(i,:),'MarkerFaceColor',colors(i,:));
end
set(gca,'XTick',1:nbehaviors*3,'XTickLabel',combinedbehaviornames);
rotateticklabel(gca,90)

legend(hdata,unique_linenames,'interpreter','none');
set(gca,'XLim',[0,3*nbehaviors+1]);

ylabel('Z-scored fraction of time');

SaveFigLotsOfWays(hfig,fullfile(outfigdir,'WildtypeBehaviorComparison'));

%% plot by weekend

idxplot = ~cellfun(@isempty,regexp({metadata.date},'^2012060','once'));
meanfractime2 = meanfractime(idxplot,:);
meanfractime_male2 = meanfractime_male(idxplot,:);
meanfractime_female2 = meanfractime_female(idxplot,:);
metadata2 = metadata(idxplot);
nexps2 = nnz(idxplot);

%% z-score the data so that we can plot on the same axes

zmu = nanmean(meanfractime2,1);
zsigma = nanstd(meanfractime2,1,1);
zmeanfractime = bsxfun(@rdivide,bsxfun(@minus,meanfractime2,zmu),zsigma);
zmu_male = nanmean(meanfractime_male2,1);
zsigma_male = nanstd(meanfractime_male2,1,1);
zmeanfractime_male = bsxfun(@rdivide,bsxfun(@minus,meanfractime_male2,zmu_male),zsigma_male);
zmu_female = nanmean(meanfractime_female2,1);
zsigma_female = nanstd(meanfractime_female2,1,1);
zmeanfractime_female = bsxfun(@rdivide,bsxfun(@minus,meanfractime_female2,zmu_female),zsigma_female);

%% compute per-strain data

line_names = {metadata2.line};
[unique_linenames,~,lineidx] = unique(line_names);

nlines = numel(unique_linenames);

meanfractime_line = nan(nlines,nbehaviors);
meanfractime_male_line = nan(nlines,nbehaviors);
meanfractime_female_line = nan(nlines,nbehaviors);
stdfractime_line = nan(nlines,nbehaviors);
stdfractime_male_line = nan(nlines,nbehaviors);
stdfractime_female_line = nan(nlines,nbehaviors);

for linei = 1:nlines,
  meanfractime_line(linei,:) = nanmean(meanfractime2(lineidx==linei,:),1);
  stdfractime_line(linei,:) = nanstd(meanfractime2(lineidx==linei,:),1,1);
  meanfractime_male_line(linei,:) = nanmean(meanfractime_male2(lineidx==linei,:),1);
  stdfractime_male_line(linei,:) = nanstd(meanfractime_male2(lineidx==linei,:),1,1);
  meanfractime_female_line(linei,:) = nanmean(meanfractime_female2(lineidx==linei,:),1);
  stdfractime_female_line(linei,:) = nanstd(meanfractime_female2(lineidx==linei,:),1,1);
end

zmeanfractime_line = bsxfun(@rdivide,bsxfun(@minus,meanfractime_line,zmu),zsigma);
zmeanfractime_male_line = bsxfun(@rdivide,bsxfun(@minus,meanfractime_male_line,zmu_male),zsigma_male);
zmeanfractime_female_line = bsxfun(@rdivide,bsxfun(@minus,meanfractime_female_line,zmu_female),zsigma_female);
zstdfractime_line = bsxfun(@rdivide,stdfractime_line,zsigma);
zstdfractime_male_line = bsxfun(@rdivide,stdfractime_male_line,zsigma_male);
zstdfractime_female_line = bsxfun(@rdivide,stdfractime_female_line,zsigma_female);

%% plot

hfig = 2;
figure(hfig);
clf;
set(hfig,'Units','pixels','Position',[80 94 1716 854]);
%colors = jet(nlines)*.7;
colors = lines(nlines);

behaviornames = regexprep(labelfns,'(labels_)|(Labels_)|(labels)|(Labels)','');

combinedzmeanfractime = reshape([zmeanfractime;zmeanfractime_male;zmeanfractime_female],[nexps2,nbehaviors*3]);
combinedzmeanfractime_line = reshape([zmeanfractime_line;zmeanfractime_male_line;zmeanfractime_female_line],[nlines,nbehaviors*3]);
combinedzstdfractime_line = reshape([zstdfractime_line;zstdfractime_male_line;zstdfractime_female_line],[nlines,nbehaviors*3]);
combinedbehaviornames = [behaviornames
  cellfun(@(x) [x,'_male'],behaviornames,'UniformOutput',false)
  cellfun(@(x) [x,'_female'],behaviornames,'UniformOutput',false)];
combinedbehaviornames = reshape(combinedbehaviornames,[1,nbehaviors*3]);

hdata = nan(1,nlines);
hold on;
for i = 1:nlines,
  plot((1:3*nbehaviors)-.025+.05*(i-1),combinedzmeanfractime(lineidx==i,:),'.','Color',colors(i,:)*.5+.5);
end
for i = 1:nlines,
  plot(repmat(1:3*nbehaviors,[2,1])-.025+.05*(i-1),...
    bsxfun(@plus,combinedzmeanfractime_line(i,:),[combinedzstdfractime_line(i,:);-combinedzstdfractime_line(i,:)]),...
    '-','Color',colors(i,:));
end
for i = 1:nlines,
  hdata(i) = plot((1:3*nbehaviors)-.025+.05*(i-1),combinedzmeanfractime_line(i,:),'o',...
    'Color',colors(i,:),'MarkerFaceColor',colors(i,:));
end
set(gca,'XTick',1:nbehaviors*3,'XTickLabel',combinedbehaviornames);
rotateticklabel(gca,90)

legend(hdata,unique_linenames,'interpreter','none');
set(gca,'XLim',[0,3*nbehaviors+1]);

ylabel('Z-scored fraction of time');

SaveFigLotsOfWays(hfig,fullfile(outfigdir,'WildtypeBehaviorComparison_Weekend2'));

%% plot each behavior separately

[~,idx] = ismember(unique_linenames,linenamecodes(:,1));
print_linenames = linenamecodes(idx,2)';

[~,idx] = ismember(labelfns,behaviorcodes(:,1));
behaviors = behaviorcodes(idx,2)';

hfig = 3;
figure(hfig);
clf;
set(hfig,'Units','pixels','Position',[100,100,1400 1000]);
hax = createsubplots(5,2,[[.05,.05];[.05,.01]]);

hbar = nan(3,nbehaviors);

datacolors = [0,0,0;0,0,.5;.5,0,0];
datanames = {'Both','Male','Female'};
grp1 = repmat(print_linenames(lineidx)',[1,3]);
grp2 = repmat(datanames,[nexps2,1]);
grporder = cell(3,nlines);
for i = 1:nlines,
  for j = 1:3,
    grporder{j,i} = sprintf('%s,%s',print_linenames_order{i},datanames{j});
  end
end
grporder = grporder(:);

for behi = 1:nbehaviors,

  axes(hax(behi));

%   v = [meanfractime_line(:,behi),meanfractime_male_line(:,behi),meanfractime_female_line(:,behi)];
%   s = [stdfractime_line(:,behi),stdfractime_male_line(:,behi),stdfractime_female_line(:,behi)];
  p = [meanfractime2(:,behi),meanfractime_male2(:,behi),meanfractime_female2(:,behi)];
%   hbar(:,behi) = bar(1:nlines,v,'grouped');
%   for i = 1:3,
%     set(hbar(i,behi),'FaceColor',datacolors(i,:));
%   end
%   hold on;
%   for i = 1:3,
%     x = mean(get(get(hbar(i,behi),'Children'),'XData'),1);
%     herr(i,behi) = errorbar(x,v(:,i),s(:,i),'linestyle','none','color',[.5,.5,.5]);
%     hexp(i,behi) = plot(x(lineidx),p(:,i),'.','color',[0,.5,.5]);
%   end

  hb = boxplot(p(:),{grp1(:),grp2(:)},...
  'ColorGroup',grp2(:),...
  'GroupOrder',grporder,...
  'PlotStyle','traditional',...
  'FactorDirection','list',...
  'labelverbosity','minor',...
  'colors',datacolors,...
  'symbol','+');

  hxlabel = findobj(get(hb(1),'Parent'),'Type','text');
  delete(hxlabel);

  if behi == 1,
    for i = 1:3,
      hdcurr = findobj(get(hb(1),'Parent'),'Type','line','Color',datacolors(i,:),'Marker','none','LineStyle','-');
      hd(i) = hdcurr(1);
    end
    legend(hd,datanames);
  end
  ylabel(sprintf('Frac. time %s',lower(behaviors{behi})));

  if mod(behi,5) == 0,
    set(gca,'XTick',2:3:3*nlines,'XTickLabel',print_linenames_order);
  else
    set(gca,'XTick',2:3:3*nlines,'XTickLabel',{});
  end

  %set(gca,'YLim',[0,max(v(:)+s(:))*1.025]);
  %set(gca,'XLim',[.5,nlines+.5]);

end

SaveFigLotsOfWays(hfig,fullfile(outfigdir,'WildtypeBehaviorComparison_Weekend2_PerBehaviorBoxPlots'));

%% plot each behavior separately, only plot both statistics

[~,idx] = ismember(unique_linenames,linenamecodes(:,1));
print_linenames = linenamecodes(idx,2)';

% [~,idx] = ismember(labelfns,behaviorcodes(:,1));
% behaviors = behaviorcodes(idx,2)';

ndx2meanfrac = [];
behaviors = {};
for ndx = 1:numel(behaviorcodes(:,1))
  ndx2labelfns = find(cellfun(@(x) strcmp(x,behaviorcodes{ndx,1}),labelfns));
  behaviors{ndx} = behaviorcodes{ndx,2};
  ndx2meanfrac(ndx) = ndx2labelfns;
end
nbehaviors = numel(behaviors);

hfig = 4;
figure(hfig);
clf;
set(hfig,'Units','pixels','Position',[100,100,1400 1000]);
hax = createsubplots(5,2,[[.05,.05];[.05,.01]]);

hbar = nan(3,nbehaviors);

%datacolors = [0,0,0;0,0,.5;.5,0,0];
%datanames = {'Both','Male','Female'};
grp1 = print_linenames(lineidx)';
%grp1 = repmat(print_linenames(lineidx)',[1,3]);
%grp2 = repmat(datanames,[nexps2,1]);
grporder = print_linenames_order;
% grporder = cell(3,nlines);
% for i = 1:nlines,
%   for j = 1:3,
%     grporder{j,i} = sprintf('%s,%s',print_linenames_order{i},datanames{j});
%   end
% end
% grporder = grporder(:);

for behi = 1:nbehaviors,

  axes(hax(behi));

%   v = [meanfractime_line(:,behi),meanfractime_male_line(:,behi),meanfractime_female_line(:,behi)];
%   s = [stdfractime_line(:,behi),stdfractime_male_line(:,behi),stdfractime_female_line(:,behi)];
  %p = [meanfractime2(:,behi),meanfractime_male2(:,behi),meanfractime_female2(:,behi)];
  p = [meanfractime2(:,ndx2meanfrac(behi))];
%   hbar(:,behi) = bar(1:nlines,v,'grouped');
%   for i = 1:3,
%     set(hbar(i,behi),'FaceColor',datacolors(i,:));
%   end
%   hold on;
%   for i = 1:3,
%     x = mean(get(get(hbar(i,behi),'Children'),'XData'),1);
%     herr(i,behi) = errorbar(x,v(:,i),s(:,i),'linestyle','none','color',[.5,.5,.5]);
%     hexp(i,behi) = plot(x(lineidx),p(:,i),'.','color',[0,.5,.5]);
%   end

  hb = boxplot(p(:),grp1(:),...
  'GroupOrder',grporder,...
  'colors',[0,0,0],...
  'symbol','+');

  hxlabel = findobj(get(hb(1),'Parent'),'Type','text');
  delete(hxlabel);

%   if behi == 1,
%     for i = 1:3,
%       hdcurr = findobj(get(hb(1),'Parent'),'Type','line','Color',datacolors(i,:),'Marker','none','LineStyle','-');
%       hd(i) = hdcurr(1);
%     end
%     legend(hd,datanames);
%   end
  ylabel(sprintf('Frac. time %s',lower(behaviors{behi})));

  if mod(behi,5) == 0,
    set(gca,'XTick',1:nlines,'XTickLabel',print_linenames_order);
  else
    set(gca,'XTick',1:nlines,'XTickLabel',{});
  end
  set(gca,'box','off');
  set(get(gca,'XLabel'),'FontSize',16);
  set(get(gca,'YLabel'),'FontSize',16);
  set(gca,'FontSize',16);

  %set(gca,'YLim',[0,max(v(:)+s(:))*1.025]);
  %set(gca,'XLim',[.5,nlines+.5]);

end

SaveFigLotsOfWays(hfig,fullfile(outfigdir,'WildtypeBehaviorComparison_Weekend2_PerBehaviorBoxPlots_BothOnly'));

%% Save the Data..

save(fullfile(outfigdir,['WildtypeBehaviorComparison_ResultsData']),'behaviornames','labelfns',...
  'meanfractime2','metadata2','scoresfns');

%% use logistic regression to predict the strain given the behavior classification results for each pair

% reorder line names
print_linenames_perexp = print_linenames(lineidx);
[~,orderedlineidx] = ismember(print_linenames_perexp,print_linenames_order);

% X is nexps x nbehaviors
X = meanfractime2;
y = orderedlineidx';
isbaddata = any(isnan(X),2);
X(isbaddata,:) = [];
y(isbaddata) = [];
errorrate = zeros(nlines,nlines);
errorrate(:) = .5;
for line1 = 1:nlines,
  idx1 = line1 == y;
  for line2 = line1+1:nlines,
    idx2 = line2 == y;
    idxcurr = idx1 | idx2;
    ncurr = nnz(idxcurr);
    Xcurr = X(idxcurr,:);
    % 1 means line1, 0 means line2
    ycurr = idx1(idxcurr);
    % loop over all examples for cross validation

    yfitcurr = nan(ncurr,1);
    for i = 1:ncurr,

      % logistic regression
      idxtrain = true(ncurr,1); idxtrain(i) = false;
      coeffscurr = glmfit(Xcurr(idxtrain,:),ycurr(idxtrain),'binomial','link','logit');
      yfitcurr(i) = glmval(coeffscurr,Xcurr(i,:),'logit');

    end

    errorcurr = nnz( (yfitcurr>.5) ~= ycurr );
    errorrate(line1,line2) = errorcurr / ncurr;
    errorrate(line2,line1) = errorrate(line1,line2);
  end
end

hfig = 5;
figure(hfig);
clf;

imagesc(errorrate,[0,.5]);
colormap gray;
set(gca,'XTick',1:nlines,'XTickLabel',print_linenames_order,...
  'YTick',1:nlines,'YTickLabel',print_linenames_order,'Box','off');
axis image;
colorbar;
title('Pairwise error rate');

errorrate0 = errorrate;

%% use regularized logistic regression to predict the strain given the behavior classification results for each pair

% reorder line names
print_linenames_perexp = print_linenames(lineidx);
[~,orderedlineidx] = ismember(print_linenames_perexp,print_linenames_order);
nlambda = 10;

% X is nexps x nbehaviors
X = meanfractime2;
y = orderedlineidx';
isbaddata = any(isnan(X),2);
X(isbaddata,:) = [];
y(isbaddata) = [];
errorrate = zeros(nlines,nlines);
errorrate(:) = .5;
for line1 = 1:nlines,
  idx1 = line1 == y;
  for line2 = line1+1:nlines,
    idx2 = line2 == y;
    idxcurr = idx1 | idx2;
    ncurr = nnz(idxcurr);
    Xcurr = X(idxcurr,:);
    % 1 means line1, 0 means line2
    ycurr = idx1(idxcurr);
    % loop over all examples for cross validation

    yfitcurr = nan(ncurr,1);
    for i = 1:ncurr,

      % logistic regression
      idxtrain = true(ncurr,1); idxtrain(i) = false;
      [coeffscurr,fitinfo] = lassoglm(Xcurr(idxtrain,:),ycurr(idxtrain),'binomial','link','logit',...
        'NumLambda',nlambda,'CV',ncurr-1);
      j = fitinfo.Index1SE;
      coeffscurr0 = coeffscurr(:,j);
      cnst = fitinfo.Intercept(j);
      coeffscurr1 = [cnst;coeffscurr0];
      yfitcurr(i) = glmval(coeffscurr1,Xcurr(i,:),'logit');
    end

    errorcurr = nnz( (yfitcurr>.5) ~= ycurr );
    errorrate(line1,line2) = errorcurr / ncurr;
    errorrate(line2,line1) = errorrate(line1,line2);
  end
end

hfig = 6;
figure(hfig);
clf;

imagesc(errorrate,[0,.5]);
colormap gray;
set(gca,'XTick',1:nlines,'XTickLabel',print_linenames_order,...
  'YTick',1:nlines,'YTickLabel',print_linenames_order,'Box','off');
xlabel('Wildtype strains');ylabel('Wildtype strains');
axis image;
colorbar;
title('Pairwise error rate');

error_rate = errorrate;
axis image;
box off;
numel(error_rate)
size(error_rate)
[Row,Col]= size(error_rate);
for i = 1:Row
  for j = 1:Col
    if i==j; continue; end
    if errorrate(i,j) ==0; continue; end
    ht(i,j) = text(j,i,sprintf('%.2f',error_rate(i,j)),...
      'FontUnits','pixels','FontWeight','bold','Color',[.7,0,0],...
      'HorizontalAlignment','center','VerticalAlignment','middle',...
      'FontSize',24);
  end
end

SaveFigLotsOfWays(hfig,fullfile(outfigdir,'WildTypeStrainPrediction_PairwiseErrorRate'));

save('WildTypeStrainPredictionData.mat','errorrate','print_linenames_order');

%     'Berlin'    'CantonS MH'    'CantonS UH'    'CantonS GR'    'Dickinson'    'OregonR'
% errorrate =
%     0.5000         0    0.0714    0.0625         0         0
%          0    0.5000    0.0714         0         0         0
%     0.0714    0.0714    0.5000         0         0         0
%     0.0625         0         0    0.5000    0.0625         0
%          0         0         0    0.0625    0.5000    0.0588
%          0         0         0         0    0.0588    0.5000


function  [n,dspchans] = plx_chanmap(filename)
% plx_chanmap(filename): return map of raw DSP channel numbers for each channel
%
% [n,dspchans] = plx_chanmap(filename)
%
% INPUT:
%   filename - if empty string, will use File Open dialog
%
% OUTPUT:
%   n - number of spike channels
%   dspchans - 1 x n array of DSP channel numbers
%
% Normally, there is one channel entry in the .plx for for each raw DSP channel,
% so the mapping is trivial dspchans[i] = i.
% However, for certain .plx files saved in some ways from OFS (notably after
% loading data files from other vendors), the mapping can be more complex.
% E.g. there may be only 2 non-empty channels in a .plx file, but those channels
% correspond to raw DSP channel numbers 7 and 34. So in this case NChans = 2,
% and dspchans[1] = 7, dspchans[2] = 34.
% The plx_ routines that return arrays always return arrays of size NChans. However,
% routines that take channels numbers as arguments always expect the raw DSP
% channel number.  So in the above example, to get the timestamps from unit 4 on
% the second channel, use
%   [n,ts] = plx_ts(filename, dspchans[2], 4 );

if nargin ~= 1
    error 'expected 1 input argument';
end

[ filename, isPl2 ] = internalPL2ResolveFilenamePlx( filename );
if isPl2 == 1
    pl2 = PL2GetFileIndex(filename);
    n = numel(pl2.SpikeChannels);
    dspchans = 1:n;
    return;
end

[n,dspchans] = mexPlex(26, filename);

end


function [modelOut,nTotalAtomTransitions] = checkRXNFiles(model, RXNFileDir)
% Checks whether the set of RXN files coresponding to a model have the consistent stoichiometry and are elementally balanced
%
% INPUTS:
%    model:         Directed stoichiometric hypergraph
%                   Represented by a matlab structure with following fields:
%
%                     * .S - The `m` x `n` stoichiometric matrix for the metabolic network
%                     * .model.mets - An `m` x 1 array of metabolite identifiers. Should match
%                       metabolite identifiers in `RXNfiles`.
%                     * .model.rxns - An `n` x 1 array of reaction identifiers. Should match
%                       RXNfile names in `RXNFileDir`.
%                     * .lb -  An `n` x 1 vector of lower bounds on fluxes.
%                     * .ub - An `n` x 1 vector of upper bounds on fluxes.
%
%    RXNFileDir:    Path to directory containing `RXNfiles` with atom mappings
%                   for internal reactions in `S`. File names should
%                   correspond to reaction identifiers in input `model.rxns`.
%                   e.g. git clone https://github.com/opencobra/ctf ~/fork-ctf
%                        then RXNFileDir = ~/fork-ctf/rxns/atomMapped
%
% OUTPUT:
% metRXNBool: `m` x 1 vector, true if metabolite identified in at least one RXN file
% RXNBool: `n` x 1 boolean vector, true if RXN file exists
% RXNParsedBool: `n` x 1 boolean vector, true if RXN file could be parsed
% RXNAtomsConservedBool: `n` x 1 boolean vector, true if atoms in RXN file are conserved
% RXNStoichiometryMatchBool:  `n` x 1 boolean vector, true if RXN stoichiometry matches model.S stoichiometry
% RXNStoichiometryMatchUptoProtonsBool:   `n` x 1 boolean vector, true if RXN stoichiometry matches model.S stoichiometry when ingnoring protons.
% RXNSubstrateTransitionNumbersOrdered:   `n` x 1 boolean vector, true if RXN file with substrate transition numbers ordered 1:q.
% RXNProductTransitionNumbersOrdered:   `n` x 1 boolean vector, true if RXN file with product transition numbers ordered 1:q.
% RXNTransitionNumbersMatching:    `n` x 1 boolean vector, true if RXN file with matching numbering of atoms between substrates and products.
% RXNMatchingElementBool:     `n` x 1 boolean vector, true if RXN file with matching elements between substrates and products.
%
% .. Authors: - Ronan M. T. Fleming, 2022.

fprintf('Checking quality of RXN files...\n');

if ~exist('RXNFileDir','var')
    RXNFileDir=pwd;
end
RXNFileDir = [regexprep(RXNFileDir,'(/|\\)$',''), ''];

[nMets,nRxns]= size(model.S);
if length(unique(model.mets))~=nMets
    disp(setdiff(model.mets,unique(model.mets)))
    error('duplicate metabolites')
end
if length(unique(model.rxns))~=nRxns
    disp(setdiff(model.rxns,unique(model.rxns)))
    error('duplicate reactions')
end

[metRXNBool,RXNBool,internalRxnBool] = findRXNFiles(model,RXNFileDir);

%preallocate outputs
RXNParsedBool = NaN*ones(nRxns,1);
RXNAtomsConservedBool = NaN*ones(nRxns,1);
RXNStoichiometryMatchBool = NaN*ones(nRxns,1);
RXNStoichiometryMatchUptoProtonsBool = NaN*ones(nRxns,1);
RXNSubstrateTransitionNumbersOrdered = NaN*ones(nRxns,1);
RXNTransitionNumbersMatching = NaN*ones(nRxns,1);
RXNProductTransitionNumbersOrdered = NaN*ones(nRxns,1);
RXNMatchingElementBool = NaN*ones(nRxns,1);

%identify the protons in the atom mapped subset
pat = '[' + lettersPattern(1) + ']';
hBool = strcmp(model.mets,'h') | matches(model.mets,pat);

checkDecompartmentaliseRXN=1;
printAtomTransitionStats=0;
nTotalAtomTransitions = 0;
for i = 1:nRxns
    if RXNBool(i)

        if checkDecompartmentaliseRXN==1
            % Read atom mapping from RXNfile to test if it is decompartmentalised
            [atomMets,metEls, metNrs, atomTransitionNrs,isSubstrate,instances] = readRXNFile(model.rxns{1},RXNFileDir);

            decompartmentaliseRXN=0;
            atomMetAbbr  = atomMets{1};
            metAbbr = model.mets{1};
            if ~strcmp(atomMetAbbr(end),metAbbr(end))
                if strcmp(atomMetAbbr(end),']')
                    decompartmentaliseRXN=1;
                elseif strcmp(metAbbr(end),']')
                    for j=1:length(model.mets)
                        model.mets{j} = model.mets{j}(1:end-2);
                    end
                end
                checkDecompartmentaliseRXN=0;
            end
        end
        rxn = model.rxns{i};

        if strcmp(rxn,'AKGDm')
            %disp(rxn)
        end

        try
            %read in each RXN file
            [atomMets,metEls, metNrs, atomTransitionNrs,isSubstrate,instances] = readRXNFile(rxn,RXNFileDir);

            if decompartmentaliseRXN
                for k=1:length(atomMets)
                    atomMets{k,1}=atomMets{k,1}(1:end-3);
                end
            end
            RXNParsedBool(i)=1;
        catch ME
            RXNParsedBool(i)=0;
            fprintf('%s%s\n',rxn,' could not be parsed.');
            disp(getReport(ME))
        end

        %check there are an even number of atoms in the rxn file
        if mod(length(metEls),2)==0
            RXNAtomsConservedBool(i)=1;
        else
            RXNAtomsConservedBool(i)=0;
            rxnFormula = printRxnFormula(model, 'rxnAbbrList',model.rxns{i},'printFlag',0);
            fprintf('%s%s%s%s\n',rxn,' ',rxnFormula{1},' does not conserve atoms.');
        end

        % Check that stoichiometry in rxnfile matches the one in S
        rxnMets = unique(atomMets);
        ss = model.S(:,i);
        as = zeros(size(ss));
        for j = 1:length(rxnMets)
            rxnMet = rxnMets{j};

            if isSubstrate(strcmp(atomMets,rxnMet))
                as(strcmp(model.mets,rxnMet)) = -max(instances(strcmp(atomMets,rxnMet)));
            else

                as(strcmp(model.mets,rxnMet)) = max(instances(strcmp(atomMets,rxnMet)));
            end
        end
        if all(as == ss)
            RXNStoichiometryMatchBool(i)=1;
        else
            RXNStoichiometryMatchBool(i)=0;
            if all(as == ss  | hBool)
                fprintf('%s%s\n',rxn, ' stoichiometry matches upto protons.')
                RXNStoichiometryMatchUptoProtonsBool(i)=1;
            else
                RXNStoichiometryMatchUptoProtonsBool(i)=0;
                fprintf('%s%s\n',rxn, ' stoichiometry in model and RXNfile do not match:')
                fprintf('%s\t,', 'In model:')
                printRxnFormula(model,'rxnAbbrList',rxn)
                fprintf('%s\t,', 'In RXNfile:')
                model.S(:,ismember(model.rxns,rxn))=as;
                printRxnFormula(model,'rxnAbbrList',rxn)
                fprintf('\n');
            end
        end

        %checks specific for atom transitions
        if ~all(atomTransitionNrs==0)
            if printAtomTransitionStats == 0
                printAtomTransitionStats=1;
            end
            if all(sort(atomTransitionNrs(isSubstrate)) == (1:sum(isSubstrate))')
                RXNSubstrateTransitionNumbersOrdered(i)=1;
            else
                RXNSubstrateTransitionNumbersOrdered(i)=0;
                fprintf([rxn, '.rxn, Substrate transition numbers not ordered 1:q.\n'])
            end
            if all(all(sort(atomTransitionNrs(~isSubstrate)) == (1:sum(~isSubstrate))'))
                RXNProductTransitionNumbersOrdered(i)=1;
            else
                RXNProductTransitionNumbersOrdered(i)=0;
                fprintf([rxn, '.rxn, Product transition numbers not ordered 1:q.\n'])
            end
            if all(sort(atomTransitionNrs(isSubstrate)) == sort(atomTransitionNrs(~isSubstrate)))
                RXNTransitionNumbersMatching(i)=1;
            else
                RXNTransitionNumbersMatching(i)=0;
                fprintf([rxn, '.rxn, Substrate and product transition numbers not matching order 1:q.\n'])
            end

            nAtomTransitions = max(atomTransitionNrs);
            matchingElementBool=false(nAtomTransitions,1);
            for k=1:nAtomTransitions
                if strcmp(metEls(atomTransitionNrs==k & isSubstrate),metEls(atomTransitionNrs==k & ~isSubstrate))
                    matchingElementBool(k)=1;
                end
            end
            if all(matchingElementBool)
                RXNMatchingElementBool(i)=1;
            else
                RXNMatchingElementBool(i)=0;
                fprintf('%s%s%s%s%u%s\n',RXNfileName,' ',rxnFormula,' contains ', nnz(~matchingElementBool), ' atom transitions violating elemental conservation.');
            end
            %calculate the total number of atom transitions
            nTotalAtomTransitions  = nTotalAtomTransitions + nAtomTransitions;
        end
    end
end

if printAtomTransitionStats
    fprintf('\n%s\n','RXN file with atom mapping summary:')
else
    fprintf('\n%s\n','RXN file summary:')
end
fprintf('%u%s\n',nMets,' metabolites in model')
fprintf('%u%s\n',nnz(metRXNBool),' metabolites in atom mapped subset of model')
fprintf('%u%s\n',nRxns,' reactions in model')
fprintf('%u%s\n',nnz(internalRxnBool),' internal reactions in model')
fprintf('%u%s\n',nnz(RXNBool),' reactions in atom mapped subset of model')
fprintf('%u%s\n',nnz(RXNParsedBool==1),' RXN files parsed.')
fprintf('%u%s\n',nnz(RXNAtomsConservedBool==1),' RXN files with the number of atom conserved between substrates and products.')
fprintf('%u%s\n',nnz(RXNStoichiometryMatchBool==1),' RXN files matching stoichiometry of the model.')
fprintf('%u%s\n',nnz(internalRxnBool & RXNStoichiometryMatchUptoProtonsBool==1),' RXN files matching stoichiometry of the model, upto protons.')
fprintf('%u%s\n',nnz(internalRxnBool & RXNStoichiometryMatchBool~=1 & ~(RXNStoichiometryMatchUptoProtonsBool==1)),' RXN files not matching stoichiometry of model, even ignoring protons.')
if printAtomTransitionStats
    fprintf('%u%s\n',nnz(RXNSubstrateTransitionNumbersOrdered==1),' RXN files with substrate transition numbers ordered 1:q.')
    fprintf('%u%s\n',nnz(RXNProductTransitionNumbersOrdered==1),' RXN files with product transition numbers ordered 1:q.')
    fprintf('%u%s\n',nnz(RXNTransitionNumbersMatching==1),' RXN files with matching numbering of atoms between substrates and products.')
    fprintf('%u%s\n',nnz(RXNMatchingElementBool==1),' RXN files with matching elements between substrates and products.')
end

model.metRXNBool=metRXNBool;
model.RXNBool=RXNBool;
model.RXNParsedBool=RXNParsedBool;
model.RXNAtomsConservedBool=RXNAtomsConservedBool;
model.RXNStoichiometryMatchBool=RXNStoichiometryMatchBool;
model.RXNStoichiometryMatchUptoProtonsBool=RXNStoichiometryMatchUptoProtonsBool;
model.RXNSubstrateTransitionNumbersOrdered=RXNSubstrateTransitionNumbersOrdered;
model.RXNProductTransitionNumbersOrdered=RXNProductTransitionNumbersOrdered;
model.RXNTransitionNumbersMatching=RXNTransitionNumbersMatching;
model.RXNMatchingElementBool=RXNMatchingElementBool;
modelOut=model;


function [resources] = getResourcesStruct(resDblArr, numDbl)
%getResourcesStruct Summary of this function goes here
%   Detailed explanation goes here

    r = readPartStrAndDblsFromDblArr(resDblArr, numDbl);

    resources = struct();
    for(i=1:size(r,1))
        resourcePart = r{i,1};
        split = strsplit(resourcePart, '/_/_/');
        resName = lower(split{1});

        if(~isfield(resources,resName))
            resources.(resName) = cell(0);
        end

        rArrOrig = resources.(resName);
        rArr = [split, r{i,2:end}];
        rArrOrig(end+1,:) = rArr;

        resources.(resName) = rArrOrig;
    end
end


function out = double(fa)
% Convert to double precision
% FORMAT double(fa)
% fa - a file_array
%__________________________________________________________________________
% Copyright (C) 2005-2018 Wellcome Trust Centre for Neuroimaging

%
% $Id: double.m 7501 2018-11-30 12:16:58Z guillaume $

out = double(full(fa));


function [txt_han,txt_lft] = coefdisp(txt_lft,txt_btm,coeffs,paren,data)
% COEFDISP Display of coefficients.

% Author: Craig Borghesani
% Date: 11/15/94
% Revised:
% Copyright (c) 1999, Prentice-Hall

len_coeff = length(coeffs);
txtct = 1;
ers = 'norm';
fontname = 'times';

for loc_coeff = 1:len_coeff,

 cur_coeff = coeffs(loc_coeff);
 power = len_coeff - loc_coeff;

 if cur_coeff~=0,
  coeff_str = num2str(abs(cur_coeff));
  if power > 0 & abs(cur_coeff) == 1,
   coeff_str = [];
  end

  if cur_coeff > 0 & loc_coeff > 1,
   coeff_str = ['+',coeff_str];
  elseif cur_coeff < 0,
   coeff_str = ['-',coeff_str];
  end

  if power > 0,
   cur_str = [coeff_str,'s'];
  else
   cur_str = coeff_str;
  end

  if paren,
   if loc_coeff == 1,
    cur_str = ['(',cur_str];
   elseif loc_coeff == len_coeff,
    cur_str = [cur_str,')'];
   end
  end

  txt_han(txtct) = text(txt_lft,txt_btm,cur_str,'erase',ers,...
              'horizontalalignment','left','verticalalignment','bottom',...
              'fontname',fontname);
  set(txt_han(txtct),'userdata',data);
  txt_ext = get(txt_han(txtct),'extent');
  txt_lft = txt_lft + txt_ext(3);
  txtct=txtct+1;

  if power > 1,
   sup_btm = txt_btm + txt_ext(4)/3;
   pow_str = num2str(power);
   txt_han(txtct) = text(txt_lft,sup_btm,pow_str,'erase',ers,...
      'horizontalalignment','left','verticalalignment','bottom',...
      'fontsize',8,'fontname',fontname);
   set(txt_han(txtct),'userdata',data);
   txt_ext = get(txt_han(txtct),'extent');
   txt_lft = txt_lft + txt_ext(3);
   txtct=txtct+1;
  end
 end
end


function [ face_pointer, face_data ] = xyzf_data_read ( input_filename, ...
  face_num, face_data_num )

%*****************************************************************************80
%
%% XYZF_DATA_READ reads the data in an XYZF file.
%
%  Discussion:
%
%    This routine assumes that the file contains exactly three kinds of
%    records:
%
%    COMMENTS which begin with a '#' character in column 1;
%    BLANKS which contain nothing but 'whitespace';
%    FACE ITEMS, which are indices of points on a face.
%
%    The routine ignores comments and blanks and returns
%    the number of face items.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 February 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILENAME, the name of the input file.
%
%    Input, integer FACE_NUM, the number of faces.
%
%    Input, integer FACE_DATA_NUM, the number of face items.
%
%    Output, integer FACE_POINTER(FACE_NUM+1), pointers to the
%    first face item for each face.
%
%    Output, integer FACE_DATA(FACE_DATA_NUM), the face items.
%
  input_unit = fopen ( input_filename, 'r' );

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

  face = 0;
  face_pointer(1) = 1;
%
%  Use FGETL, not FGETS, so we don't pick up the NEWLINE character.
%
  while ( face < face_num )

    text = fgetl ( input_unit );

    if ( text(1) == '#' || s_len_trim ( text ) == 0 )
      continue
    end

    face = face + 1;

    n = s_word_count ( text );
    face_pointer(face+1) = face_pointer(face) + n;

    ilo = face_pointer(face);
    ihi = face_pointer(face+1) - 1;

    [ temp, count ] = sscanf ( text, '%d' );

    face_data(ilo:ihi) = temp(1:count);

  end
%
%  Close the file.
%
  fclose ( input_unit );

  return
end


function h = imgsc(I, varargin)
%IMGSC Alias for imagesc for images.
% Usage:
%   imgsc(I)
%   imgsc(I, ...)
%
% See also: imagesc, sc

% figure('KeyPressFcn',@KeyPressFcn_cb)
figclosekey
h = imagesc(I, varargin{:});
H = size(I,1); W = size(I,2);
if  max([H W]) / min([H W]) < 2 || all([H W] < 25)
    axis image
end
colorbar

if nargout < 1; clear h; end

end


function [column_1, column_2, labels, lenght] = load_data(file)
    is_last_line = 0;
    start=1;
    labels = [];
    k = 0;
    file_instance=fopen(file,'rt');
    line = fopen(file_instance);
    while ischar(line)
        line = fgetl(file_instance);
        if ~isempty(strfind(line,'object'))
            k = k+1;
            index = k;
        end
        if ~isempty(strfind(line,'class'))
                split_values = split(line,' ');
                class = split_values(3);
                labels(index) = class;
        end
        if ~isempty(strfind(line,'----------------'))
           is_last_line=0;
        end
        if is_last_line == 1
            if line ~= -1
                start = start+1;
                split_values = strsplit(string(line));
                column_1(index,start) = double(split_values(1, 2));
                column_2(index,start) = double(split_values(1, 3));
            end
        end
        if ~isempty(strfind(line,'dominant hand trajectory:'))
           is_last_line = 1;
           start = 1;
        end
    end
    fclose(file_instance);
    lenght = index;
end


%Revolute Robot manipulator Revolute link class
%
% A subclass of the Link class: holds all information related to a robot
% link such as kinematics parameters, rigid-body inertial parameters, motor
% and transmission parameters.
%
% Notes::
% - This is reference class object
% - Link class objects can be used in vectors and arrays
%
% References::
% - Robotics, Vision & Control, Chap 7
%   P. Corke, Springer 2011.
%
% See also Link, Prismatic, SerialLink.

% Copyright (C) 1993-2015, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

classdef Revolute < Link
    methods
        function L = Revolute(varargin)
            L = L@Link(varargin{:});

            if nargin == 0
                L.theta = [];
            end
            L.sigma = 0;
            if isempty(L.d)
                L.d = 0;
            end
            if ~isempty(L.theta)
                error('theta cannot be specified for a revolute link');
            end
        end

    end
end


function x = is_1d_regression(x)
x = isnumeric(x) && size(x,2) == 1;


function createVelocititesControlButtons(panel_x0,panel_y0,fig_h,panel_Width,panel_height)
%% An interface for velocities magitueds control, this interface is a part of the Virtual smartPad interface
% Copyright: Mohammad SAFEEA, 2018-July-27th

global virtualTeachPendantLinearVelocityMagnitude;
global virtualTeachPendantAngularVelocityMagnitude;
global virtualTeachPendantJointVelocityMagnitude;

virtualTeachPendantLinearVelocityMagnitude=5;
virtualTeachPendantAngularVelocityMagnitude=2;
virtualTeachPendantJointVelocityMagnitude=2;

initialVals={virtualTeachPendantLinearVelocityMagnitude;
    virtualTeachPendantAngularVelocityMagnitude;
    virtualTeachPendantJointVelocityMagnitude};

% Draw a panel, the container of interface
pnl_h=uipanel(fig_h,'Title','Motion velocity','FontSize',12,...
            'Units','pixels');
pnl_h.Position=[panel_x0 panel_y0 panel_Width panel_height];

interMargin=2;
basic_width=(panel_Width-5*interMargin)/10;

upperMargin=60;
interCentersVerticalDistance=(panel_height-upperMargin)/2.7;

text_height=30;
labelsHeight=25;
control_height=interCentersVerticalDistance*.75;

centegradeSymbol=char(176);
st1Temp=['EEF ang... [',centegradeSymbol,'/sec]'];
st2Temp=['Joint vel [',centegradeSymbol,'/sec]'];
labels={'EEF lin... [mm/sec]';st1Temp;st2Temp};

    for i=1:3
        yCenter=panel_height-upperMargin-interCentersVerticalDistance*(i-1);
        % joint label
        lbl=uicontrol(pnl_h,'Style','text',...
            'Units','pixels',...
            'String',labels{i});
        cWidth=5*basic_width;
        cHeight=labelsHeight;
        x0=interMargin;
        y0=yCenter-control_height/2;
        lbl.Position=[x0 y0 cWidth cHeight];
        set(lbl,'HorizontalAlignment','left')
        % minus button
        minusButHandle=uicontrol(pnl_h,'Style', 'pushbutton', 'String', '-',...
                'Units','pixels');
        x0=x0+cWidth+interMargin ;
        cWidth=basic_width;
        cHeight=control_height;
        y0=yCenter-cHeight/2;
        minusButHandle.Position=[x0 y0 cWidth cHeight];
        % text of velocity magnitude
        str=sprintf('%0.1f',initialVals{i});
        textHandle=uicontrol(pnl_h,'Style', 'edit', 'String', str,...
                'Units','pixels');
        x0=x0+cWidth+interMargin ;
        cWidth=2*basic_width;
        cHeight=text_height;
        y0=yCenter-cHeight/2;
        textHandle.Position=[x0 y0 cWidth cHeight];
        % plus button
        plusButHandle=uicontrol(pnl_h,'Style', 'pushbutton', 'String', '+',...
                'Units','pixels');
        x0=x0+cWidth+interMargin ;
        cWidth=basic_width;
        cHeight=control_height;
        y0=yCenter-cHeight/2;
        plusButHandle.Position=[x0 y0 cWidth cHeight];
        % set callbacks of buttons
        if i==1
            fun1=@(object,event)velLinearCallBack(object,event,textHandle,+1);
            fun2=@(object,event)velLinearCallBack(object,event,textHandle,-1);
        elseif i==2
            fun1=@(object,event)velAngularCallBack(object,event,textHandle,+0.2);
            fun2=@(object,event)velAngularCallBack(object,event,textHandle,-0.2);
        elseif i==3
            fun1=@(object,event)jointVelCallBack(object,event,textHandle,+0.2);
            fun2=@(object,event)jointVelCallBack(object,event,textHandle,-0.2);
        end
        set(minusButHandle,'Callback', fun2);
        set(plusButHandle,'Callback', fun1);

    end
end

function velLinearCallBack(object,event,textHandle,increment)
global virtualTeachPendantLinearVelocityMagnitude;
virtualTeachPendantLinearVelocityMagnitude=virtualTeachPendantLinearVelocityMagnitude+increment;
maxLimit=10;
minLimit=1;
if virtualTeachPendantLinearVelocityMagnitude>maxLimit
    virtualTeachPendantLinearVelocityMagnitude=maxLimit;
end
if virtualTeachPendantLinearVelocityMagnitude<minLimit
    virtualTeachPendantLinearVelocityMagnitude=minLimit;
end
% Update the textbox
str=sprintf('%0.1f',virtualTeachPendantLinearVelocityMagnitude);
set(textHandle,'String',str);
end

function velAngularCallBack(object,event,textHandle,increment)
global virtualTeachPendantAngularVelocityMagnitude;
virtualTeachPendantAngularVelocityMagnitude=virtualTeachPendantAngularVelocityMagnitude+increment;
maxLimit=10;
minLimit=1;
if virtualTeachPendantAngularVelocityMagnitude>maxLimit
    virtualTeachPendantAngularVelocityMagnitude=maxLimit;
end
if virtualTeachPendantAngularVelocityMagnitude<minLimit
    virtualTeachPendantAngularVelocityMagnitude=minLimit;
end
% Update the textbox
str=sprintf('%0.1f',virtualTeachPendantAngularVelocityMagnitude);
set(textHandle,'String',str);
end

function jointVelCallBack(object,event,textHandle,increment)
global virtualTeachPendantJointVelocityMagnitude;
virtualTeachPendantJointVelocityMagnitude=virtualTeachPendantJointVelocityMagnitude+increment;
maxLimit=10;
minLimit=1;
if virtualTeachPendantJointVelocityMagnitude>maxLimit
    virtualTeachPendantJointVelocityMagnitude=maxLimit;
end
if virtualTeachPendantJointVelocityMagnitude<minLimit
    virtualTeachPendantJointVelocityMagnitude=minLimit;
end
% Update the textbox
str=sprintf('%0.1f',virtualTeachPendantJointVelocityMagnitude);
set(textHandle,'String',str);
end


function gB = plus(gB,xy)
% shift grains in x/y direction
%
% Syntax
%
%   % shift in x direction
%   gB = gB + [100,0]
%
% Input
%  gB - @grainBoundary
%  xy - x and y coordinates of the shift
%
% Output
%  gB - @grainBoundary

if isa(xy,'grainBoundary'), [xy,gB] = deal(gB,xy); end
if isa(xy,'vector3d'), xy = [xy.x,xy.y]; end

gB.V = gB.V + repmat(xy,size(gB.V,1),1);


function [montage, cfg] = ft_prepare_montage(cfg, data)

% FT_PREPARE_MONTAGE creates a referencing scheme based on the input configuration
% options and the channels in the data structure. The resulting montage can be
% given as input to FT_APPLY_MONTAGE, or as cfg.montage to FT_PREPROCESSING.
%
% Use as
%   montage = ft_prepare_montage(cfg, data)
%
% The configuration can contain the following fields:
%   cfg.refmethod     = 'avg', 'comp', 'bipolar', 'laplace', 'doublebanana', 'longitudinal', 'circumferential', 'transverse' (default = 'avg')
%   cfg.implicitref   = string with the label of the implicit reference, or empty (default = [])
%   cfg.refchannel    = cell-array with new EEG reference channel(s), this can be 'all' for a common average reference
%   cfg.groupchans    = 'yes' or 'no', should channels be rereferenced in separate groups
%                       for bipolar and laplace methods, this requires channnels to be
%                       named using an alphanumeric code, where letters represent the
%                       group and numbers represent the order of the channel whithin
%                       its group (default = 'no')
%
% The implicitref option allows adding the implicit reference channel to the data as
% a channel with zeros.
%
% The resulting montage is a structure with the fields
%   montage.tra      = MxN matrix
%   montage.labelold = Nx1 cell-array
%   montage.labelnew = Mx1 cell-array
%
% As an example, an output bipolar montage could look like this
%   bipolar.labelold  = {'1',   '2',   '3',   '4'}
%   bipolar.labelnew  = {'1-2', '2-3', '3-4'}
%   bipolar.tra       = [
%     +1 -1  0  0
%      0 +1 -1  0
%      0  0 +1 -1
%   ];
%
% See also FT_PREPROCESSING, FT_APPLY_MONTAGE

% Copyright (C) 2017-2022, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

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

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

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

% the data can be passed as input argument or can be read from disk
hasdata = exist('data', 'var') && ~isempty(data);

% basic check/initialization of input arguments
if ~hasdata
  data = struct([]);
else
  data = ft_checkdata(data, 'datatype', {'raw', 'raw+comp', 'timelock', 'timelock+comp'});
end

% do a sanity check for incompatible options which are used in ft_preprocessing and elsewhere
cfg = ft_checkconfig(cfg, 'forbidden', {'montage', 'method'});

% set default configuration options
cfg.refmethod    = ft_getopt(cfg, 'refmethod', 'avg');
cfg.channel      = ft_getopt(cfg, 'channel', 'all');
cfg.implicitref  = ft_getopt(cfg, 'implicitref');
cfg.refchannel   = ft_getopt(cfg, 'refchannel');
cfg.groupchans   = ft_getopt(cfg, 'groupchans', 'no');

if isfield(cfg, 'reref')
  assert(istrue(cfg.reref), 'cannot create a montage without cfg.reref=''yes''');
end

% here the actual work starts
if hasdata
  cfg.channel    = ft_channelselection(cfg.channel, data.label);
  cfg.refchannel = ft_channelselection(cfg.refchannel, cat(1, data.label(:), cfg.implicitref));
else
  if ischar(cfg.channel)
    cfg.channel = {cfg.channel};
  end
  if ischar(cfg.refchannel)
    cfg.refchannel = {cfg.refchannel};
  end
end

% the first montage serves to add the implicit reference channel
% the last row for the implicitref will be all zero
montage1 = [];
montage1.labelold = cfg.channel(:);
montage1.labelnew = cfg.channel(:);
if ~isempty(cfg.implicitref)
  montage1.labelnew{end+1} = cfg.implicitref;
end
montage1.tra = eye(numel(montage1.labelnew), numel(montage1.labelold));

% the second montage serves to subtract the selected reference channels
switch cfg.refmethod
  case 'avg'
    % make a montage that subtracts the mean of all channels specified in cfg.refchannel
    montage2 = [];
    montage2.labelold = montage1.labelnew;
    montage2.labelnew = montage1.labelnew;
    montage2.tra      = eye(numel(montage2.labelnew));
    refsel = match_str(montage2.labelold, cfg.refchannel);
    montage2.tra(:,refsel) = montage2.tra(:,refsel) - 1/numel(refsel);

    % apply montage2 to montage1, the result is the combination of both
    montage = ft_apply_montage(montage1, montage2);

  case 'comp'
    assert(isempty(cfg.implicitref), 'implicitref not supported with refmethod=''%s''', cfg.refmethod);
    % construct an linear projection from channels to components
    montage = [];
    montage.labelold = data.topolabel;
    montage.labelnew = data.label;
    montage.tra      = data.unmixing;

  case 'invcomp'
    assert(isempty(cfg.implicitref), 'implicitref not supported with refmethod=''%s''', cfg.refmethod);
    % construct an linear projection from components to channels
    montage = [];
    montage.labelold = data.label;
    montage.labelnew = data.topolabel;
    montage.tra      = data.topo;

  case 'bipolar'
    if istrue(cfg.groupchans)
      % this uses recursion to make the montage for each group
      label = montage1.labelnew;
      group = cell(size(label));
      for i=1:numel(label)
        group(i) = regexp(label{i}, '^[a-zA-Z]+', 'match');
      end
      ugroup = unique(group, 'stable');

      tmpcfg = keepfields(cfg, {'refmethod', 'implicitref', 'refchannel', 'channel'});
      tmpcfg.groupchans = 'no';
      tmpcfg.showcallinfo = 'no';

      groupmontage = cell(size(ugroup));
      for g = 1:length(ugroup) % for each group of channels
        % select the channels within the group
        tmpcfg.channel = label(strcmp(group, ugroup{g}));
        groupmontage{g} = ft_prepare_montage(tmpcfg);
      end

      % start with a montage that keeps all channels the same
      montage2 = [];
      montage2.labelold = label(:)';
      montage2.labelnew = label(:);
      montage2.tra = eye(length(label));

      for g = length(ugroup):-1:1
        % apply the montage for each groep (i.e., combine them), keep all other channels as they are
        % unused channels end up at the end, hence doing it in reverse order keeps the channel order consistent
        montage2 = ft_apply_montage(montage2, groupmontage{g}, 'keepunused', true);
      end

    else
      % create a montage for the bipolar derivation of sequential channels
      montage2          = [];
      montage2.labelold = montage1.labelnew;
      montage2.labelnew = strcat(montage1.labelnew(1:end-1),'-',montage1.labelnew(2:end));
      tra_neg           = diag(-ones(numel(montage1.labelnew)-1,1), 1);
      tra_plus          = diag( ones(numel(montage1.labelnew)-1,1),-1);
      montage2.tra      = tra_neg(1:end-1,:)+tra_plus(2:end,:);

    end % if groupchans

    % apply montage2 to montage1, the result is the combination of both
    montage = ft_apply_montage(montage1, montage2);

  case 'laplace'
    if istrue(cfg.groupchans)
      % this uses recursion to make the montage for each group
      label = montage1.labelnew;
      group = cell(size(label));
      for i=1:numel(label)
        group(i) = regexp(label{i}, '^[a-zA-Z]+', 'match');
      end
      group = unique(group, 'stable');

      tmpcfg = keepfields(cfg, {'refmethod', 'implicitref', 'refchannel', 'channel'});
      tmpcfg.groupchans = 'no';
      tmpcfg.showcallinfo = 'no';

      groupmontage = cell(size(group));
      for g = 1:length(group) % for each group of channels
        % select the channels within the group
        tmpcfg.channel = label(startsWith(label, group{g}));
        groupmontage{g} = ft_prepare_montage(tmpcfg);
      end

      % start with a montage that keeps all channels the same
      montage2 = [];
      montage2.labelold = label(:)';
      montage2.labelnew = label(:);
      montage2.tra = eye(length(label));

      for g = length(group):-1:1
        % apply the montage for each groep (i.e., combine them), keep all other channels as they are
        % unused channels end up at the end, hence doing it in reverse order keeps the channel order consistent
        montage2 = ft_apply_montage(montage2, groupmontage{g}, 'keepunused', true);
      end

    else
      % create a montage for the laplacian derivation of neighboring channels where
      % each channel is re-referenced against the mean of the two nearest channels,
      % while channels at the extremities will be re-referenced against their closest
      % neighbor; this is particularly useful for sEEG shafts

      montage2          = [];
      montage2.labelold = montage1.labelnew;
      tra_neg1          = diag(-0.5*ones(numel(montage1.labelnew)-1,1), 1);
      tra_neg2          = diag(-0.5*ones(numel(montage1.labelnew)-1,1), -1);

      if numel(montage2.labelold) > 2
        montage2.labelnew = montage1.labelnew;
        tra_plus          = diag(ones(numel(montage1.labelnew),1),0);
        montage2.tra      = tra_neg1+tra_neg2+tra_plus;
        montage2.tra(1,2) = -1;
        montage2.tra(end,end-1) = -1;
      else
        % The following commands are just meant to avoid errors, in case
        % only one channel is given as input: the algorithm will behave
        % exactly as it would in the 'bipolar' case
        montage2.labelnew = cell(numel(montage1.labelnew),0);
        tra_plus          = diag(ones(numel(montage1.labelnew)-1,1),-1);
        montage2.tra      = tra_neg1+tra_neg2+tra_plus(2:end,:);
      end

    end % if groupchans

    % apply montage2 to montage1, the result is the combination of both
    montage = ft_apply_montage(montage1, montage2);

  case {'longitudinal', 'doublebanana'}
    % see https://www.learningeeg.com/montages-and-technical-components
    montage = [];
    montage.labelold = {'Fp1', 'Fpz', 'Fp2', 'F7', 'F3', 'Fz', 'F4', 'F8', 'T3', 'C3', 'Cz', 'C4', 'T4', 'T5', 'P3', 'Pz', 'P4', 'T6', 'O1', 'Oz', 'O2'};
    montage.labelnew = {
      % left temporal chain
      'Fp1-F7'
      'F7-T3'
      'T3-T5'
      'T5-O1'
      % left parasagittal chain
      'Fp1-F3'
      'F3-C3'
      'C3-P3'
      'P3-O1'
      % central chain
      'Fz-Cz'
      'Cz-Pz'
      % right parasagittal chain
      'Fp2-F4'
      'F4-C4'
      'C4-P4'
      'P4-O2'
      % right temporal chain
      'Fp2-F8'
      'F8-T4'
      'T4-T6'
      'T6-O2'
      };
    % construct the montage from new channel labels
    montage.tra = zeros(length(montage.labelnew), length(montage.labelold));
    for i=1:length(montage.labelnew)
      lab = split(montage.labelnew{i}, '-');
      montage.tra(i, strcmp(montage.labelold, lab{1})) = +1;
      montage.tra(i, strcmp(montage.labelold, lab{2})) = -1;
    end
    % do a sanity check on the montage
    assert(all(sum(montage.tra, 2)==0));
    assert(all(max(montage.tra, [], 2)==+1));
    assert(all(min(montage.tra, [], 2)==-1));

  case 'circumferential'
    % see https://www.learningeeg.com/montages-and-technical-components
    montage = [];
    montage.labelold = {'Fp1', 'Fpz', 'Fp2', 'F7', 'F3', 'Fz', 'F4', 'F8', 'T3', 'C3', 'Cz', 'C4', 'T4', 'T5', 'P3', 'Pz', 'P4', 'T6', 'O1', 'Oz', 'O2'};
    montage.labelnew = {
      'Fp1-F7'
      'F7-T3'
      'T3-T5'
      'T5-O1'
      'O1-O2'
      'O2-T6'
      'T6-T4'
      'T4-F8'
      'F8-Fp2'
      'Fp2-Fp1'
      };
    % construct the montage from new channel labels
    montage.tra = zeros(length(montage.labelnew), length(montage.labelold));
    for i=1:length(montage.labelnew)
      lab = split(montage.labelnew{i}, '-');
      montage.tra(i, strcmp(montage.labelold, lab{1})) = +1;
      montage.tra(i, strcmp(montage.labelold, lab{2})) = -1;
    end
    % do a sanity check on the montage
    assert(all(sum(montage.tra, 2)==0));
    assert(all(max(montage.tra, [], 2)==+1));
    assert(all(min(montage.tra, [], 2)==-1));

  case 'transverse'
    % this is inspired by https://doi.org/10.1016/j.earlhumdev.2011.08.008 but probably better documented elsewhere
    % see https://www.learningeeg.com/montages-and-technical-components
    % this particular implementation only considers the 10% distances
    montage = [];
    montage.labelold = {'Fp1', 'Fpz', 'Fp2', 'F7', 'F3', 'Fz', 'F4', 'F8', 'T3', 'C3', 'Cz', 'C4', 'T4', 'T5', 'P3', 'Pz', 'P4', 'T6', 'O1', 'Oz', 'O2'};
    montage.labelnew = {
      'Fp1-Fp2'
      'F7-F3'
      'F3-Fz'
      'Fz-F4'
      'F4-F8'
      'T3-C3'
      'C3-Cz'
      'Cz-C4'
      'C4-T4'
      'T5-P3'
      'P3-Pz'
      'Pz-P4'
      'P4-T6'
      'O1-O2'
      };
    % construct the montage from new channel labels
    montage.tra = zeros(length(montage.labelnew), length(montage.labelold));
    for i=1:length(montage.labelnew)
      lab = split(montage.labelnew{i}, '-');
      montage.tra(i, strcmp(montage.labelold, lab{1})) = +1;
      montage.tra(i, strcmp(montage.labelold, lab{2})) = -1;
    end
    % do a sanity check on the montage
    assert(all(sum(montage.tra, 2)==0));
    assert(all(max(montage.tra, [], 2)==+1));
    assert(all(min(montage.tra, [], 2)==-1));

  otherwise
    error('unsupported refmethod=''%s''', cfg.refmethod);
end

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


function title = p12_title ( title )

%*****************************************************************************80
%
%% P12_TITLE returns the title of problem 12.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 May 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string TITLE, the title of the problem.
%
  title = 'Flat Stanley (ALL derivatives are zero at the root.)';

  return
end


function hole_point = p07_hole_point ( hole_index, m )

%*****************************************************************************80
%
%% P07_HOLE_POINT returns a point inside a given hole in problem 7.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 April 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer HOLE_INDEX, the index of the hole.
%
%    Input, integer M, the spatial dimension.
%
%    Output, real HOLE_POINT(M), a point in the hole
%
  hole_point(1:2) = [ ];

  return
end


function mrAnatConvertVAnatToT1Nifti(vAnat,outFileName)
%
%  mrAnatConvertVAnatToT1Nifti([vAnat],[outFileName])
%
% This function takes a vAnatomy.dat file converts it to a NIFTI and saves
% that NIFTI struct as vAnatomy.nii.gz by default.
%
% vAnat is a file name to a vAnatomy.dat
% outFilenmae defaults to 'vAnatomy.nii.gz'.
%
% Example:
%  vAnatPath = mrtInstallSampleData('anatomy/anatomyV','vAnatomy', ...
%   [], [], 'filetype', 'dat');
%  outFileName = [];
%  vAnatFileName = sprintf('%s.dat', vAnatPath);
%  mrAnatConvertVAnatToT1Nifti(vAnatFileName,outFileName);
%
% HISTORY:
% 4/20/2009 LMP wrote the thing
%
% LMP (c) Stanford VISTALAB

if(~exist('vAnat','var') || isempty(vAnat))
    [f,p] = uigetfile({'*.dat';'*.*'},'Select a vAnatomy.dat file for input...');
    if(isnumeric(f)), disp('User canceled.'); return; end
    vAnat = fullfile(p,f);
end

if(~exist('outFileName','var') || isempty(outFileName))
    p = fileparts(vAnat);
    outFileName = fullfile(p,'vAnatomy.nii.gz');
end

[vData,mmPerVox] = readVAnat(vAnat);

% Convert mrgray sagittal format to our preferred axial format for NIFTI
vData = flip(flip(permute(vData,[3 2 1]),2),3);
mmPerVox = mmPerVox([3 2 1]);
xform = [diag(1./mmPerVox), size(vData)'/2; 0 0 0 1];

% Modern version - BW, October 2012
ni = niftiCreate('fname',outFileName,'qto_xyz',inv(xform), 'data', vData);

% ni.qto_xyz = inv(xform);
% ni.qto_ijk = xform;
% ni.sto_xyz = inv(xform);
% ni.sto_ijk = xform;

niftiWrite(ni);

return

end

function [vData,mmPerVox] = readVAnat(vFile)

% set this to nan's in case the vAnatomy is old-style, in which
% case it won't have mmPerPix in the header.
mmPerVox = [nan,nan,nan];
volSize = [nan,nan,nan];

fid = fopen(vFile);
% read header: volSize and mmPerPix (if available)
tmp = fscanf(fid,'rows %f (%f mm/pixel)\n');
volSize(1) = tmp(1);
if length(tmp)>1, mmPerVox(1) = tmp(2); end
tmp = fscanf(fid,'cols %f (%f mm/pixel)\n');
volSize(2) = tmp(1);
if length(tmp)>1, mmPerVox(2) = tmp(2); end
tmp = fscanf(fid,'planes %f (%f mm/pixel)\n');
volSize(3) = tmp(1);
if length(tmp)>1, mmPerVox(3) = tmp(2); end

% Check that this is a valid header for a vAnatomy file. The next line should be '* \n'
endOfHeader = '*';
nextLine = fgets(fid);
if ~(length(nextLine)>=2 && nextLine(1)==endOfHeader)
    myErrorDlg(['vAnatomy file: ',vFile,' has invalid header']);
end

% If mmPerPix was not in the vAnatomy header, try to get it from UnfoldParams
if(isnan(mmPerVox(1)) || isnan(mmPerVox(2)) || isnan(mmPerVox(3)))
    % Try to get the voxel size from the old UnfoldParams.mat file.
    % warning('volume_pix_size not available. Try to get it from the old UnfoldParams file.');
    eval('ufp = load(fullfile(fpath,''UnfoldParams.mat''));', 'ufp = [];');
    if(isfield(ufp, 'volume_pix_size'))
        mmPerVox = 1./ufp.volume_pix_size;
    else
        % Error: can't find mmPerPix
        %myErrorDlg('Can not determine volume voxel size. You need to create an UnfoldParams file.');
        % Display a warning and carry on:
        disp('Warning : Can not determine volume voxel size. Setting to 1x1x1mm.');
        mmPerVox=[1 1 1];
    end
end

% read volume
vData = fread(fid,prod(volSize),'uint8');
fclose(fid);

% *** HACK!  Sometimes the vAnatomy is missing the last byte (???)
if length(vData) == prod(volSize)-1
    vData(end+1) = 0;
end

% Return vData permuted to maintain correct orientations. The old way was
% very inefficient.
vData=reshape(vData,[volSize(2),volSize(1),volSize(3)]);
vData=double(permute(vData,[2,1,3])); % This double cast is required for routines that expect readVolAnat to return a double.

end


function [TrainX, TestX, TrainY, TestY, numSource, numTrain, numTarget, numTest] = HIDC_loadData(inputPath)
    load(inputPath);
    traindata{1,1} = TrainData;
    trainlabel{1,1} = TrainLabel;
    testdata{1,1} = TestData;
    testlabel{1,1} = TestLabel;
    numSource = size(traindata,2);                              % number of train file
    numTrain = zeros(1,numSource);
    TrainX = [];
    TrainY = [];
    for i = 1 : length(numTrain)
        numTrain(1,i) = size(traindata{1,i},2);
        TrainX = [TrainX traindata{1,i}];
        TrainY = [TrainY trainlabel{1,i}];
    end

    numTarget = size(testdata,2);                              % number of train file
    numTest = zeros(1,numTarget);
    TestX = [];
    TestY = [];
    for i = 1 : length(numTest)
        numTest(1,i) = size(testdata{1,i},2);
        TestX = [TestX testdata{1,i}];
        TestY = [TestY testlabel{1,i}];
    end
    TrainY = TrainY+1;
    TestY = TestY+1;
end