function [x_trans,IDX,ntrans] = ...
  ComputePerFrameTrans(x,trans_types)

if ~exist('trans_types','var'),
  %trans_types = 'all';
  trans_types = uint8(15);
end

%usealltrans = ischar(trans_types) && strcmpi(trans_types,'all');

x_trans = x;
IDX.orig = 1;
IDX.abs = 0;
IDX.flip = 0;
%if usealltrans || ismember('abs',trans_types),
if bitand(2,trans_types),
  x_trans(end+1,:) = abs(x);
  IDX.abs = size(x_trans,1);
end
%if usealltrans || ismember('flip',trans_types),
if bitand(4,trans_types),
  x_trans(end+1,:) = -x;
  IDX.flip = size(x_trans,1);
end
ntrans = size(x_trans,1);


function prev_rng = seed_rand(seed)
% seed_rand - Set random number generator to a fixed seed.
%   prev_rng = seed_rand(seed)
%
%   Strategic use ensures that results are reproducible.
%
%   To restore the previous rng after calling this do:
%   rng(prev_rng);

% AUTORIGHTS
% ---------------------------------------------------------
% Copyright (c) 2014, Ross Girshick
%
% This file is part of the R-CNN code and is available
% under the terms of the Simplified BSD License provided in
% LICENSE. Please retain this notice and LICENSE if you use
% this file (or any portion of it) in your project.
% ---------------------------------------------------------

if nargin < 1
    % This value works best for me.
    seed = 3;
    % Just kidding, of course ;-).
end

prev_rng = rng;
rng(seed, 'twister')


function response = Cautious(n,p)

if n==1 || n==20
    response = 'defect';
elseif p==0 || p==3
    response = 'cooperate';
else
    response = 'defect';
end


function varargout = plot3(f, g, h, varargin)
%PLOT3   Plot for CLASSICFUN objects in 3-D space.
%   PLOT() is a three-dimensional analogue of PLOT().
%
%   PLOT3(X, Y, Z), where Z, Y, and Z are three CLASSICFUN objects, plots a line in
%   3-space. X, Y, and Z may be array-valued, but must have the same number of
%   columns.
%
%   Various line types, plot symbols, and colors may be obtained with PLOT3(X,
%   Y, Z, S) where s is a 1, 2 or 3 character string made from the characters
%   listed under the PLOT command.
%
%   H1 = PLOT3(X, Y, Z) returns a column vector of handles to lineseries
%   objects, one handle per plotted line (in the case of vector-valued CLASSICFUN
%   objects). [H1, H2] returns a second vector of column handles, this time for
%   each of the marker plots.
%
% See also PLOT, PLOTDATA.

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

% Deal with an empty input:
if ( isempty(f) )
    if ( nargout == 1 )
        varargout{1} = plot([]);
    end
    return
end

% Store the hold state of the current axis:
holdState = ishold;

%%
% We can only pl0t real data in this way:
f = real(f);
g = real(g);
h = real(h);

% Get the data for plotting from PLOTDATA():
data = plotData(f, g, h);

%%
% Plot the curve:
h1 = plot3(data.xLine, data.yLine, data.zLine, varargin{:});

% No points on the line plot:
set(h1, 'Marker', 'none')

% Hold the plot:
hold on

%%
% Plot the points:
h2 = plot3(data.xPoints, data.yPoints, data.zPoints, varargin{:});

% Change the style accordingly:
set(h2, 'LineStyle', 'none')
if ( all(strcmp(get(h2, 'Marker'), 'none')) && length(f) < 257 )
    set(h2,'Marker', 'o')
end

%%
% Return hold state to what it was before:
if ( ~holdState )
    hold off
end

% Give an output if one was requested:
if ( nargout > 0 )
    varargout{1} = h1;
    varargout{2} = h2;
end

end


function grad = fif2grad(filename);

% FIF2GRAD constructs a gradiometer definition from a Neuromag *.fif file
% The resulting gradiometer definition can be used by Fieldtrip for forward
% and inverse computations.
%
% Use as
%   grad = fif2grad(filename);
%
% See also READ_HEADER, CTF2GRAD, BTI2GRAD

% Copyright (C) 2004, Joachim Gross
%
% This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
% 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: fif2grad.m 2885 2011-02-16 09:41:58Z roboos $

% this try-catch construct ensures that missing gradiometer information is
% handeled in a "graceful" way
grad = [];
try
   megmodel('head',[0 0 0],filename);
   [n,s,t]=chaninfo;
   [TY,NA]=chaninfo('type');
   nCoils=sum(TY+1);      % number of coils
   nSensors=length(TY);   % number of sensors
   grad.pnt=zeros(nCoils,3);
   grad.ori=zeros(nCoils,3);
   grad.tra=zeros(nSensors,nCoils);
   grad.unit='cm';
   % define coils
   kCoil=1;
   for k=1:nSensors,
      if (TY(k)==0),  %magnetometer
         grad.pnt(kCoil,:)=100*(t{k}(1:3,4));
         grad.ori(kCoil,:)=t{k}(1:3,3);
         grad.tra(k,kCoil)=1;
         kCoil=kCoil+1;
         grad.label{k}=deblank(s(k,:));
      elseif (TY(k) == 1), %planar gradiometer
         grad.pnt(kCoil,:)=100*(t{k}(1:3,4)-0.008*t{k}(1:3,1)); % multiply with 100 to get cm
         grad.ori(kCoil,:)=t{k}(1:3,3);
         grad.tra(k,kCoil)= -1;
         kCoil=kCoil+1;
         grad.pnt(kCoil,:)=100*(t{k}(1:3,4)+0.008*t{k}(1:3,1));
         grad.ori(kCoil,:)=t{k}(1:3,3);
         grad.tra(k,kCoil)= 1;
         kCoil=kCoil+1;
         grad.label{k}=deblank(s(k,:));
      else
         error('unknown sensor type');
      end
   end
catch
   warning(['gradiometer information could not be extracted from file']);
   warning(['returning an empty grad structure']);
   return;
end


function [Lmk, Frm, Fac] = makeMeasFactor(Lmk, Obs, Frm, Fac)

% MAKEMEASFACTOR Make measurement factor.
%   [Lmk, Frm, Fac] = MAKEMEASFACTOR(Lmk, Obs, Frm, Fac) creates a new
%   measurement factor Fac linking frame Frm to landmark Lmk, using the
%   observation informaiton in Obs.

%   Copyright 2015-     Joan Sola @ IRI-UPC-CSIC

Fac.used = true; % Factor is being used ?
Fac.id = newId; % Factor unique ID

Fac.type = 'measurement'; % {'motion','measurement','absolute'}
Fac.rob = Frm.rob;
Fac.sen = Obs.sen;
Fac.lmk = Obs.lmk;
Fac.frames = Frm.frm;

% Ranges
Fac.state.r1 = Frm.state.r;
Fac.state.r2 = Lmk.state.r;

% Measurement is the straight data
Fac.meas.y = Obs.meas.y;
Fac.meas.R = Obs.meas.R;
Fac.meas.W = Obs.meas.R^-1; % measurement information matrix

% Expectation has zero covariance -- and info in not defined
Fac.exp.e = Fac.meas.y; % expectation
Fac.exp.E = zeros(size(Obs.meas.R)); % expectation cov
%     Fac.exp.W = Fac.meas.W; % expectation information matrix

% Error is zero at this stage, and takes covariance and info from measurement
Fac.err.z     = zeros(size(Fac.meas.y)); % error or innovation (we call it error because we are on graph SLAM)
Fac.err.Z     = Fac.meas.R;              % error cov matrix
Fac.err.W     = Fac.meas.W;              % error information matrix
Fac.err.Wsqrt = chol(Fac.err.W);

% Jacobians are zero at this stage. Just make size correct.
Fac.err.J1 = Obs.Jac.E_r; % Jac. of error wrt. node 1 - robot pose
Fac.err.J2 = Obs.Jac.E_l; % Jac. of error wrt. node 2 - lmk state

Fac.err.size  = numel(Fac.err.z);

% Append factor to Frame's and Lmk's factors lists.
Frm.factors = [Frm.factors Fac.fac];
Lmk.factors = [Lmk.factors Fac.fac];

% ========== 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


%COPY_GEOMETRY_OBJECT Copy geometry object(s) with transformation.
%
%   [ GEOM, NEW_TAGS ] = COPY_GEOMETRY_OBJECT( TAGS, GEOM, TRSFARGS,
%   CONNECT ) Copies the geometry object(s) in GEOM with corresponding
%   TAGS. Optional TRSFARGS are passed to transform the objects, and
%   CONNECTing boundaries for 3D CAD geometries (default false).
%
%   See also GEOM_APPLY_TRANSFORMATION

% Copyright 2013-2022 Precise Simulation, Ltd.


function mm_header_print ( input_filename, id, type, rep, field, symm )

%*****************************************************************************80
%
%% MM_HEADER_PRINT prints header information from a Matrix Market file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 May 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, character ( len = * ) INPUT_FILENAME, the input file name.
%
%    Input, character ( len = 14 ) ID, the Matrix Market identifier.
%    This value must be '%%MatrixMarket'.
%
%    Input, character ( len = 6 ) TYPE, the Matrix Market type.
%    This value must be 'matrix'.
%
%    Input, character ( len = 10 ) REP, the Matrix Market 'representation'
%    indicator.  Possible values include:
%    'coordinate'   (for sparse data)
%    'array'        (for dense data)
%    'elemental'    (to be added)
%
%    Input, character ( len = 7 ) FIELD, the Matrix Market 'field'.
%    Possible values include:
%    'real'
%    'double'
%    'complex'
%    'integer'
%    'pattern'
%
%    Input, character ( len = 19 ) SYMM, the Matrix Market symmetry.
%    Possible values include:
%    'symmetric'
%    'hermitian'
%    'skew-symmetric'
%    'general'
%
  fprintf ( 1, '\n');
  fprintf ( 1, 'MM_HEADER_PRINT:\n' );
  fprintf ( 1, '  Header information from Matrix Market file "%s".\n', ...
    input_filename );
  fprintf ( 1, '\n');
  fprintf ( 1, '  Matrix Market ID = "%s".\n', id );
  fprintf ( 1, '    "%%%%MatrixMarket" is only allowed value.\n' );
  fprintf ( 1, '\n');
  fprintf ( 1, '  Matrix Market TYPE = "%s".\n', type );
  fprintf ( 1, '    "matrix" is only allowed value.\n' );
  fprintf ( 1, '\n');
  fprintf ( 1, '  Representation type REP = "%s".\n', rep );
  fprintf ( 1, '    "coordinate" for sparse matrices,\n' );
  fprintf ( 1, '    "array"      for dense matrices,\n' );
  fprintf ( 1, '    "elemental"  for unassembled finite element matrices.\n' );
  fprintf ( 1, '\n');
  fprintf ( 1, '  Numeric FIELD = "%s".\n', field );
  fprintf ( 1, '    "integer" for integer values,\n' );
  fprintf ( 1, '    "real"    for real values,\n' );
  fprintf ( 1, '    "double"  for double precision real values,\n' );
  fprintf ( 1, '    "complex" for complex values,\n' );
  fprintf ( 1, '    "pattern" for nonzero pattern only.\n' );
  fprintf ( 1, '\n');
  fprintf ( 1, '  Symmetry type SYMM = "%s".\n', symm );
  fprintf ( 1, '    "general"         no symmetry,\n' );
  fprintf ( 1, '    "symmetric"       A(I,J) = A(J,I),\n' );
  fprintf ( 1, '                      input only lower triangle.\n' );
  fprintf ( 1, '    "skew-symmetric"  A(I,J) = - A(J,I),\n' );
  fprintf ( 1, '                      input only strict lower triangle.\n' );
  fprintf ( 1, '    "Hermitian"       A(I,J) = A*(J,I),\n' );
  fprintf ( 1, '                      input only lower triangle.\n' );

  return
end


function [ i_min, i_max, j_min, j_max, m, n, nst ] = st_header_read ( ...
  input_filename )

%*****************************************************************************80
%
%% ST_HEADER_READ reads the header of an ST file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 July 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILENAME, the name of the ST file.
%
%    Output, integer I_MIN, I_MAX, the minimum and maximum rows.
%
%    Output, integer J_MIN, J_MAX, the minimum and maximum columns.
%
%    Output, integer M, the number of rows.
%
%    Output, integer N, the number of columns.
%
%    Output, integer NST, the number of nonzeros.
%
  input_unit = fopen ( input_filename );

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

  nst = 0;
  i_min = + Inf;
  i_max = - Inf;
  j_min = + Inf;
  j_max = - Inf;

  string = '  %d  %d  %f';

  while ( 1 )

    line = fgets ( input_unit );

    if ( line == -1 )
      break
    end

    [ x, count ] = sscanf ( line, string );

    i = x(1);
    j = x(2);
    aij = x(3);

    nst = nst + 1;
    i_min = min ( i_min, i );
    i_max = max ( i_max, i );
    j_min = min ( j_min, j );
    j_max = max ( j_max, j );

  end

  fclose ( input_unit );

  m = i_max - i_min + 1;
  n = j_max - j_min + 1;

  return
end


function p = propagate_upforce(p)

% Find inconsistency of y <= x1 + x2 + ...
if p.feasible
    for i = 1:length(p.upForce)
        forcing = p.upForce{i}.forcing;
        if p.lb(forcing)==1
            forced = p.upForce{i}.forced;
            if all(p.ub(forced)==0)
                p.feasible = 0;
                return
            end
        end
    end
end


function [net,stats] = cnn_train_dag(net, imdb, getBatch, varargin)
%CNN_TRAIN_DAG Demonstrates training a CNN using the DagNN wrapper
%    CNN_TRAIN_DAG() is similar to CNN_TRAIN(), but works with
%    the DagNN wrapper instead of the SimpleNN wrapper.

% Copyright (C) 2014-15 Andrea Vedaldi.
% 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).

% Todo: save momentum with checkpointing (a waste?)

opts.expDir = fullfile('data','exp') ;
opts.continue = true ;
opts.batchSize = 256 ;
opts.numSubBatches = 1 ;
opts.train = [] ;
opts.val = [] ;
opts.gpus = [] ;
opts.prefetch = false ;
opts.numEpochs = 300 ;
opts.learningRate = 0.001 ;
opts.weightDecay = 0.0005 ;
opts.momentum = 0.9 ;
opts.memoryMapFile = fullfile(tempdir, 'matconvnet.bin') ;
opts.profile = false ;

opts.derOutputs = {'objective', 1} ;
opts.extractStatsFn = @extractStats ;
opts = vl_argparse(opts, varargin) ;

if ~exist(opts.expDir, 'dir'), mkdir(opts.expDir) ; end
if isempty(opts.train), opts.train = find(imdb.images.set==1) ; end
if isempty(opts.val), opts.val = find(imdb.images.set==2) ; end
if isnan(opts.train), opts.train = [] ; end

% -------------------------------------------------------------------------
%                                                            Initialization
% -------------------------------------------------------------------------

state.getBatch = getBatch ;
evaluateMode = isempty(opts.train) ;
if ~evaluateMode
  if isempty(opts.derOutputs)
    error('DEROUTPUTS must be specified when training.\n') ;
  end
end
stats = [] ;

% setup GPUs
numGpus = numel(opts.gpus) ;
if numGpus > 1
  if isempty(gcp('nocreate')),
    parpool('local',numGpus) ;
    spmd, gpuDevice(opts.gpus(labindex)), end
  end
  if exist(opts.memoryMapFile)
    delete(opts.memoryMapFile) ;
  end
elseif numGpus == 1
  gpuDevice(opts.gpus)
end

% -------------------------------------------------------------------------
%                                                        Train and validate
% -------------------------------------------------------------------------

modelPath = @(ep) fullfile(opts.expDir, sprintf('net-epoch-%d.mat', ep));
modelFigPath = fullfile(opts.expDir, 'net-train.pdf') ;

start = opts.continue * findLastCheckpoint(opts.expDir) ;
if start >= 1
  fprintf('resuming by loading epoch %d\n', start) ;
  [net, stats] = loadState(modelPath(start)) ;
end

for epoch=start+1:opts.numEpochs

  % train one epoch
  state.epoch = epoch ;
  state.learningRate = opts.learningRate(min(epoch, numel(opts.learningRate))) ;
  state.train = opts.train(randperm(numel(opts.train))) ; % shuffle
  state.val = opts.val ;
  state.imdb = imdb ;

  if numGpus <= 1
    stats.train(epoch) = process_epoch(net, state, opts, 'train') ;
    stats.val(epoch) = process_epoch(net, state, opts, 'val') ;
  else
    savedNet = net.saveobj() ;
    spmd
      net_ = dagnn.DagNN.loadobj(savedNet) ;
      stats_.train = process_epoch(net_, state, opts, 'train') ;
      stats_.val = process_epoch(net_, state, opts, 'val') ;
      if labindex == 1, savedNet_ = net_.saveobj() ; end
    end
    net = dagnn.DagNN.loadobj(savedNet_{1}) ;
    stats__ = accumulateStats(stats_) ;
    stats.train(epoch) = stats__.train ;
    stats.val(epoch) = stats__.val ;
    clear net_ stats_ stats__ savedNet_ ;
  end

  if ~evaluateMode
    saveState(modelPath(epoch), net, stats) ;
  end

  figure(1) ; clf ;
  plots = setdiff(...
    cat(2,...
        fieldnames(stats.train)', ...
        fieldnames(stats.val)'), {'num', 'time'}) ;
  for p = plots
    p = char(p) ;
    values = zeros(0, epoch) ;
    leg = {} ;
    for f = {'train', 'val'}
      f = char(f) ;
      if isfield(stats.(f), p)
        tmp = [stats.(f).(p)] ;
        values(end+1,:) = tmp(1,:)' ;
        leg{end+1} = f ;
      end
    end
    subplot(1,numel(plots),find(strcmp(p,plots))) ;
    plot(1:epoch, values','o-') ;
    xlabel('epoch') ;
    title(p) ;
    legend(leg{:}) ;
    grid on ;
  end
  drawnow ;
  print(1, modelFigPath, '-dpdf') ;
end

% -------------------------------------------------------------------------
function stats = process_epoch(net, state, opts, mode)
% -------------------------------------------------------------------------

if strcmp(mode,'train')
  state.momentum = num2cell(zeros(1, numel(net.params))) ;
end

numGpus = numel(opts.gpus) ;
if numGpus >= 1
  net.move('gpu') ;
  if strcmp(mode,'train')
    sate.momentum = cellfun(@gpuArray,state.momentum,'UniformOutput',false) ;
  end
end
if numGpus > 1
  mmap = map_gradients(opts.memoryMapFile, net, numGpus) ;
else
  mmap = [] ;
end

stats.time = 0 ;
stats.num = 0 ;
subset = state.(mode) ;
start = tic ;
num = 0 ;

for t=1:opts.batchSize:numel(subset)
  batchSize = min(opts.batchSize, numel(subset) - t + 1) ;

  for s=1:opts.numSubBatches
    % get this image batch and prefetch the next
    batchStart = t + (labindex-1) + (s-1) * numlabs ;
    batchEnd = min(t+opts.batchSize-1, numel(subset)) ;
    batch = subset(batchStart : opts.numSubBatches * numlabs : batchEnd) ;
    num = num + numel(batch) ;
    if numel(batch) == 0, continue ; end

    inputs = state.getBatch(state.imdb, batch) ;

    if opts.prefetch
      if s == opts.numSubBatches
        batchStart = t + (labindex-1) + opts.batchSize ;
        batchEnd = min(t+2*opts.batchSize-1, numel(subset)) ;
      else
        batchStart = batchStart + numlabs ;
      end
      nextBatch = subset(batchStart : opts.numSubBatches * numlabs : batchEnd) ;
      state.getBatch(state.imdb, nextBatch) ;
    end

    if strcmp(mode, 'train')
      net.mode = 'normal' ;
      net.accumulateParamDers = (s ~= 1) ;
      net.eval(inputs, opts.derOutputs) ;
    else
      net.mode = 'test' ;
      net.eval(inputs) ;
    end
  end

  % extract learning stats
  stats = opts.extractStatsFn(net) ;

  % accumulate gradient
  if strcmp(mode, 'train')
    if ~isempty(mmap)
      write_gradients(mmap, net) ;
      labBarrier() ;
    end
    state = accumulate_gradients(state, net, opts, batchSize, mmap) ;
  end

  % print learning statistics
  time = toc(start) ;
  stats.num = num ;
  stats.time = toc(start) ;

  fprintf('%s: epoch %02d: %3d/%3d: %.1f Hz', ...
    mode, ...
    state.epoch, ...
    fix(t/opts.batchSize)+1, ceil(numel(subset)/opts.batchSize), ...
    stats.num/stats.time * max(numGpus, 1)) ;
  for f = setdiff(fieldnames(stats)', {'num', 'time'})
    f = char(f) ;
    fprintf(' %s:', f) ;
    fprintf(' %.3f', stats.(f)) ;
  end
  fprintf('\n') ;
end

net.reset() ;
net.move('cpu') ;

% -------------------------------------------------------------------------
function state = accumulate_gradients(state, net, opts, batchSize, mmap)
% -------------------------------------------------------------------------
for p=1:numel(net.params)

  % bring in gradients from other GPUs if any
  if ~isempty(mmap)
    numGpus = numel(mmap.Data) ;
    tmp = zeros(size(mmap.Data(labindex).(net.params(p).name)), 'single') ;
    for g = setdiff(1:numGpus, labindex)
      tmp = tmp + mmap.Data(g).(net.params(p).name) ;
    end
    net.params(p).der = net.params(p).der + tmp ;
  else
    numGpus = 1 ;
  end

  switch net.params(p).trainMethod

    case 'average' % mainly for batch normalization
      thisLR = net.params(p).learningRate ;
      net.params(p).value = ...
          (1 - thisLR) * net.params(p).value + ...
          (thisLR/batchSize) * net.params(p).der ;

    case 'gradient'
      thisDecay = opts.weightDecay * net.params(p).weightDecay ;
      thisLR = state.learningRate * net.params(p).learningRate ;
      state.momentum{p} = opts.momentum * state.momentum{p} ...
        - thisDecay * net.params(p).value ...
        - (1 / batchSize) * net.params(p).der ;
      net.params(p).value = net.params(p).value + thisLR * state.momentum{p} ;

    case 'otherwise'
      error('Unknown training method ''%s'' for parameter ''%s''.', ...
        net.params(p).trainMethod, ...
        net.params(p).name) ;
  end
end

% -------------------------------------------------------------------------
function mmap = map_gradients(fname, net, numGpus)
% -------------------------------------------------------------------------
format = {} ;
for i=1:numel(net.params)
  format(end+1,1:3) = {'single', size(net.params(i).value), net.params(i).name} ;
end
format(end+1,1:3) = {'double', [3 1], 'errors'} ;
if ~exist(fname) && (labindex == 1)
  f = fopen(fname,'wb') ;
  for g=1:numGpus
    for i=1:size(format,1)
      fwrite(f,zeros(format{i,2},format{i,1}),format{i,1}) ;
    end
  end
  fclose(f) ;
end
labBarrier() ;
mmap = memmapfile(fname, 'Format', format, 'Repeat', numGpus, 'Writable', true) ;

% -------------------------------------------------------------------------
function write_gradients(mmap, net)
% -------------------------------------------------------------------------
for i=1:numel(net.params)
  mmap.Data(labindex).(net.params(i).name) = gather(net.params(i).der) ;
end

% -------------------------------------------------------------------------
function stats = accumulateStats(stats_)
% -------------------------------------------------------------------------

stats = struct() ;

for s = {'train', 'val'}
  s = char(s) ;
  total = 0 ;

  for g = 1:numel(stats_)
    stats__ = stats_{g} ;
    num__ = stats__.(s).num ;
    total = total + num__ ;

    for f = setdiff(fieldnames(stats__.(s))', 'num')
      f = char(f) ;

      if g == 1
        stats.(s).(f) = 0 ;
      end
      stats.(s).(f) = stats.(s).(f) + stats__.(s).(f) * num__ ;

      if g == numel(stats_)
        stats.(s).(f) = stats.(s).(f) / total ;
      end
    end
  end
  stats.(s).num = total ;
end

% -------------------------------------------------------------------------
function stats = extractStats(net)
% -------------------------------------------------------------------------
sel = find(cellfun(@(x) isa(x,'dagnn.Loss'), {net.layers.block})) ;
stats = struct() ;
for i = 1:numel(sel)
  stats.(net.layers(sel(i)).outputs{1}) = net.layers(sel(i)).block.average ;
end

% -------------------------------------------------------------------------
function saveState(fileName, net, stats)
% -------------------------------------------------------------------------
net_ = net ;
net = net_.saveobj() ;
save(fileName, 'net', 'stats') ;

% -------------------------------------------------------------------------
function [net, stats] = loadState(fileName)
% -------------------------------------------------------------------------
load(fileName, 'net', 'stats') ;
net = dagnn.DagNN.loadobj(net) ;

% -------------------------------------------------------------------------
function epoch = findLastCheckpoint(modelDir)
% -------------------------------------------------------------------------
list = dir(fullfile(modelDir, 'net-epoch-*.mat')) ;
tokens = regexp({list.name}, 'net-epoch-([\d]+).mat', 'tokens') ;
epoch = cellfun(@(x) sscanf(x{1}{1}, '%d'), tokens) ;
epoch = max([epoch 0]) ;


function [Handles] = ctf_channel_plot(ctf,surf,CHAN,Handles)

% ctf_channel_plot - plot ctf.sensor data
%
% [Handles] = ctf_channel_plot(ctf [,surf][,CHAN][,H])
%
% ctf  - a struct returned by ctf_read
% surf - a surface tesselation struct, surf.vertices and surf.faces;
%        the default is to create a convex hull of the sensor locations
% CHAN - see ctf_channel_select for options (default, CHAN = 'meg')
%
% Handles - handles struct, eg:
%           H.Hf - figure handle to plot into (default, H.Hf = figure;)
%           H.Hs - sensor handles
%           H.Hp - patch handles
%           H.Hl - light handles
%
% All inputs, except ctf, are optional.  An empty input [] will be replaced
% with the default.
%
%      <>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
%      <                                                      >
%      <                    DISCLAIMER:                       >
%      <                                                      >
%      < THIS PROGRAM IS INTENDED FOR RESEARCH PURPOSES ONLY. >
%      < THIS PROGRAM IS IN NO WAY INTENDED FOR CLINICAL OR   >
%      <                    OFFICIAL USE.                     >
%      <                                                      >
%      <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>
%

% $Revision: 1.1 $ $Date: 2009-01-30 03:49:26 $

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

% Modified: 05/2004, Darren.Weber_at_radiology.ucsf.edu
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if ~exist('ctf','var'), error('no ctf input'); end
if isempty(ctf), error('no ctf input'); end

% check the figure handle for initialization
if ~exist('Handles','var'),
  Handles.Hf = figure;
  colordef(Handles.Hf,'white')
end
if isempty(Handles),
  Handles.Hf = figure;
  colordef(Handles.Hf,'white')
end
if ~isfield(Handles,'Hf'),
  Handles.Hf = figure;
  colordef(Handles.Hf,'white')
end
if isempty(Handles.Hf),
  Handles.Hf = figure;
  colordef(Handles.Hf,'white')
end

% check other fields of the Handles
if ~isfield(Handles,'Hp'), Handles.Hp = {}; end
if ~isfield(Handles,'Hs'), Handles.Hs = {}; end
if ~isfield(Handles,'Hl'), Handles.Hl = []; end

usesurf = 1; % assume input surf
if ~exist('surf','var'), usesurf = 0; end
if isempty(surf), usesurf = 0; end

if ~exist('CHAN','var'), CHAN = 'meg'; end
if CHAN,
  % Get the channel indices to plot
  [CHAN,type] = ctf_channel_select(ctf,CHAN);
  sensors.vertices = zeros(length(CHAN),3);
  for i = 1:length(CHAN),
    sensors.vertices(i,:) = ctf.sensor.info(CHAN(i)).location(:,1)';
  end
end

ver = '$Revision: 1.1 $ $Date: 2009-01-30 03:49:26 $';
fprintf('\nCTF_CHANNEL_PLOT [v %s]\n',ver(11:15));

figure(Handles.Hf); hold on
set(Handles.Hf,'Renderer','OpenGL')

if CHAN,
  % plot the sensor cloud
  Handles.Hs{end+1} = scatter3(sensors.vertices(:,1),...
                               sensors.vertices(:,2),...
                               sensors.vertices(:,3),...
                               50,'bo','filled');
end

if ~usesurf,
  % nothing provided, assume we want
  % to create a convex hull of the sensors
  surf.vertices = sensors.vertices;
  surf.faces = convhulln(surf.vertices);
end
Nvert = length(surf.vertices);

% assume surface is a skin color
skinRGB = [1, 0.85, 0.75];
vertexColors = ones(Nvert,1) * skinRGB;

% plot the surface patch (eg, sensors or scalp)
Handles.Hp{end+1} = patch('faces',surf.faces,'vertices',surf.vertices,...
                          'facecolor','interp',...
                          'FaceVertexCData', vertexColors,...
                          'edgecolor', 'none',...
                          'facealpha',0.5);

% view parameters
view([40,20])
daspect([1 1 1])
axis equal
axis tight
grid on

lighting phong
material dull

% only add a light if it doesn't exist already
if ~isfield(Handles,'Hl'),
  Handles.Hl = camlight;
elseif isempty(Handles.Hl),
  Handles.Hl = camlight;
end

% The CTF MEG Head Coordinate System is
% +X anterior, +Y left, +Z superior
xlabel('x (cm)')
ylabel('y (cm)')
zlabel('z (cm)')

rotate3d on

return


function model=sortModel(model,sortReversible,sortMetName,sortReactionOrder)
% sortModel
%   Sorts a model based on metabolite names and compartments
%
%   model             a model structure
%   sortReversible    sorts the reversible reactions so the the metabolite
%                     that is first in lexiographical order is a reactant
%                     (opt, default true)
%   sortMetName       sort the metabolite names in the equation, also uses
%                     compartment abbreviation (opt, default false)
%   sortReactionOrder sorts the reaction order within each subsystem so that
%                     reactions consuming some metabolite comes efter
%                     reactions producing it. This overrides the
%                     sortReversible option and reactions are sorted so that
%                     the production direction matches the consumption
%                     direction (opt, default false)
%
%   model             an updated model structure
%
%   Usage: model=sortModel(model,sortReversible,sortMetName,sortReactionOrder)

if nargin<2
    sortReversible=true;
end
if nargin<3
    sortMetName=false;
end
if nargin<4
    sortReactionOrder=false;
end

if sortMetName==true
    %Assuming that metComps are the indexes. Should be changed at one point
    [~, metIndexes]=sort(strcat(model.metNames,'[',model.comps(model.metComps),']'));
    model=permuteModel(model,metIndexes,'mets');
end

if sortReversible==true && sortReactionOrder==false
    %Get all reversible reactions
    revIndexes=find(model.rev);

    %Loop through them
    for i=1:numel(revIndexes)
        %Create a cell array with all the metabolite names
        mets=find(model.S(:,revIndexes(i)));
        metNames=strcat(model.metNames(mets),model.comps(model.metComps(mets)));

        if iscellstr(metNames)
            [~, indexes]=sort(metNames);

            if model.S(mets(indexes(1)),revIndexes(i))>0
                model.S(:,revIndexes(i))=model.S(:,revIndexes(i))*-1;
            end
        end
    end
end

if sortReactionOrder==true
    %Check if the model has sub-systems, otherwise throw an error
    if ~isfield(model,'subSystems')
        EM='The model must contain a subSystems field in order to sort reaction order';
        dispEM(EM);
    end

    subsystemsUnique='';
    subsystemsConcatenated='';
    for i=1:numel(model.subSystems)
        subsystemsConcatenated{i,1}=strjoin(model.subSystems{i,1},';');
        if ~isempty(model.subSystems{i,1})
            for j=1:numel(model.subSystems{i,1})
                subsystemsUnique{numel(subsystemsUnique)+1,1}=model.subSystems{i,1}{1,j};
            end
        end
    end
    subsystemsUnique=unique(subsystemsUnique);
    for i=1:numel(subsystemsUnique)
        %Get all reactions for that subsystem
        rxns=find(~cellfun(@isempty,regexp(subsystemsConcatenated,subsystemsUnique(i))));

        %Temporarily ignore large subsystems because of inefficient
        %implementation
        if numel(rxns)<2 || numel(rxns)>250
            continue;
        end

        nRxns=numel(rxns);
        revRxns=rxns(model.rev(rxns)~=0);

        %This variable will hold the current reversibility directions of
        %the reversible reactions. 1 means the same direction as in the
        %original model and -1 means the opposite direction.
        oldRev=ones(numel(revRxns),1);

        %The problem could probably be solved analytically but a simple
        %random method is implemented here instead. Two reactions are
        %chosen randomly and their positions are switched. A score is
        %calculated based on the number of metabolites that are produced
        %before they are consumed. If the perturbed model has a better or
        %equal score than the original the reaction order is switched. If
        %no increase in score has been seen after 1000*rxnsInSubsystem then
        %the optimization is terminated

        rxnOrder=1:nRxns;
        oldScore=-inf;
        counter=0;
        firstIter=true;
        while 1==1
            counter=counter+1;
            if counter==100*nRxns
                break;
            end

            newRxnOrder=rxnOrder;
            rev=oldRev;

            if firstIter==false
                y=randperm(nRxns,2);

                %Switch the order
                newRxnOrder(y(1))=rxnOrder(y(2));
                newRxnOrder(y(2))=rxnOrder(y(1));

                %With a 50% chance, also switch the reversibility of one of
                %the reactions
                if rand()>0.5 && numel(rev)>1
                    n=randperm(numel(rev),1);
                    rev(n)=rev(n)*-1;
                end
            end
            firstIter=false;

            tempS=model.S;

            %Switch the directionalities
            for j=1:numel(rev)
                if rev(j)==-1
                    tempS(:,revRxns(j))=tempS(:,revRxns(j)).*-1;
                end
            end

            %Get the metabolites that are involved and when they are
            %produced/consumed
            s=tempS(:,newRxnOrder);

            %Remove mets that aren't used in both directions
            s=s(any(s,2),:);

            %Add so that all mets are produced and consumed in the end
            s=[s ones(size(s,1),1) ones(size(s,1),1)*-1];

            %For each metabolite, find the reaction where it's first
            %produced and the reaction where it's first consumed
            s1=s>0;
            r1=arrayfun(@(x) find(s1(x,:),1,'first'),1:size(s1,1));
            s2=s<0;
            r2=arrayfun(@(x) find(s2(x,:),1,'first'),1:size(s2,1));

            score=sum(r1<r2);

            if score>=oldScore
                if score>oldScore
                    counter=0;
                end
                oldScore=score;
                oldRev=rev;
                rxnOrder=newRxnOrder;
            end
        end

        %Update the model for this subsystem
        for j=1:numel(oldRev)
            if oldRev(j)==-1
                model.S(:,revRxns(j))=model.S(:,revRxns(j)).*-1;
            end
        end
        order=1:numel(model.rxns);
        order(rxns)=rxns(rxnOrder);
        model=permuteModel(model, order, 'rxns');
    end
end
end


function [SPM,xSPM] = spm_getSPM(varargin)
% Compute a specified and thresholded SPM/PPM following estimation
% FORMAT [SPM,xSPM] = spm_getSPM;
% Query SPM in interactive mode.
%
% FORMAT [SPM,xSPM] = spm_getSPM(xSPM);
% Query SPM in batch mode. See below for a description of fields that may
% be present in xSPM input. Values for missing fields will be queried
% interactively.
%
% xSPM      - structure containing SPM, distribution & filtering details
% .swd      - SPM working directory - directory containing current SPM.mat
% .title    - title for comparison (string)
% .Z        - minimum of Statistics {filtered on u and k}
% .n        - conjunction number <= number of contrasts
% .STAT     - distribution {Z, T, X, F or P}
% .df       - degrees of freedom [df{interest}, df{residual}]
% .STATstr  - description string
% .Ic       - indices of contrasts (in SPM.xCon)
% .Im       - indices of masking contrasts (in xCon)
% .pm       - p-value for masking (uncorrected)
% .Ex       - flag for exclusive or inclusive masking
% .u        - height threshold
% .k        - extent threshold {voxels}
% .XYZ      - location of voxels {voxel coords}
% .XYZmm    - location of voxels {mm}
% .S        - search Volume {voxels}
% .R        - search Volume {resels}
% .FWHM     - smoothness {voxels}
% .M        - voxels -> mm matrix
% .iM       - mm -> voxels matrix
% .VOX      - voxel dimensions {mm} - column vector
% .DIM      - image dimensions {voxels} - column vector
% .Vspm     - Mapped statistic image(s)
% .Ps       - uncorrected P values in searched volume (for voxel FDR)
% .Pp       - uncorrected P values of peaks (for peak FDR)
% .Pc       - uncorrected P values of cluster extents (for cluster FDR)
% .uc       - 0.05 critical thresholds for FWEp, FDRp, FWEc, FDRc
% .thresDesc - description of height threshold (string)
%
% Required fields of SPM
%
% xVol   - structure containing details of volume analysed
%
% xX     - Design Matrix structure
%        - (see spm_spm.m for structure)
%
% xCon   - Contrast definitions structure array
%        - (see also spm_FcUtil.m for structure, rules & handling)
% .name  - Contrast name
% .STAT  - Statistic indicator character ('T', 'F' or 'P')
% .c     - Contrast weights (column vector contrasts)
% .X0    - Reduced design matrix data (spans design space under Ho)
%          Stored as coordinates in the orthogonal basis of xX.X from spm_sp
%          (Matrix in SPM99b)  Extract using X0 = spm_FcUtil('X0',...
% .iX0   - Indicates how contrast was specified:
%          If by columns for reduced design matrix then iX0 contains the
%          column indices. Otherwise, it's a string containing the
%          spm_FcUtil 'Set' action: Usually one of {'c','c+','X0'}
% .X1o   - Remaining design space data (X1o is orthogonal to X0)
%          Stored as coordinates in the orthogonal basis of xX.X from spm_sp
%          (Matrix in SPM99b)  Extract using X1o = spm_FcUtil('X1o',...
% .eidf  - Effective interest degrees of freedom (numerator df)
%        - Or effect-size threshold for Posterior probability
% .Vcon  - Name of contrast (for 'T's) or ESS (for 'F's) image
% .Vspm  - Name of SPM image
%
% Evaluated fields in xSPM (input)
%
% xSPM      - structure containing SPM, distribution & filtering details
% .swd      - SPM working directory - directory containing current SPM.mat
% .title    - title for comparison (string)
% .Ic       - indices of contrasts (in SPM.xCon)
% .n        - conjunction number <= number of contrasts
% .Im       - indices of masking contrasts (in xCon)
% .pm       - p-value for masking (uncorrected)
% .Ex       - flag for exclusive or inclusive masking
% .u        - height threshold
% .k        - extent threshold {voxels}
% .thresDesc - description of height threshold (string)
%
% In addition, the xCon structure is updated. For newly evaluated
% contrasts, SPM images (spmT_????.{img,hdr}) are written, along with
% contrast (con_????.{img,hdr}) images for SPM{T}'s, or Extra
% Sum-of-Squares images (ess_????.{img,hdr}) for SPM{F}'s.
%
% The contrast images are the weighted sum of the parameter images,
% where the weights are the contrast weights, and are uniquely
% estimable since contrasts are checked for estimability by the
% contrast manager. These contrast images (for appropriate contrasts)
% are suitable summary images of an effect at this level, and can be
% used as input at a higher level when effecting a random effects
% analysis. (Note that the ess_????.{img,hdr} and
% SPM{T,F}_????.{img,hdr} images are not suitable input for a higher
% level analysis.) See spm_RandFX.man for further details.
%
%__________________________________________________________________________
%
% spm_getSPM prompts for an SPM and applies thresholds {u & k}
% to a point list of voxel values (specified with their locations {XYZ})
% This allows the SPM be displayed and characterized in terms of regionally
% significant effects by subsequent routines.
%
% For general linear model Y = XB + E with data Y, design matrix X,
% parameter vector B, and (independent) errors E, a contrast c'B of the
% parameters (with contrast weights c) is estimated by c'b, where b are
% the parameter estimates given by b=pinv(X)*Y.
%
% Either single contrasts can be examined or conjunctions of different
% contrasts. Contrasts are estimable linear combinations of the
% parameters, and are specified using the SPM contrast manager
% interface [spm_conman.m]. SPMs are generated for the null hypotheses
% that the contrast is zero (or zero vector in the case of
% F-contrasts). See the help for the contrast manager [spm_conman.m]
% for a further details on contrasts and contrast specification.
%
% A conjunction assesses the conjoint expression of multiple effects. The
% conjunction SPM is the minimum of the component SPMs defined by the
% multiple contrasts.  Inference on the minimum statistics can be
% performed in different ways.  Inference on the Conjunction Null (one or
% more of the effects null) is accomplished by assessing the minimum as
% if it were a single statistic; one rejects the conjunction null in
% favor of the alternative that k=nc, that the number of active effects k
% is equal to the number of contrasts nc.  No assumptions are needed on
% the dependence between the tests.
%
% Another approach is to make inference on the Global Null (all effects
% null).  Rejecting the Global Null of no (u=0) effects real implies an
% alternative that k>0, that one or more effects are real.   A third
% Intermediate approach, is to use a null hypothesis of no more than u
% effects are real.  Rejecting the intermediate null that k<=u implies an
% alternative that k>u, that more than u of the effects are real.
%
% The Global and Intermediate nulls use results for minimum fields which
% require the SPMs to be identically distributed and independent. Thus,
% all component SPMs must be either SPM{t}'s, or SPM{F}'s with the same
% degrees of freedom. Independence is roughly guaranteed for large
% degrees of freedom (and independent data) by ensuring that the
% contrasts are "orthogonal". Note that it is *not* the contrast weight
% vectors per se that are required to be orthogonal, but the subspaces of
% the data space implied by the null hypotheses defined by the contrasts
% (c'pinv(X)). Furthermore, this assumes that the errors are
% i.i.d. (i.e. the estimates are maximum likelihood or Gauss-Markov. This
% is the default in spm_spm).
%
% To ensure approximate independence of the component SPMs in the case of
% the global or intermediate null, non-orthogonal contrasts are serially
% orthogonalised in the order specified, possibly generating new
% contrasts, such that the second is orthogonal to the first, the third
% to the first two, and so on.  Note that significant inference on the
% global null only allows one to conclude that one or more of the effects
% are real.  Significant inference on the conjunction null allows one to
% conclude that all of the effects are real.
%
% Masking simply eliminates voxels from the current contrast if they
% do not survive an uncorrected p value (based on height) in one or
% more further contrasts.  No account is taken of this masking in the
% statistical inference pertaining to the masked contrast.
%
% The SPM is subject to thresholding on the basis of height (u) and the
% number of voxels comprising its clusters {k}. The height threshold is
% specified as above in terms of an [un]corrected p value or
% statistic.  Clusters can also be thresholded on the basis of their
% spatial extent. If you want to see all voxels simply enter 0.  In this
% instance the 'set-level' inference can be considered an 'omnibus test'
% based on the number of clusters that obtain.
%
% BAYESIAN INFERENCE AND PPMS - POSTERIOR PROBABILITY MAPS
%
% If conditional estimates are available (and your contrast is a T
% contrast) then you are asked whether the inference should be 'Bayesian'
% or 'classical' (using GRF).  If you choose Bayesian the contrasts are of
% conditional (i.e. MAP) estimators and the inference image is a
% posterior probability map (PPM).  PPMs encode the probability that the
% contrast exceeds a specified threshold.  This threshold is stored in
% the xCon.eidf.  Subsequent plotting and tables will use the conditional
% estimates and associated posterior or conditional probabilities.
%
% see spm_results_ui.m for further details of the SPM results section.
% see also spm_contrasts.m
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Andrew Holmes, Karl Friston & Jean-Baptiste Poline
% $Id$

%-GUI setup
%--------------------------------------------------------------------------
spm_help('!ContextHelp',mfilename)
spm('Pointer','Arrow')

%-Select SPM.mat & note SPM results directory
%--------------------------------------------------------------------------
if (nargin > 0)
    xSPM = varargin{1};
end
try
    swd = xSPM.swd;
    sts = 1;
catch
    [spmmatfile, sts] = spm_select(1,'^SPM\.mat$','Select SPM.mat');
    swd = spm_str_manip(spmmatfile,'H');
end;
if ~sts, SPM = []; xSPM = []; return; end

%-Preliminaries...
%==========================================================================

%-Load SPM.mat
%--------------------------------------------------------------------------
try
    load(fullfile(swd,'SPM.mat'));
catch
    error(['Cannot read ' fullfile(swd,'SPM.mat')]);
end
SPM.swd = swd;

%-Change directory so that relative filenames are valid
%--------------------------------------------------------------------------
cd(SPM.swd);

%-Check the model has been estimated
%--------------------------------------------------------------------------
try
    XYZ  = SPM.xVol.XYZ;
catch

    %-Check the model has been estimated
    %----------------------------------------------------------------------
    str = { 'This model has not been estimated.';...
        'Would you like to estimate it now?'};
    if spm_input(str,1,'bd','yes|no',[1,0],1)
        SPM = spm_spm(SPM);
    else
        SPM = []; xSPM = [];
        return
    end
end

xX   = SPM.xX;                      %-Design definition structure
XYZ  = SPM.xVol.XYZ;                %-XYZ coordinates
S    = SPM.xVol.S;                  %-search Volume {voxels}
R    = SPM.xVol.R;                  %-search Volume {resels}
M    = SPM.xVol.M(1:3,1:3);         %-voxels to mm matrix
VOX  = sqrt(diag(M'*M))';           %-voxel dimensions

% check the data and other files have valid filenames
%-----------------------------------------------------------------------
try, SPM.xY.VY     = spm_check_filename(SPM.xY.VY);     end
try, SPM.xVol.VRpv = spm_check_filename(SPM.xVol.VRpv); end
try, SPM.Vbeta     = spm_check_filename(SPM.Vbeta);     end
try, SPM.VResMS    = spm_check_filename(SPM.VResMS);    end
try, SPM.VM        = spm_check_filename(SPM.VM);        end

%-Contrast definitions
%==========================================================================

%-Load contrast definitions (if available)
%--------------------------------------------------------------------------
try
    xCon = SPM.xCon;
catch
    xCon = {};
end

%==========================================================================
% - C O N T R A S T S ,   S P M    C O M P U T A T I O N ,    M A S K I N G
%==========================================================================

%-Get contrasts
%--------------------------------------------------------------------------
try
    Ic = xSPM.Ic;
catch
    [Ic,xCon] = spm_conman(SPM,'T&F',Inf,...
                           '    Select contrasts...',' for conjunction',1);
end
if isempty(xCon)
    % figure out whether new contrasts were defined, but not selected
    % do this by comparing length of SPM.xCon to xCon, remember added
    % indices to run spm_contrasts on them as well
    try
        noxCon = numel(SPM.xCon);
    catch
        noxCon = 0;
    end
    IcAdd = (noxCon+1):numel(xCon);
else
    IcAdd = [];
end

nc        = length(Ic);  % Number of contrasts

%-Allow user to extend the null hypothesis for conjunctions
%
% n: conjunction number
% u: Null hyp is k<=u effects real; Alt hyp is k>u effects real
%    (NB Here u is from Friston et al 2004 paper, not statistic thresh).
%                  u         n
% Conjunction Null nc-1      1     |    u = nc-n
% Intermediate     1..nc-2   nc-u  |    #effects under null <= u
% Global Null      0         nc    |    #effects under alt  > u,  >= u+1
%----------------------------------+---------------------------------------
if (nc > 1)
    try
        n = xSPM.n;
    catch
        if nc==2
            But = 'Conjunction|Global';      Val=[1 nc];
        else
            But = 'Conj''n|Intermed|Global'; Val=[1 NaN nc];
        end
        n = spm_input('Null hyp. to assess?','+1','b',But,Val,1);
        if isnan(n)
            if nc == 3,
                n = nc - 1;
            else
                n = nc - spm_input('Effects under null ','0','n1','1',nc-1);
            end
        end
    end
else
    n = 1;
end

%-Enforce orthogonality of multiple contrasts for conjunction
% (Orthogonality within subspace spanned by contrasts)
%--------------------------------------------------------------------------
if nc > 1 && n > 1 && ~spm_FcUtil('|_?',xCon(Ic), xX.xKXs)

    OrthWarn = 0;

    %-Successively orthogonalise
    %-NB: This loop is peculiarly controlled to account for the
    %     possibility that Ic may shrink if some contrasts disappear
    %     on orthogonalisation (i.e. if there are colinearities)
    %----------------------------------------------------------------------
    i = 1;
    while(i < nc), i = i + 1;

        %-Orthogonalise (subspace spanned by) contrast i w.r.t. previous
        %------------------------------------------------------------------
        oxCon = spm_FcUtil('|_',xCon(Ic(i)), xX.xKXs, xCon(Ic(1:i-1)));

        %-See if this orthogonalised contrast has already been entered
        % or is colinear with a previous one. Define a new contrast if
        % neither is the case.
        %------------------------------------------------------------------
        d     = spm_FcUtil('In',oxCon,xX.xKXs,xCon);

        if spm_FcUtil('0|[]',oxCon,xX.xKXs)

            %-Contrast was colinear with a previous one - drop it
            %--------------------------------------------------------------
            Ic(i) = [];
            i     = i - 1;

        elseif any(d)

            %-Contrast unchanged or already defined - note index
            %--------------------------------------------------------------
            Ic(i) = min(d);

        else

            %-Define orthogonalised contrast as new contrast
            %--------------------------------------------------------------
            OrthWarn = OrthWarn + 1;
            conlst     = sprintf('%d,',Ic(1:i-1));
            oxCon.name = sprintf('%s (orth. w.r.t {%s})', xCon(Ic(i)).name,...
                conlst(1:end-1));
            xCon  = [xCon, oxCon];
            Ic(i) = length(xCon);
        end

    end % while...

    if OrthWarn
        warning(sprintf(['Contrasts changed!  %d contrasts orthogonalized ',...
            'to allow conjunction inf.'], OrthWarn))
    end

    SPM.xCon = xCon;
end % if nc>1...
SPM.xCon = xCon;

%-Get contrasts for masking
%--------------------------------------------------------------------------
try
    Im = xSPM.Im;
    if ~isempty(Im)
        maskCon = 1;
    else
        maskCon = 0;
    end
catch
    maskCon = spm_input('mask with other contrast(s)','+1','y/n',[1,0],2);
end
if maskCon
    try
        Im = xSPM.Im;
    catch
        [Im,xCon] = spm_conman(SPM,'T&F',-Inf,...
            'Select contrasts for masking...',' for masking',1);
    end

    %-Threshold for mask (uncorrected p-value)
    %----------------------------------------------------------------------
    try
        pm = xSPM.pm;
    catch
        pm = spm_input('uncorrected mask p-value','+1','r',0.05,1,[0,1]);
    end

    %-Inclusive or exclusive masking
    %----------------------------------------------------------------------
    try
        Ex = xSPM.Ex;
    catch
        Ex = spm_input('nature of mask','+1','b','inclusive|exclusive',[0,1]);
    end
else
    Im = [];
    pm = [];
    Ex = [];
end

%-Create/Get title string for comparison
%--------------------------------------------------------------------------
if nc == 1
    str  = xCon(Ic).name;
else
    str  = [sprintf('contrasts {%d',Ic(1)),sprintf(',%d',Ic(2:end)),'}'];
    if n == nc
        str = [str ' (global null)'];
    elseif n == 1
        str = [str ' (conj. null)'];
    else
        str = [str sprintf(' (Ha: k>=%d)',(nc-n)+1)];
    end
end
if Ex
    mstr = 'masked [excl.] by';
else
    mstr = 'masked [incl.] by';
end
if length(Im) == 1
    str  = sprintf('%s (%s %s at p=%g)',str,mstr,xCon(Im).name,pm);

elseif ~isempty(Im)
    str  = [sprintf('%s (%s {%d',str,mstr,Im(1)),...
        sprintf(',%d',Im(2:end)),...
        sprintf('} at p=%g)',pm)];
end
try
    titlestr = xSPM.title;
    if isempty(titlestr)
        titlestr = str;
    end
catch
    titlestr     = spm_input('title for comparison','+1','s',str);
end

%-Bayesian or classical Inference?
%==========================================================================
if isfield(SPM,'PPM')

    % Make sure SPM.PPM.xCon field exists
    %----------------------------------------------------------------------
    if ~isfield(SPM.PPM,'xCon')
        SPM.PPM.xCon = [];
    end

    % Set Bayesian con type
    %----------------------------------------------------------------------
    if length(SPM.PPM.xCon) < Ic
        SPM.PPM.xCon(Ic).PSTAT = xCon(Ic).STAT;
    end

    % Make this one a Bayesian contrast - if first level
    %----------------------------------------------------------------------
    if isfield(SPM.PPM,'VB')
        [xCon(Ic).STAT] = deal('P');
    end

    if all(strcmp([SPM.PPM.xCon(Ic).PSTAT],'T'))

        % Simple contrast
        %------------------------------------------------------------------
        str = 'Effect size threshold for PPM';

        if isfield(SPM.PPM,'VB') % 1st level Bayes

            % For VB - set default effect size to zero
            %--------------------------------------------------------------
            Gamma = 0;
            xCon(Ic).eidf = spm_input(str,'+1','e',sprintf('%0.2f',Gamma));

        elseif nc == 1 && isempty(xCon(Ic).Vcon) % 2nd level Bayes
            % con image not yet written
            %--------------------------------------------------------------
            if spm_input('Inference',1,'b',{'Bayesian','classical'},[1 0]);

                %-Get Bayesian threshold (Gamma) stored in xCon(Ic).eidf
                % The default is one conditional s.d. of the contrast
                %----------------------------------------------------------
                Gamma         = sqrt(xCon(Ic).c'*SPM.PPM.Cb*xCon(Ic).c);
                xCon(Ic).eidf = spm_input(str,'+1','e',sprintf('%0.2f',Gamma));
                xCon(Ic).STAT = 'P';
            end
        end
    else
        % Compound contrast using Chi^2 statistic
        %------------------------------------------------------------------
        if ~isfield(xCon(Ic),'eidf') || isempty(xCon(Ic).eidf)
            xCon(Ic).eidf = 0; % temporarily
        end
    end
end

%-Compute & store contrast parameters, contrast/ESS images, & SPM images
%==========================================================================
SPM.xCon = xCon;
SPM      = spm_contrasts(SPM, unique([Ic, Im, IcAdd]));
xCon     = SPM.xCon;
STAT     = xCon(Ic(1)).STAT;
VspmSv   = cat(1,xCon(Ic).Vspm);

%-Check conjunctions - Must be same STAT w/ same df
%--------------------------------------------------------------------------
if (nc > 1) && (any(diff(double(cat(1,xCon(Ic).STAT)))) || ...
        any(abs(diff(cat(1,xCon(Ic).eidf))) > 1))
    error('illegal conjunction: can only conjoin SPMs of same STAT & df');
end

%-Degrees of Freedom and STAT string describing marginal distribution
%--------------------------------------------------------------------------
df     = [xCon(Ic(1)).eidf xX.erdf];
if nc > 1
    if n > 1
        str = sprintf('^{%d \\{Ha:k\\geq%d\\}}',nc,(nc-n)+1);
    else
        str = sprintf('^{%d \\{Ha:k=%d\\}}',nc,(nc-n)+1);
    end
else
    str = '';
end

switch STAT
    case 'T'
        STATstr = sprintf('%c%s_{%.0f}','T',str,df(2));
    case 'F'
        STATstr = sprintf('%c%s_{%.0f,%.0f}','F',str,df(1),df(2));
    case 'P'
        STATstr = sprintf('%s^{%0.2f}','PPM',df(1));
end

%-Compute (unfiltered) SPM pointlist for masked conjunction requested
%==========================================================================
fprintf('\t%-32s: %30s','SPM computation','...initialising')            %-#

%-Compute conjunction as minimum of SPMs
%--------------------------------------------------------------------------
Z     = Inf;
for i = Ic
    Z = min(Z,spm_get_data(xCon(i).Vspm,XYZ));
end

%-Copy of Z and XYZ before masking, for later use with FDR
%--------------------------------------------------------------------------
XYZum = XYZ;
Zum   = Z;

%-Compute mask and eliminate masked voxels
%--------------------------------------------------------------------------
for i = Im
    fprintf('%s%30s',repmat(sprintf('\b'),1,30),'...masking')           %-#

    Mask = spm_get_data(xCon(i).Vspm,XYZ);
    um   = spm_u(pm,[xCon(i).eidf,xX.erdf],xCon(i).STAT);
    if Ex
        Q = Mask <= um;
    else
        Q = Mask >  um;
    end
    XYZ   = XYZ(:,Q);
    Z     = Z(Q);
    if isempty(Q)
        fprintf('\n')                                                   %-#
        warning(sprintf('No voxels survive masking at p=%4.2f',pm));
        break
    end
end

%==========================================================================
% - H E I G H T   &   E X T E N T   T H R E S H O L D S
%==========================================================================

u   = -Inf;        % height threshold
k   = 0;           % extent threshold {voxels}

%-Get FDR mode
%--------------------------------------------------------------------------
try
    topoFDR = spm_get_defaults('stats.topoFDR');
catch
    topoFDR = true;
end

%-Height threshold - classical inference
%--------------------------------------------------------------------------
if STAT ~= 'P'

    %-Get height threshold
    %----------------------------------------------------------------------
    fprintf('%s%30s',repmat(sprintf('\b'),1,30),'...height threshold')  %-#
    try
        thresDesc = xSPM.thresDesc;
    catch
        if topoFDR
            str = 'FWE|none';
        else
            str = 'FWE|FDR|none';
        end
        thresDesc = spm_input('p value adjustment to control','+1','b',str,[],1);
    end

    switch thresDesc

        case 'FWE' % Family-wise false positive rate
            %--------------------------------------------------------------
            try
                u = xSPM.u;
            catch
                u = spm_input('p value (FWE)','+0','r',0.05,1,[0,1]);
            end
            thresDesc = ['p<' num2str(u) ' (' thresDesc ')'];
            u = spm_uc(u,df,STAT,R,n,S);

        case 'FDR' % False discovery rate
            %--------------------------------------------------------------
            if topoFDR,
                fprintf('\n');                                          %-#
                error('Change defaults.stats.topoFDR to use voxel FDR.');
            end
            try
                u = xSPM.u;
            catch
                u = spm_input('p value (FDR)','+0','r',0.05,1,[0,1]);
            end
            thresDesc = ['p<' num2str(u) ' (' thresDesc ')'];
            u = spm_uc_FDR(u,df,STAT,n,VspmSv,0);

        case 'none'  % No adjustment: p for conjunctions is p of the conjunction SPM
            %--------------------------------------------------------------
            try
                u = xSPM.u;
            catch
                u = spm_input(['threshold {',STAT,' or p value}'],'+0','r',0.001,1);
            end
            if u <= 1
                thresDesc = ['p<' num2str(u) ' (unc.)'];
                u = spm_u(u^(1/n),df,STAT);
            else
                thresDesc = [STAT '=' num2str(u) ];
            end

        otherwise
            %--------------------------------------------------------------
            fprintf('\n');                                              %-#
            error(sprintf('Unknown control method "%s".',thresDesc));

    end % switch thresDesc

    %-Compute p-values for topological and voxel-wise FDR (all search voxels)
    %----------------------------------------------------------------------
    if ~topoFDR
        %-Voxel-wise FDR
        fprintf('%s%30s',repmat(sprintf('\b'),1,30),'...for voxelFDR')  %-#
        switch STAT
            case 'Z'
                Ps   = (1-spm_Ncdf(Zum)).^n;
            case 'T'
                Ps   = (1 - spm_Tcdf(Zum,df(2))).^n;
            case 'X'
                Ps   = (1-spm_Xcdf(Zum,df(2))).^n;
            case 'F'
                Ps   = (1 - spm_Fcdf(Zum,df)).^n;
        end
        Ps = sort(Ps);
    end

    %-Peak FDR
    %----------------------------------------------------------------------
    [up,Pp] = spm_uc_peakFDR(0.05,df,STAT,R,n,Zum,XYZum,u);

    %-Cluster FDR
    %----------------------------------------------------------------------
    if STAT == 'T' && n == 1
        V2R        = 1/prod(SPM.xVol.FWHM(SPM.xVol.DIM > 1));
        [uc,Pc,ue] = spm_uc_clusterFDR(0.05,df,STAT,R,n,Zum,XYZum,V2R,u);
    else
        uc  = NaN;
        ue  = NaN;
        Pc  = [];
    end

    %-Peak FWE
    %----------------------------------------------------------------------
    uu      = spm_uc(0.05,df,STAT,R,n,S);

%-Height threshold - Bayesian inference
%--------------------------------------------------------------------------
elseif STAT == 'P'

    u_default = 1 - 1/SPM.xVol.S;
    str       = 'Posterior probability threshold for PPM';
    u         = spm_input(str,'+0','r',u_default,1);
    thresDesc = ['P>'  num2str(u) ' (PPM)'];

end % (if STAT)

%-Calculate height threshold filtering
%--------------------------------------------------------------------------
Q      = find(Z > u);

%-Apply height threshold
%--------------------------------------------------------------------------
Z      = Z(:,Q);
XYZ    = XYZ(:,Q);
if isempty(Q)
    fprintf('\n');                                                      %-#
    warning(sprintf('No voxels survive height threshold u=%0.2g',u))
end

%-Extent threshold (disallowed for conjunctions)
%--------------------------------------------------------------------------
if ~isempty(XYZ) && nc == 1

    fprintf('%s%30s',repmat(sprintf('\b'),1,30),'...extent threshold')  %-#

    %-Get extent threshold [default = 0]
    %----------------------------------------------------------------------
    try
        k = xSPM.k;
    catch
        k = spm_input('& extent threshold {voxels}','+1','r',0,1,[0,Inf]);
    end

    %-Calculate extent threshold filtering
    %----------------------------------------------------------------------
    A     = spm_clusters(XYZ);
    Q     = [];
    for i = 1:max(A)
        j = find(A == i);
        if length(j) >= k; Q = [Q j]; end
    end

    % ...eliminate voxels
    %----------------------------------------------------------------------
    Z     = Z(:,Q);
    XYZ   = XYZ(:,Q);
    if isempty(Q)
        fprintf('\n');                                                  %-#
        warning(sprintf('No voxels survive extent threshold k=%0.2g',k))
    end

else

    k = 0;

end % (if ~isempty(XYZ))

%-For Bayesian inference provide (default) option to display contrast values
%--------------------------------------------------------------------------
if STAT == 'P'
    if spm_input('Plot effect-size/statistic',1,'b',{'Yes','No'},[1 0])
        Z = spm_get_data(xCon(Ic).Vcon,XYZ);
    end
end

%==========================================================================
% - E N D
%==========================================================================
fprintf('%s%30s\n',repmat(sprintf('\b'),1,30),'...done')                %-#
spm('Pointer','Arrow')

%-Assemble output structures of unfiltered data
%==========================================================================
xSPM   = struct( ...
            'swd',      swd,...
            'title',    titlestr,...
            'Z',        Z,...
            'n',        n,...
            'STAT',     STAT,...
            'df',       df,...
            'STATstr',  STATstr,...
            'Ic',       Ic,...
            'Im',       Im,...
            'pm',       pm,...
            'Ex',       Ex,...
            'u',        u,...
            'k',        k,...
            'XYZ',      XYZ,...
            'XYZmm',    SPM.xVol.M(1:3,:)*[XYZ; ones(1,size(XYZ,2))],...
            'S',        SPM.xVol.S,...
            'R',        SPM.xVol.R,...
            'FWHM',     SPM.xVol.FWHM,...
            'M',        SPM.xVol.M,...
            'iM',       SPM.xVol.iM,...
            'DIM',      SPM.xVol.DIM,...
            'VOX',      VOX,...
            'Vspm',     VspmSv,...
            'thresDesc',thresDesc);

% RESELS per voxel (density) if it exists
%--------------------------------------------------------------------------
xSPM.VRpv = SPM.xVol.VRpv;
try
    xSPM.units = SPM.xVol.units;
catch
    try, xSPM.units = varargin{1}.units; end;
end

% p-values for topological and voxel-wise FDR
%--------------------------------------------------------------------------
try, xSPM.Ps    = Ps;             end  % voxel   FDR
try, xSPM.Pp    = Pp;             end  % peak    FDR
try, xSPM.Pc    = Pc;             end  % cluster FDR

% 0.05 critical thresholds for FWEp, FDRp, FWEc, FDRc
%--------------------------------------------------------------------------
try, xSPM.uc    = [uu up ue uc];  end


function batch_efficiency(dwcard)
% Start in directory above individual model/results directories
%
% :Usage:
% ::
%
%     function batch_efficiency(dwcard)
%
% :Inputs:
%
%   **dwcard:**
%        is a wildcard for directories to probe, e.g., 'subject*'
%
% ..
%    Tor Wager, 10/8/02
% ..

d = dir(dwcard);

mypwd = pwd;
eval(['diary ' mypwd filesep 'model_efficiency_stats.out'])

for i = 1:length(d)

	try
		spm_efficiency([d(i).name filesep 'SPM.mat']);
	catch
		disp(['Problem with subject ' d(i).name])
	end

end

diary off

return


function bin = imCropLabel(img, label)
%IMCROPLABEL Extract the portion of image that contains the specified label
%
%   BIN = imCropLabel(IMG, LABEL)
%   Crops the regions in original label image IMG that corresponds to the
%   label given by the index LABEL. Works for 2D and 3D images.
%   The result is a binary image. A 1-pixel thick boundary is left around
%   the binary result, unless the label touches original image borders.
%
%   Example
%     % read and segment a demo image
%     img = imread('coins.png');
%     bin = imFillHoles(imOtsuThreshold(img));
%     lbl = bwlabel(bin, 4);
%     % crop region corresponding to label 3
%     bin3 = imCropLabel(lbl, 3);
%     imshow(bin3);
%
%   See also
%   imcrop, label2rgb, imFindLabels
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2013-04-02,    using Matlab 7.9.0.529 (R2009b)
% Copyright 2013 INRA - Cepia Software Platform.

% get image size and dimension
dim = size(img);
nd = length(dim);

% binarize image
bin = img == label;

if nd == 2
    % first array direction
    l1 = sum(bin, 2);
    i0(1) = find(l1, 1, 'first');
    i1(1) = find(l1, 1, 'last');

    % second array direction
    l1 = sum(bin, 1);
    i0(2) = find(l1, 1, 'first');
    i1(2) = find(l1, 1, 'last');

    % try to add one pixel if not outside boundary
    inds = i0 > 1;
    i0(inds) = i0(inds) - 1;
    inds = i1 < dim;
    i1(inds) = i1(inds) + 1;

    % extract only the necessary part of image
    bin = bin(i0(1):i1(1), i0(2):i1(2));

elseif nd == 3
    % first array direction
    l1 = sum(sum(bin, 2), 3);
    i0(1) = find(l1, 1, 'first');
    i1(1) = find(l1, 1, 'last');

    % second array direction
    l1 = sum(sum(bin, 1), 3);
    i0(2) = find(l1, 1, 'first');
    i1(2) = find(l1, 1, 'last');

    % third array direction
    l1 = sum(sum(bin, 1), 2);
    i0(3) = find(l1, 1, 'first');
    i1(3) = find(l1, 1, 'last');

    % try to add one pixel if not outside boundary
    inds = i0 > 1;
    i0(inds) = i0(inds) - 1;
    inds = i1 < dim;
    i1(inds) = i1(inds) + 1;

    % extract only the necessary part of image
    bin = bin(i0(1):i1(1), i0(2):i1(2), i0(3):i1(3));

else
    error('Can not manage dimensions other than 2 or 3');
end


function so = filterStream(si,filter)
% FILTERSTREAM  Filter (matimatically) a stream
so = {feval(filter,streamCar(si)), ...
        delayEval(@filterStream,{streamCdr(si),filter})};


function val = get(c,prop_name)

% GET - Get correlation properties
%
% VAL = get(C,PROP_NAME)
% See HELP CORRELATION for description of primary property names:
%   Waveforms, Trig, Corr, Lag, Stat, Link, Clust
%
% Additional scalar properties:
%   Traces:         number of traces
%   Data_Length:    number of samples in each trace
%   Fs:             Frequency
%   Period:         Period
%   Nyq:            Nyquist frequency
%   **NOTE - The scalar properties listed above exist for each waveform
%   (except Traces). However, the correlation object requires them to be
%   the same. GET only reads the value associated with the first waveform
%   Normally this will not be an issue. If the correlation object
%   was created manually it is possible for these fields to be different.
%
% Additional vector properties (nx1):
%   Start, Trig, End:             same as Start_Matlab, End_Matlab
%   Start_Str, Trig_Str, End_Str:           String times
%   Start_Matlab, Trig_Matlab, End_Matlab:  Matlab-format times
%   Start_Epoch, Trig_Epoch, End_Epoch:     Epoch-format times
%
% Additional vector properties (nx1 cell vector)
%   Sta (or Station):       Cell vector of station names
%   Chan (or Component):    Cell vector of channel names
%
% Additional matrix properties (nxm matrix)
%   Data:                    Matrix of raw trace data
%                           (n traces) x (m samples)

% Author: Michael West, Geophysical Institute, Univ. of Alaska Fairbanks
% $Date$
% $Revision$

if nargin <= 1
    error('Not enough inputs');
end

if ~isa(c,'correlation')
    error('First argument must be a correlation object');
end

switch upper(prop_name)
    case {'WAVEFORMS'}
        val = c.W;
    case {'WAVEFORM'}
        val = c.W;
    case {'WAVES'}
        val = c.W;
    case {'TRIG'}
        val = c.trig;
    case {'TRIG_STR'}
        val = cellstr(datestr(c.trig,'dd-mmm-yyyy HH:MM:SS.FFF'));
    case {'TRIG_MATLAB'}
        val = c.trig;
    case {'TRIG_EPOCH'}
        disp('TRIG_EPOCH property not currently implimented');
    case {'CORR'}
        val = c.C;
    case {'LAG'}
        val = c.L;
    case {'STAT'}
        val = c.stat;
    case {'LINK'}
        val = c.link;
    case {'CLUST'}
        val = c.clust;
    case {'TRACES'}
        val = size(c.W,1);

    % FROM WAVEFORM/GET (SCALAR OUTPUT)
    case {'DATA_LENGTH'}
        vals = get(c.W,'DATA_LENGTH');
         %checkvals(vals);
       val = vals(1);
    case {'FS'}
        vals = get(c.W,'FS');
        %checkvals(vals);
        val = vals(1);
%     case {'PERIOD'}
%         val = get(c.W(1),'PERIOD');
%     case {'NYQ'}
%         val = get(c.W(1),'NYQ');

%     % FROM WAVEFORM/GET (VECTOR)
    case {'STATION', 'STA'}
        val = get(c.W,'STATION');
    case {'COMPONENT', 'CHAN'}
        val = get(c.W,'COMPONENT');
%     case {'CHAN'}
%         val = get(c.W,'COMPONENT');
%
%     case {'START'}
%         val = get(c.W,'START_MATLAB');
%     case {'END'}
%         val = get(c.W,'END_MATLAB');
%
%     case {'START_STR'}
%         val = get(c.W,'START_STR');
%     case {'START_MATLAB'}
%         val = get(c.W,'START_MATLAB');
%     case {'START_EPOCH'}
%         val = get(c.W,'START_EPOCH');
%
%     case {'END_STR'}
%         val = get(c.W,'END_STR');
%     case {'END_MATLAB'}
%         val = get(c.W,'END_MATLAB');
%     case {'END_EPOCH'}
%         val = get(c.W,'END_EPOCH');
%
%     case {'DURATION_STR'}
%         val = get(c.W,'DURATION_STR');
%     case {'DURATION_MATLAB'}
%         val = get(c.W,'DURATION_MATLAB');
%     case {'DURATION_EPOCH'}
%         val = get(c.W,'DURATION_EPOCH');

 % OTHER ROUTINES
    case {'DATA'}
        val = double(c.W);

    otherwise
        try
            % see if it is a valid waveform property
            val = get(c.W,prop_name);
        catch
            error([upper(prop_name) ' is not a valid argument for correlation/get']);
        end
end;

%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% CHECKVALS
% This function checks to see if each waveform has the same parameters

function checkvals(vals)

same = all(vals(:) == vals(1));

if ~same
    % Warning is disabled because it gets called repeatedly (annoyingly)
    % from within other scripts
    % warning('Waveforms have different frequencies or different numbers of samples. Consider VERIFY function');
end;


%kpamgenpattern 'shifts a pattern to yield a full scan '
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros pamgenpattern.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'First Input data object'
% Integer: numX 'Number of Steps X', default: 5: 'number of steps into X direction'
% Integer: numY 'Number of Steps Y', default: 5: 'number of steps into Y direction'
% Integer: stepX 'Step X', default: 1: 'steps into X direction to jump to while stepping'
% Integer: stepY 'Step Y', default: 1: 'steps into Y direction to jump to while stepping'
% OutputFile: o 'Output', required: 'Resulting output data object'
%
% Example: o = kpamgenpattern(i, {'i','';'numX',5;'numY',5;'stepX',1;'stepY',1;'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% pamgenpattern - shifts a pattern to yield a full scan
%
%  DESCRIPTION
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1996-2003, Rainer Heintzmann,  All rights reserved.
%

function varargout = kpamgenpattern(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,..] = kpamgenpattern(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'numX', 5;'numY', 5;'stepX', 1;'stepY', 1;'o', '__output'};
maxval={0,2,2,2,2,0};
minval={0,2,2,2,2,0};
istoggle=[0,0,0,0,0,0];
was_set=istoggle * 0;
paramtype={'InputFile','Integer','Integer','Integer','Integer','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 'pamgenpattern"  -k'],Inputs,narglist);


function [requ_clab, W, neighbor_clab]= procutil_getClabForLaplacian(dat, varargin)
%GETCLABFORLAPLACIAN - Get channels which are required for Laplacian filtering
%
%Synopsis:
%   CLAB= procutil_getClabForLaplacian(DAT, <OPT>)
%   CLAB= procutil_getClabForLaplacian(DAT, CLAB, <OPT>)
%
%Arguments:
%   DAT:    STRUCT   - Continuous or epoched data, or directly the full
%                      channel set from which the clabs for laplacian should
%                      be extracted
%   CLAB:   CELL     - Names of channels that should be filtered by
%                      proc_laplacian. Accepts wildcards.
%   OPT: 	PROPLIST - struct or property/value list of optional properties:
%     'FilterType': CHAR (default 'small') - Name of the type of Laplace
%                      filter that should be used. Simply add your filter
%                      to the subfunction 'getLaplaceFilter'.
%     'CLab': CELL     - Equal to CLAB as a second parameter.
%     'IgnoreCLab': CELL (default {'E*'}) - Names of the channels that are
%                      to be left out of the calculation.
%     'GridFcn': FUNC
%     'RequireCompleteNeighborhood: BOOL (default 1) - Enforce that a
%                      Laplace channel can only be returned if all the
%                      necessary neighbors are available.
%
%Returns:
%   REQU_CLAB:         cell array of channel labels, necessary for the
%                      given Laplace channels
%   W:                 filter matrix that can be used, e.g. in
%                      proc_linearDerivation, to calculate the Laplace
%                      channels
%   NEIGHBOR_CLAB:     Channels around the Laplace channels that are used
%                      for referencing
%
%Examples:
%   procutil_getClabForLaplacian(dat, {'C3', 'C4'});
%   procutil_getClabForLaplacian(dat, 'FilterType', 'large', 'CLab', {'C3', 'C4'});

%See:
% proc_laplacian
%
% Benjamin Blankertz
% Martijn Schreuder 06/12 - Updated the help documentation

props= {'CLab'                         '*'                    'CHAR|CELL{CHAR}'
        'IgnoreCLab'                   {'E*'}                 'CHAR|CELL{CHAR}'
        'GridFcn'                      @util_gridForLaplacian 'FUNC'
        'FilterType'                   'small'                'CHAR(small large horizontal vertical bip_to_anterior bip_to_posterior bip_to_left bip_to_right diagonal diagonal_small)'
        'RequireCompleteNeighborhood'  1                      'BOOL'};

if mod(nargin,2)==0,
  misc_checkType(varargin{1}, 'CHAR|CELL{CHAR}', 'CLAB');
  opt= opt_proplistToStruct(varargin{2:end});
  opt.CLab= varargin{1};
else
  opt= opt_proplistToStruct(varargin{:});
end

[opt,isdefault] = opt_setDefaults(opt, props);
opt_checkProplist(opt, props);
misc_checkType(dat, 'CELL{CHAR}|STRUCT(clab)');
tcstate= bbci_typechecking('off');

if ~iscell(opt.IgnoreCLab),
  opt.IgnoreCLab= {opt.IgnoreCLab};
end

if isstruct(dat)
  clab= dat.clab;
else
  clab= dat;
end

laplace= [];
laplace.grid= opt.GridFcn();
laplace.filter= procutil_lapGetLaplacianFilter(opt.FilterType);

rc= util_chanind(clab, cat(2, {'not'}, opt.IgnoreCLab));
nOrigChans= length(clab);
pos= zeros(2, nOrigChans);
for ic= 1:nOrigChans,
  pos(:,ic)= procutil_lapGetCoordinates(clab{ic}, laplace.grid);
end
pos(:,setdiff(1:nOrigChans,rc,'legacy'))= inf;

idx_tbf= util_chanind(clab, opt.CLab);
W= zeros(length(clab), length(idx_tbf));
lc= 0;
requ_clab= {};
neighbor_clab= cell(length(idx_tbf), 1);
for ci= 1:length(idx_tbf),
  cc= idx_tbf(ci);
  refChans= [];
  nRefs= size(laplace.filter,2);
  for ir= 1:nRefs,
    ri= find( pos(1,:)==pos(1,cc)+laplace.filter(1,ir) & ...
      pos(2,:)==pos(2,cc)+laplace.filter(2,ir) );
    refChans= [refChans ri];
  end
  if length(refChans)==nRefs | ~opt.RequireCompleteNeighborhood,
    lc= lc+1;
    W(cc,lc)= 1;
    if ~isempty(refChans),
      W(refChans,lc)= -1/length(refChans);
    end
    requ_clab= unique(cat(2, requ_clab, clab([cc refChans])),'legacy');
    neighbor_clab{ci}= clab(refChans);
  end
end
W= W(util_chanind(clab, requ_clab),:);

bbci_typechecking(tcstate);


classdef WrapperMshFile < FileReader

    properties (Access = private)
        dataBase
        lineNumber0
        tScan
        dimension
        nnode
    end

    properties (Access = private)
        lineNumber
    end

    methods (Access = public)

        function obj = WrapperMshFile(cParams)
            obj.init(cParams)
        end

        function read(obj)
            obj.openFile();
            obj.scanFile();
            obj.readDimensionAndNnode();
            obj.readCoordinates();
            obj.readConnec();
            obj.closeFile();
        end

        function d = getDataBase(obj)
            d = obj.dataBase;
        end

    end

    methods (Access = private)

        function init(obj,cParams)
            obj.filePath = cParams.filePath;
            obj.lineNumber0 = 7;
        end

        function scanFile(obj)
            t = textscan(obj.fid,'%s','delimiter','\n', 'headerlines',0);
            obj.tScan = t{1};
        end

        function readDimensionAndNnode(obj)
            lineDimension = 5;
            tLine = obj.readLines(lineDimension);
            tLinesS = split(tLine{1});
            tLinesD = str2double(tLinesS);
            obj.dimension = tLinesD(4);
            obj.nnode = tLinesD(8);
        end

        function readCoordinates(obj)
            iline = 0;
            line0 = obj.lineNumber0;
            isCoord = true;
            xNodes = zeros(1,obj.dimension);
            while isCoord
                iline = iline + 1;
                tLine = obj.readLines(iline + line0);
                if strcmp(tLine{1},'end coordinates ')
                    isCoord = false;
                else
                    isCoord = true;
                    tLinesS = split(tLine{1});
                    tLinesD = str2double(tLinesS);
                    xNodes(iline,:) = tLinesD(2:end-1,1);
                end
            end
            obj.dataBase.coord = xNodes;
        end

        function readConnec(obj)
            line0 = obj.lineNumber0 + size(obj.dataBase.coord,1) + 3;
            iline = 0;
            isCoord = true;
            conn = zeros(1,obj.nnode);
            while isCoord
                iline = iline + 1;
                tLine = obj.readLines(iline + line0);
                if strcmp(tLine{1},'end elements')
                    isCoord = false;
                else
                    isCoord = true;
                    tLinesS = split(tLine{1});
                    tLinesD = str2double(tLinesS);
                    conn(iline,:) = tLinesD(2:obj.nnode+1,1);
                end
            end
            obj.dataBase.connec = conn;
        end

        function tLine = readLines(obj,lineNumber,nLines)
            tLine = obj.tScan(lineNumber,:);
        end

    end

end


function mtrExportFibers(fg, fileName, xformToAcPc, xform, fiberToStrFlag, version)
% Exports fiber group to .pdb format file
%
%  mtrExportFibers(fg, fileName, [xformToAcPc], [xform=eye()],[fiberToStrFlag=true],[version=3])
%
% Writes a mrDiffusion fiber group structure to a pdb file.  You should
% always write to a version 3 file (the default) unless you know what you
% are doing and really need a version 2 file.
%
% If your fibers are already in AcPc space then you probably want to store
% them that way in the file as it makes everything else easier.  In that
% case don't set xformToAcPc and xform.  They will default to identity and
% leave your fibers in the AcPc space.
%
% fg:             Fiber group to save into PDB file
% fileName:       Filename for PDB file
% xformToAcPc:    Transform current fiber coordinates into AcPc space
% xform:          Transforms current fiber coordinates into the space we would like
%                 to store on file
% fiberToStrFlag: set to zero if want to use legacy code for saving pdb
%                 file
% version:        PDB 3 (default) or 2 (not desired)
%
% Examples: (See Debug configuration for testing)
%   fgName = fullfile(mrvDataRootPath,'quench','fibers','LeftArcuate_ver3.pdb');
%   fg = mtrImportFibers(fgName);
%   v = 3; mtrExportFibers(fg, 'deleteMe.pdb', [], [], [], v);
%
% Stanford VISTA Team

if ~exist('fiberToStrFlag', 'var')|| isempty(fiberToStrFlag) || fiberToStrFlag~=0
    fiberToStrFlag=true; %By defaultconvert the Matlab fiber data structure into one big contiguous array.
end

if ~exist('fileName','var') || isempty(fileName)
    fileName = mrvSelectFile('w', 'pdb', 'Write pdb fibers');
end

% Make sure extension is pdb
[p,n] = fileparts(fileName);
fileName = [fullfile(p,n),'.pdb'];

if ~exist('version', 'var')|| isempty(version), version = 3; end

if version ~= 2 && version ~= 3
	error('PDB version should be 2 or 3');
end

if(~exist('xformToAcPc','var') || isempty(xformToAcPc))
    xformToAcPc = eye(4);
end

% comment and explain, please
if(exist('xform','var') && ~isempty(xform) && (isstruct(xform) || ~all(all(xform==eye(4)))))
    fg = dtiXformFiberCoords(fg, xform);
    % xformToAcPc = xformToAcPc*inv(xform);
    xformToAcPc = xformToAcPc/xform;
end

% Create blank database for finding some of the sizes to write out
pdb = mtrPathwayDatabase();
% PDB structure will have stat header info, but fg will retain the actual
% statistics per path to record

%fg.params = {};
% This routine (see below) is empty.  If we want to check something, then
% let's figure out what and then check it. For now, I am commenting it out.
% [pdb,fg] = enforceRightStats(pdb,fg);
numstats = length( pdb.pathway_statistic_headers );
numalgs = 0;

% Set offset and open the file.
% Tragically the getAlgorithms... function is a single number that doesn't
% depend on the input argument.
%
offset = 4*4 + 16*8 + numstats * getStatisticsHeaderSize(pdb) + ...
    numalgs * getAlgorithmsHeaderSize(pdb); % 4 uint, 16 doubles
fid = fopen(fileName, 'wb');

% Writing header
fwrite(fid,offset,'uint');  % An integer that points to something ...
xformToAcPc = xformToAcPc';
fwrite(fid,xformToAcPc(:),'double');  % The xform
fwrite(fid,numstats,'uint');          % The number of statistics saved with the fibers

% Write statistics to the PDB header
saveStatisticsHeader(pdb,fid);

fwrite(fid,numalgs,'uint');  % Well, this is weird.  I guess numalgs is always zero.
% Write algorithm header
% saveAlgorithmHeader(pdb,fid);

fwrite(fid,version,'uint');

% Writing path info
numpaths = length(fg.fibers);
fwrite(fid,numpaths,'uint');
fileOffsets = zeros(1,numpaths);
for ff = 1:numpaths
    % Record current file position to write later
    fileOffsets(ff) = ftell(fid);

    path_offset = 3 * 4  + numstats*8; % 4 int, numstats double
    fwrite(fid,path_offset,'int');
    nn = size( fg.fibers{ff}, 2 );
    fwrite(fid,nn,'int');
    fwrite(fid,0,'int'); % algo type HACK
    fwrite(fid,1,'int'); % seedpointindex HACK ???

    % Write stats per path
    for as = 1:numstats
        fwrite(fid,fg.params{as}.stat(ff),'double');
    end

    % Writing path nodes
    %pos = fg.fibers{ff}.coords;
    pos = fg.fibers{ff};
    %pos = mrAnatXformCoords(xformFromAcpc, pos')';
    % Change from 1 based to 0 based positions in mm space
    %pos = pos - repmat([2,2,2]',1,size(pos,2));
    fwrite(fid,pos,'double');

    % Writing stats values per position
    for as = 1:numstats
        % Just write garbage as fiber groups can't handle per point stats
        if( pdb.pathway_statistic_headers(as).is_computed_per_point )
            error('Cannot export fiber group with per point statistics!');
            %fwrite(fid,this.pathways(p).point_stat_array(as,:),'double');
        end
    end
end

% Database Footer
fwrite(fid,fileOffsets,'uint64');
fclose(fid);

% Convert to string depending on the version.
if fiberToStrFlag
	if version == 2, str=fiberToStr(fg); end
	if version == 3, str=fiberToStr3(fg);end
    myf = fopen(fileName,'wb');fwrite(myf,str,'uint8');fclose(myf);%fclose(fid);return;
end
return;

%-----
function [pdb,fg] = enforceRightStats(pdb,fg)
%if ~isempty(fg.params) && ~ieNotDefined('fg.params{1}.name') && strcmpi(fg.params{1}.name,'weight')
% The above check is wrong because ieNotDefined cant work this way. This
% wrong check ends up destroying the params. Nor do I understand why this
% function always ends up overwriting the fibers.
return;

if ~isempty(fg.params) && isfield(fg.params{1},'name') && ~isempty(fg.params{1}.name)
    tempFGParams = fg.params(1);
    fg.params = {};
    fg.params{1}.name = 'Length';
    for ff=1:length(fg.fibers)
        fiber = fg.fibers{ff};
        if(size(fiber,2)<size(fiber,1)); fiber=fiber'; end
        mmPerStep = sqrt(sum((fiber(:,1)-fiber(:,2)).^2));
        fg.params{1}.stat(ff) = mmPerStep*(size(fiber,2)-1);
    end
    s=length(pdb.pathway_statistic_headers)+1;
    pdb = addStatisticHeader(pdb,fg.params{1}.name,'NA', 1, 0, 1, 8877+s);
    fg.params(2) = tempFGParams;
    s=length(pdb.pathway_statistic_headers)+1;
    pdb = addStatisticHeader(pdb,fg.params{2}.name,'NA', 1, 0, 1, 8877+s);
    for ii=3:3
        pdb = addBlankStat(pdb,'Blank');
        fg.params{ii}.name = 'Blank';
        fg.params{ii}.stat = zeros(1,length(fg.fibers));
    end
else
    fg.params = {};
    fg.params{1}.name = 'Length';
    for ff=1:length(fg.fibers)
        fiber = fg.fibers{ff};
        if(size(fiber,2)<size(fiber,1)); fiber=fiber'; end
        mmPerStep = sqrt(sum((fiber(:,1)-fiber(:,2)).^2));
        fg.params{1}.stat(ff) = mmPerStep*(size(fiber,2)-1);
    end
    for ii=2:3
        pdb = addBlankStat(pdb,'Blank');
        fg.params{ii}.name = 'Blank';
        fg.params{ii}.stat = zeros(1,length(fg.fibers));
        %     if numstats>=ii
        %         pdb = addBlankStat(pdb,fg.params{ii}.name);
        %     else
        %         pdb = addBlankStat(pdb,'Blank');
        %         fg.params{ii}.stat = zeros(1,length(fg.fibers));
        %     end
    end
end
return;

%-----
function pdb = addBlankStat(pdb,agg_name)
s=length(pdb.pathway_statistic_headers)+1;
pdb = addStatisticHeader(pdb,agg_name,'NA', 1, 0, 1, 8877+s);
return;


classdef TestFastNlMeansDenoisingColored
    %TestFastNlMeansDenoisingColored

    methods (Static)
        function test_1
            img = cv.imread(fullfile(mexopencv.root(),'test','lena.jpg'), ...
                'Color',true, 'ReduceScale',2);
            out = cv.fastNlMeansDenoisingColored(img, 'H',10, 'HColor',10);
            validateattributes(out, {class(img)}, {'size',size(img)});
        end

        function test_2
            % we use IMNOISE from Image Processing Toolbox
            if ~mexopencv.require('images')
                error('mexopencv:testskip', 'toolbox');
            end

            img = cv.imread(fullfile(mexopencv.root(),'test','lena.jpg'), ...
                'Color',true, 'ReduceScale',2);
            img = imnoise(img, 'gaussian');
            out = cv.fastNlMeansDenoisingColored(img, 'H',10, 'HColor',10);
            validateattributes(out, {class(img)}, {'size',size(img)});
        end

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

end


function x = unique(x)
%UNIQUE (overloaded)

if min(x.dim(1),x.dim(2))~=1
    error('UNIQUE currently only supported for vectors')
end

base = x.basis;
vars = x.lmi_variables;
[new_base,i,j] = unique(base,'rows');

x.basis = new_base;
if x.dim(2)==1
    x.dim(1) = size(new_base,1);
else
    x.dim(2) = size(new_base,1);
end
% Reset info about conic terms
x.conicinfo = [0 0];


function [ ] = DrawQuadrotor( x,y )
%DRAWQUADROTOR Summary of this function goes here
%   Detailed explanation goes here
rotor_R=0.15;
wheelbase=0.2;
offset=(wheelbase/2+rotor_R)/sqrt(2);
rectangle('Position',[x-offset-rotor_R,y-offset-rotor_R,2*rotor_R,2*rotor_R],'Curvature',[1,1],'edgecolor','k'),axis equal
rectangle('Position',[x-offset-rotor_R,y+offset-rotor_R,2*rotor_R,2*rotor_R],'Curvature',[1,1],'edgecolor','r'),axis equal
rectangle('Position',[x+offset-rotor_R,y-offset-rotor_R,2*rotor_R,2*rotor_R],'Curvature',[1,1],'edgecolor','k'),axis equal
rectangle('Position',[x+offset-rotor_R,y+offset-rotor_R,2*rotor_R,2*rotor_R],'Curvature',[1,1],'edgecolor','r'),axis equal
end