function gmsh_mesh3d_write ( gmsh_filename, m, node_num, node_x, ...
  element_order, element_num, element_node )

%*****************************************************************************80
%
%% GMSH_MESH3D_WRITE writes 3D mesh data as a Gmsh mesh file.
%
%  Discussion:
%
%    The node ordering for the 20 node element is not standard.
%
%    Assuming the vertices are A, B, C and D, Gmsh uses the following ordering:
%
%    1:    a
%    2:        b
%    3:            c
%    4:                d
%    5: (2*a  +b        )/3
%    6: (  a+2*b        )/3
%    7: (    2*b+  c    )/3
%    8: (      b+2*c    )/3
%    9: (  a    +2*c    )/3
%   10: (2*a    +  c    )/3
%   11: (2*a        +  d)/3
%   12: (  a        +2*d)/3
%   13: (     b     +2*d)/3
%   14: (   2*b     +  d)/3
%   15: (       +  c+2*d)/3
%   16: (       +2*c+  d)/3
%   17: (  a+  b+  c    )/3
%   18: (  a+  b    +  d)/3
%   19: (      b+  c+  d)/3
%   20: (  a+      c+  d)/3
%
%    Leo Rebholz used the following ordering:
%
%    1:    a
%    2:        b
%    3:            c
%    4:                d
%    5: (2*a  +b        )/3
%    6: (2*a    +  c    )/3
%    7: (  a+2*b        )/3
%    8: (  a    +2*c    )/3
%    9: (  a+  b+  c    )/3
%   10: (    2*b+  c    )/3
%   11: (      b+2*c    )/3
%   12: (2*a        +  d)/3
%   13: (   2*b     +  d)/3
%   14: (       +2*c+  d)/3
%   15: (  a+  b    +  d)/3
%   16: (      b+  c+  d)/3
%   17: (  a+      c+  d)/3
%   18: (  a        +2*d)/3
%   19: (     b     +2*d)/3
%   20: (       +  c+2*d)/3
%
%    Since the only 20 node data we have is from Leo, we will assume that
%    all 20 node input data is in Leo's format, and needs to be converted
%    to the Gmsh convention.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    07 October 2014
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Christophe Geuzaine, Jean-Francois Remacle,
%    Gmsh: a three-dimensional finite element mesh generator with
%    built-in pre- and post-processing facilities,
%    International Journal for Numerical Methods in Engineering,
%    Volume 79, Number 11, pages 1309-1331, 2009.
%
%  Parameters:
%
%    Input, string GMSH_FILENAME, the name of the Gmsh file.
%
%    Input, integer M, the spatial dimension.
%
%    Input, integer NODE_NUM, the number of nodes.
%
%    Input, real NODE_X(M,NODE_NUM), the node coordinates.
%
%    Input, integer ELEMENT_ORDER, the order of the elements.
%
%    Input, integer ELEMENT_NUM, the number of elements.
%
%    Input, integer ELEMENT_NODE(ELEMENT_ORDER,ELEMENT_NUM), the nodes
%    that make up each element.
%
  leo_to_gmsh = [...
     1,  2,  3,  4,  5, ...
     7, 10, 11,  8,  6, ...
    12, 18, 19, 13, 20, ...
    14,  9, 15, 16, 17 ];
%
%  Enforce 1-based indexing.
%
  element_node = mesh_base_one ( node_num, element_order, element_num, ...
    element_node );
%
%  Open the file.
%
  gmsh = fopen ( gmsh_filename, 'wt' );

  if ( gmsh < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'GMSH_MESH3D_WRITE - Error!\n' );
    fprintf ( 1, '  Could not open the output file.\n' );
    error ( 'GMSH_MESH3D_WRITE - Error!' );
  end
%
%  Write the data.
%
  fprintf ( gmsh, '$MeshFormat\n' );
  fprintf ( gmsh, '2.2 0 8\n' );
  fprintf ( gmsh, '$EndMeshFormat\n' );

  fprintf ( gmsh, '$Nodes\n' );
  fprintf ( gmsh, '%d\n', node_num );
  for node = 1 : node_num
    fprintf ( gmsh, '%d', node );
    for dim = 1 : 3
      if ( dim <= m )
        fprintf ( gmsh, '  %g', node_x(dim,node) );
      else
        fprintf ( gmsh, '  %g', 0.0 );
      end
    end
    fprintf ( gmsh, '\n' );
  end
  fprintf ( gmsh, '$EndNodes\n' );
%
%  These are the Gmsh codes for 4, 10 and 20 node tetrahedral elements.
%
  if ( element_order == 4 )
    element_type = 4;
  elseif ( element_order == 10 )
    element_type = 11;
  elseif ( element_order == 20 )
    element_type = 29;
  end

  tag_num = 2;
  tag1 = 0;
  fprintf ( gmsh, '$Elements\n' );
  fprintf ( gmsh, '%d\n', element_num );
  for element = 1 : element_num
    fprintf ( gmsh, '%d  %d  %d  %d  %d', ...
      element, element_type, tag_num, tag1, element );
    for vertex = 1 : element_order
      if ( element_order == 20 )
        v = leo_to_gmsh(vertex);
      else
        v = vertex;
      end
      fprintf ( gmsh, '  %d', element_node(v,element) );
    end
    fprintf ( gmsh, '\n' );
  end
  fprintf ( gmsh, '$EndElements\n' );

  fclose ( gmsh );

  return
end


function module = noise_module_diagonal(varargin)

options = struct('init', struct(), ...
                 'prior', struct(), ...
                 'separation', 'rows', ...
                 'update_tau', 1);
[options, errmsg] = argparse(options, varargin{:});
error(errmsg);

init = struct('tau', 1);
[init, errmsg] = argparse(init, options.init);
error(errmsg);

prior = struct('a_tau', 1e-5, ...
               'b_tau', 1e-5);
[prior, errmsg] = argparse(prior, options.prior);
error(errmsg);

tau = [];
a_tau = [];
b_tau = [];
weights = [];

module.initialize = @initialize;
module.update = @update;
module.get_struct = @get_struct;

  function [Tau] = initialize(M,N)
  switch options.separation
   case 'rows'
    tau = nan(M,1);
    a_tau = nan(M,1);;
    b_tau = nan(M,1);
   case 'columns'
    tau = nan(1,N);
    a_tau = nan(1,N);
    b_tau = nan(1,N);
   otherwise
    error('Unknown separation');
  end

  tau(:) = init.tau(:);
  Tau = bsxfun(@plus, tau, zeros(M,N));
  end

  function S = get_struct()
  % TODO: not ready yet..
  S.module = 'noise_module_isotropic';
  S.tau = tau;
  S.a_tau = a_tau;
  S.b_tau = b_tau;
  S.prior = prior;
  S.init = init;
  S.options = options;
  end

  function [Tau, LogTau, KL_Tau] = update(iter, E2, Obs)

  % OBS is the number of observations for each element of E2.

  % <(Y-WX)^2>
  switch options.separation
   case 'rows'
    e2 = sum(E2,2);
    obs = sum(Obs,2);
   case 'columns'
    e2 = sum(E2,1);
    obs = sum(Obs,1);
   otherwise
    error('Unknown separation');
  end

  %
  % Update tau
  %

  if index_selected(iter, options.update_tau)

    a_tau(:) = prior.a_tau(:) + 0.5*obs(:);
    b_tau(:) = prior.b_tau(:) + 0.5*e2(:);

    tau = a_tau ./ b_tau;
    logtau = psi(a_tau) - log(b_tau);

    %
    % Compute Kullback-Leibler divergence KL(q(tau)||p(tau))
    %

    % <log p(Tau)>
    logpdf_p = sum(gamma_logpdf(tau(:), prior.a_tau(:), prior.b_tau(:), logtau(:)));

    % <log q(Tau)>
    logpdf_q = -sum(gamma_entropy(a_tau,b_tau));

    % KL(q||p)
    KL_Tau = logpdf_q - logpdf_p;

  else
    logtau = log(tau);
    KL_Tau = 0;
  end

  % Compute expectations of weighted Tau
  O = zeros(size(E2));
  Tau = bsxfun(@plus, tau, O);
  LogTau = bsxfun(@plus, logtau, O);

  end

end


function y = feval(f, x)
%FEVAL   Evaluate a CHEBTECH.
%   Y = FEVAL(F, X) evaluates of the CHEBTECH F at points X.
%
%   If size(F, 2) > 1 then FEVAL returns values in the form [F_1(X), F_2(X),
%   ...], where size(F_k(X)) = size(X).
%
%   Example:
%     f = chebtech2(@(x) 1./( 1 + 25*x.^2 ) );
%     x = linspace(-1, 1, 1000);
%     [xx, yy] = meshgrid(x, x);
%     ff = feval(f, xx + 1i*yy);
%     h = surf(xx, yy, 0*xx, angle(-ff));
%     set(h, 'edgealpha', 0)
%     view(0, 90), shg
%     colormap(hsv)
%
% See also BARY, CLENSHAW, NUDCT.

% Developer note: We use either Clenshaw's algorithm or a nonuniform DCT,
% depending on the dimensions of F and X (determined heuristically).

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

if ( isempty(f) )
    y = [];
    return
end

% Reshape x to be a column vector
[n, m] = size(f);
sizex = size(x);
ndimsx = ndims(x);
x = x(:);

if ( (m > 1) && (ndimsx > 2) )
    error('CHEBFUN:CHEBTECH:feval:evalArrayAtNDArray', ...
        ['Evaluation of a CHEBTECH with more than one column at inputs ' ...
         'with more than two dimensions is not supported.']);
end

if ( n <= 4000 || numel(x) <= 4000 )
    % Evaluate using Clenshaw's algorithm:
    y = f.clenshaw(x, f.coeffs);
else
    % Use fast transform for high degree Chebyshev expansions:
    y = chebfun.ndct(x, f.coeffs);
end

% Reshape the output if possible:
if ( (m == 1) && ( (ndimsx > 2) || (sizex(2) > 1) ) )
    y = reshape(y, sizex);
elseif ( (m > 1) && ( (ndimsx == 2) || (sizex(2) > 1) ) )
    y = reshape(y, sizex(1), m*numel(x)/sizex(1));
end

end


function plotData(D)

data = D.data;
Jumps = D.Jumps;
P = D.P;

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
%                           States                              %
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
figH = figure(1); clf;
set(figH,'Name','States','NumberTitle','off')

subplot(4,1,1);hold on;
plot(data.time,data.state.th);
ylabel('Angle (rad)')
xlabel('Time (s)')
dottedLine(Jumps,axis);

subplot(4,1,2); hold on;
plot(data.time,data.state.dth);
ylabel('Rate (rad)')
xlabel('Time (s)')
dottedLine(Jumps,axis);

subplot(4,1,3); hold on
plot(data.time,data.state.x,'r');
plot(data.time,data.state.y,'b');
legend('x','y');
ylabel('position (m)')
xlabel('Time (s)')
dottedLine(Jumps,axis);

subplot(4,1,4); hold on
plot(data.time,data.state.dx,'r');
plot(data.time,data.state.dy,'b');
legend('dx','dy');
ylabel('velocity (m/s)')
xlabel('Time (s)')
dottedLine(Jumps,axis);

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
%                                Traces                                   %
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%

L = P.L;
LL = P.FullLength;
x0 = data.state.x;
y0 = data.state.y;
x1 = x0 - L*sin(data.state.th);
y1 = y0 + L*cos(data.state.th);
x2 = x0 - LL*sin(data.state.th);
y2 = y0 + LL*cos(data.state.th);
bnd = [min(min(x0),min(x2)),max(max(x0),max(x2))];

figH = figure(3); clf; hold on;
set(figH,'Name','Traces','NumberTitle','off')

plot(bnd,[0,0],'k-','LineWidth',1);
plot(x0,y0,'r','LineWidth',3)
plot(x1,y1,'m','LineWidth',3)
plot(x2,y2,'b','LineWidth',3)
legend('ground','O','CoM','Tip');
axis 'equal';
xlabel('Horizontal Position (m)');
ylabel('Vertical Position (m)');

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
%                           Forces and Energy                             %
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
figH = figure(2); clf;
set(figH,'Name','Energy','NumberTitle','off')

subplot(3,1,1); hold on;
plot(data.time,data.contact.h,'r');
plot(data.time,data.contact.v,'b');
legend('Horizontal','Vertical')
ylabel('Contact Force (N)')
xlabel('Time (s)')
dottedLine(Jumps,axis);

subplot(3,1,2); hold on;
E_pot = data.energy.potential;
E_kin = data.energy.kinetic;
plot(data.time,E_pot,'b');
plot(data.time,E_kin,'r');
plot(data.time,E_kin + E_pot,'k','LineWidth',2);
legend('Potential','Kinetic','Total','Location','NorthWest')
ylabel('Energy (J)')
xlabel('Time (s)')
dottedLine(Jumps,axis);

subplot(3,1,3); hold on;
plot(data.time,E_kin + E_pot,'k','LineWidth',2);
ylabel('Total Energy (J)')
xlabel('Time (s)')
dottedLine(Jumps,axis);

figH = figure(4); clf; hold on
set(figH,'Name','Contacts','NumberTitle','off')

th = data.state.th*180/pi;
plot(th,data.contact.h,'r');
plot(th,data.contact.v,'b');
legend('Horizontal','Vertical')
ylabel('Contact Force (N)')
xlabel('Angle (deg)')

end

%%%% SUB FUNCTIONS %%%%

function dottedLine(time,AXIS)

for i=1:length(time)
    %Plots a dotted line between phases
    plot(time(i)*[1;1],[AXIS(3);AXIS(4)],'k:','LineWidth',1);
end

end


function test8 (nmat)
%TEST8 order a large range of sparse matrices, test symbfact2
% compare AMD and METIS
% Example:
%   test8(nmat)
% See also cholmod_test

% Copyright 2006-2007, Timothy A. Davis, University of Florida

fprintf ('=================================================================\n');
fprintf ('test8: factorize a large range of sparse matrices\n') ;

% get list of test matrices

index = UFget ;

% GHS posdef test set (more or less)
f = find (...
    ((index.numerical_symmetry == 1 & index.isBinary) | (index.posdef)) ...
    & (index.nnzdiag == index.nrows) ...
    & (index.nrows > 10000 | index.nrows == 9000) ...
    & (index.nrows < 600000) & (index.nnz > index.nrows)) ;		    %#ok

% include small matrices
f = find (...
    ((index.numerical_symmetry == 1 & index.isBinary) | (index.posdef)) ...
    & (index.nnzdiag == index.nrows) ...
    & (index.nrows < 600000) & (index.nnz > index.nrows)) ;

for k = 1:length (f)
    names {k} = index.Name {f(k)} ;			%#ok
end

[ignore i] = sort (names) ;

f = f (i) ;

% fprintf ('test matrices sorted by name:\n') ;
% for i = f
%     fprintf ('%4d: %-20s %-20s %12d %d\n', i,  ...
% 	index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ;
% end

[ignore i] = sort (index.nrows (f)) ;
f = f (i) ;

if (nargin > 0)
    nmat = max (0,nmat) ;
    nmat = min (nmat, length (f)) ;
    f = f (1:nmat) ;
end

fprintf ('test matrices sorted by dimension:\n') ;
for i = f
    fprintf ('%4d: %-20s %-20s %12d %d\n', i,  ...
	index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ;
end

junk = sparse (1) ;

% input ('hit enter to continue: ') ;

for k = 1:length (f)

    Problem = UFget (f(k)) ;
    A = Problem.A ;
    fprintf ('\n================== Problem: %s  n: %d nnz: %d\n', ...
	Problem.name, size (A,1), nnz (A)) ;
    fprintf ('title: %s\n\n', Problem.title) ;
    clear Problem
    n = size (A,1) ;							    %#ok

    amd2 (junk) ;
    metis (junk) ;

    tic ;
    [p1,info] = amd2 (A) ;						    %#ok
    t1 = toc ;
    S1 = A (p1,p1) ;
    tic ;
    c1 = symbfact (S1) ;
    ts1 = toc ;
    tic ;
    d1 = symbfact (S1) ;
    ts2 = toc ;
    if (any (c1 ~= d1))
	error ('!')
    end
    fprintf ('symbfact time: MATLAB %9.4f  CHOLMOD %9.4f  speedup %8.2f\n', ...
	ts1, ts2, ts1/ts2) ;

    lnz1 = sum (c1) ;
    fl1 = sum (c1.^2) ;
    fprintf ('time: amd     %10.4f mnnz(L) %8.1f mfl %8.0f  fl/nnz(L) %8.1f\n', ...
	t1, lnz1/1e6, fl1 /1e6, fl1/lnz1) ;

    tic ;
    p2 = metis (A) ;
    t2 = toc ;
    S2 = A (p2,p2) ;
    c2 = symbfact (S2) ;
    lnz2 = sum (c2) ;
    fl2 = sum (c2.^2) ;

    fprintf ('time: metis   %10.4f mnnz(L) %8.1f mfl %8.0f  fl/nnz(L) %8.1f\n', ...
	t2, lnz2/1e6, fl2/1e6, fl2/lnz2) ;

    r = lnz2 / lnz1 ;							    %#ok
    fprintf ('\nmetis/amd time: %8.4f nnz(L): %8.4f\n', t2/t1, lnz2/lnz1) ;

    % save results
    lnz (k,1) = lnz1 ;			    %#ok
    lnz (k,2) = lnz2 ;			    %#ok
    fl1 (k,1) = fl1 ;			    %#ok
    fl2 (k,2) = fl2 ;			    %#ok
    t (k,1) = t1 ;			    %#ok
    t (k,2) = t2 ;			    %#ok

end

fprintf ('test8 passed\n') ;


%==============================================================================
% This code is part of the Matlab-based toolbox
% FAIR - Flexible Algorithms for Image Registration.
% For details see
% - https://github.com/C4IR and
% - http://www.siam.org/books/fa06/
% ##2
%==============================================================================
%
%   - data                 PETCT, Omega=(0,140)x(0,151), level=4:7, m=[128,128]
%   - viewer               viewImage2D
%   - interpolation        splineInter
%   - distance             NGF
%   - pre-registration     rigid2D
%   - regularizer          mbCurvature
%   - optimization         Gauss-Newton
% ===============================================================================

close all, help(mfilename);

setup2DPETCTData
imgModel('reset','imgModel','splineInter','regularizer','moments','theta',1e-2);
distance('reset','distance','NGF','edge',25);
trafo('reset','trafo','rigid2D');
regularizer('reset','regularizer','mbCurvature','alpha',10);
[yc,wc,his] = MLIR(ML,...
  'minLevel',4,'maxIterNPIR',25,'parametric',1,'plotMLiter',0);

%==============================================================================


function w = m_ilut_2dir(v,aparams,mparams)
%m_ilut_2dir     two-directional ILU preconditioning
%   w = m_ilut_2dir(v,aparams,mparams)
%   input
%          v            operand for preconditioning operator
%          aparams      structure defining coefficient matrix
%          mparams      structure defining preconditioning matrix
%                          factored splitting operators L*U, Lv*Uv
%                          permutation vectors p, ip
%   output
%          w            result of preconditioning operation
%
%   IFISS function: HCE; 28 February 2005.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage

w = mparams.U\(mparams.L\v);
r = v - aparams.A*w;
rp = r(mparams.ip);
rp = mparams.Uv\(mparams.Lv\rp);
rpp = rp(mparams.p);
w = w + rpp;


% READLOCS - read electrode location coordinates and other information from a file.
%              Several standard file formats are supported. Users may also specify
%              a custom column format. Defined format examples are given below
%              (see File Formats).
% Usage:
%   >>  eloc = readlocs( filename );
%   >>  EEG.chanlocs = readlocs( filename, 'key', 'val', ... );
%   >>  [eloc, labels, theta, radius, indices] = ...
%                                               readlocs( filename, 'key', 'val', ... );
% Inputs:
%   filename   - Name of the file containing the electrode locations
%                {default: 2-D polar coordinates} (see >> help topoplot )
%
% Optional inputs:
%   'filetype'  - ['loc'|'sph'|'sfp'|'xyz'|'asc'|'polhemus'|'besa'|'chanedit'|'custom']
%                 Type of the file to read. By default the file type is determined
%                 using the file extension (see below under File Formats),
%                  'loc'   an EEGLAB 2-D polar coordinates channel locations file
%                          Coordinates are theta and radius (see definitions below).
%                  'sph'   Matlab spherical coordinates (Note: spherical
%                          coordinates used by Matlab functions are different
%                          from spherical coordinates used by BESA - see below).
%                  'sfp'   EGI Cartesian coordinates (NOT Matlab Cartesian - see below).
%                  'xyz'   Matlab/EEGLAB Cartesian coordinates (NOT EGI Cartesian).
%                          z is toward nose; y is toward left ear; z is toward vertex
%                  'asc'   Neuroscan polar coordinates.
%                  'polhemus' or 'polhemusx' - Polhemus electrode location file recorded
%                          with 'X' on sensor pointing to subject (see below and READELP).
%                  'polhemusy' - Polhemus electrode location file recorded with
%                          'Y' on sensor pointing to subject (see below and READELP).
%                  'besa' BESA-'.elp' spherical coordinates. (Not MATLAB spherical -
%                           see below).
%                  'chanedit' - EEGLAB channel location file created by POP_CHANEDIT.
%                  'custom' - Ascii file with columns in user-defined 'format' (see below).
%   'importmode' - ['eeglab'|'native'] for location files containing 3-D cartesian electrode
%                  coordinates, import either in EEGLAB format (nose pointing toward +X).
%                  This may not always be possible since EEGLAB might not be able to
%                  determine the nose direction for scanned electrode files. 'native' import
%                  original cartesian coordinates (user can then specify the position of
%                  the nose when calling the TOPOPLOT function; in EEGLAB the position
%                  of the nose is stored in the EEG.chaninfo structure). {default 'eeglab'}
%   'format'    -  [cell array] Format of a 'custom' channel location file (see above).
%                  {default: if no file type is defined. The cell array contains
%                  labels defining the meaning of each column of the input file.
%                           'channum'   [positive integer] channel number.
%                           'labels'    [string] channel name (no spaces).
%                           'theta'     [real degrees] 2-D angle in polar coordinates.
%                                       positive => rotating from nose (0) toward left ear
%                           'radius'    [real] radius for 2-D polar coords; 0.5 is the head
%                                       disk radius and limit for TOPOPLOT plotting).
%                           'X'         [real] Matlab-Cartesian X coordinate (to nose).
%                           'Y'         [real] Matlab-Cartesian Y coordinate (to left ear).
%                           'Z'         [real] Matlab-Cartesian Z coordinate (to vertex).
%                           '-X','-Y','-Z' Matlab-Cartesian coordinates pointing opposite
%                                       to the above.
%                           'sph_theta' [real degrees] Matlab spherical horizontal angle.
%                                       positive => rotating from nose (0) toward left ear.
%                           'sph_phi'   [real degrees] Matlab spherical elevation angle.
%                                       positive => rotating from horizontal (0) upwards.
%                           'sph_radius' [real] distance from head center (unused).
%                           'sph_phi_besa' [real degrees] BESA phi angle from vertical.
%                                       positive => rotating from vertex (0) towards right ear.
%                           'sph_theta_besa' [real degrees] BESA theta horiz/azimuthal angle.
%                                       positive => rotating from right ear (0) toward nose.
%                           'ignore'    ignore column}.
%     The input file may also contain other channel information fields.
%                           'type'      channel type: 'EEG', 'MEG', 'EMG', 'ECG', others ...
%                           'calib'     [real near 1.0] channel calibration value.
%                           'gain'      [real > 1] channel gain.
%                           'custom1'   custom field #1.
%                           'custom2', 'custom3', 'custom4', etc.    more custom fields
%   'skiplines' - [integer] Number of header lines to skip (in 'custom' file types only).
%                 Note: Characters on a line following '%' will be treated as comments.
%   'readchans' - [integer array] indices of electrodes to read. {default: all}
%   'center'    - [(1,3) real array or 'auto'] center of xyz coordinates for conversion
%                 to spherical or polar, Specify the center of the sphere here, or 'auto'.
%                 This uses the center of the sphere that best fits all the electrode
%                 locations read. {default: [0 0 0]}. [Deprecated]
% Outputs:
%   eloc        - structure containing the channel names and locations (if present).
%                 It has three fields: 'eloc.labels', 'eloc.theta' and 'eloc.radius'
%                 identical in meaning to the EEGLAB struct 'EEG.chanlocs'.
%   labels      - cell array of strings giving the names of the electrodes. NOTE: Unlike the
%                 three outputs below, includes labels of channels *without* location info.
%   theta       - vector (in degrees) of polar angles of the electrode locations.
%   radius      - vector of polar-coordinate radii (arc_lengths) of the electrode locations
%   indices     - indices, k, of channels with non-empty 'locs(k).theta' coordinate
%
% File formats:
%   If 'filetype' is unspecified, the file extension determines its type.
%
%   '.loc' or '.locs' or '.eloc':
%               polar coordinates. Notes: angles in degrees:
%               right ear is 90; left ear -90; head disk radius is 0.5.
%               Fields:   N    angle  radius    label
%               Sample:   1    -18    .511       Fp1
%                         2     18    .511       Fp2
%                         3    -90    .256       C3
%                         4     90    .256       C4
%                           ...
%               Note: In previous releases, channel labels had to contain exactly
%               four characters (spaces replaced by '.'). This format still works,
%               though dots are no longer required.
%   '.sph':
%               Matlab spherical coordinates. Notes: theta is the azimuthal/horizontal angle
%               in deg.: 0 is toward nose, 90 rotated to left ear. Following this, performs
%               the elevation (phi). Angles in degrees.
%               Fields:   N    theta    phi    label
%               Sample:   1      18     -2      Fp1
%                         2     -18     -2      Fp2
%                         3      90     44      C3
%                         4     -90     44      C4
%                           ...
%   '.elc':
%               Cartesian 3-D electrode coordinates scanned using the EETrak software.
%               See READEETRAKLOCS.
%   '.elp':
%               Polhemus-.'elp' Cartesian coordinates. By default, an .elp extension is read
%               as PolhemusX-elp in which 'X' on the Polhemus sensor is pointed toward the
%               subject. Polhemus files are not in columnar format (see READELP).
%   '.elp':
%               BESA-'.elp' spherical coordinates: Need to specify 'filetype','besa'.
%               The elevation angle (phi) is measured from the vertical axis. Positive
%               rotation is toward right ear. Next, perform azimuthal/horizontal rotation
%               (theta): 0 is toward right ear; 90 is toward nose, -90 toward occiput.
%               Angles are in degrees.  If labels are absent or weights are given in
%               a last column, READLOCS adjusts for this. Default labels are E1, E2, ...
%               Fields:   Type  label      phi  theta
%               Sample:   EEG   Fp1        -92   -72
%                         EEG   Fp2         92    72
%                         EEG   C3         -46    0
%                         EEG   C4          46    0
%                           ...
%   '.xyz':
%               Matlab/EEGLAB Cartesian coordinates. Here. x is towards the nose,
%               y is towards the left ear, and z towards the vertex. Note that the first
%               column (x) is -Y in a Matlab 3-D plot, the second column (y) is X in a
%               matlab 3-D plot, and the third column (z) is Z.
%               Fields:   channum   x           y         z     label
%               Sample:   1       .950        .308     -.035     Fp1
%                         2       .950       -.308     -.035     Fp2
%                         3        0           .719      .695    C3
%                         4        0          -.719      .695    C4
%                           ...
%   '.asc', '.dat':
%               Neuroscan-.'asc' or '.dat' Cartesian polar coordinates text file.
%   '.mat':
%               Brainstrom or fieldtrip channel location/layout file.
%   '.lay':
%               Fieldtrip layout file.
%   '.txt':
%               Fieldtrip electore file.
%               Fields:   label      phi  theta
%               Sample:   Fp1        -92   -72
%                         Fp2         92    72
%                         C3         -46    0
%                         C4          46    0
%   '.sfp':
%               BESA/EGI-xyz Cartesian coordinates. Notes: For EGI, x is toward right ear,
%               y is toward the nose, z is toward the vertex. EEGLAB converts EGI
%               Cartesian coordinates to Matlab/EEGLAB xyz coordinates.
%               Fields:   label   x           y          z
%               Sample:   Fp1    -.308        .950      -.035
%                         Fp2     .308        .950      -.035
%                         C3     -.719        0          .695
%                         C4      .719        0          .695
%                           ...
%   '.ced':
%               ASCII file saved by POP_CHANEDIT. Contains multiple MATLAB/EEGLAB formats.
%               Cartesian coordinates are as in the 'xyz' format (above).
%               Fields:   channum  label  theta  radius   x      y      z    sph_theta   sph_phi  ...
%               Sample:   1        Fp1     -18    .511   .950   .308  -.035   18         -2       ...
%                         2        Fp2      18    .511   .950  -.308  -.035  -18         -2       ...
%                         3        C3      -90    .256   0      .719   .695   90         44       ...
%                         4        C4       90    .256   0     -.719   .695  -90         44       ...
%                           ...
%               The last columns of the file may contain any other defined fields (gain,
%               calib, type, custom).
%
%    Fieldtrip structure:
%               If a Fieltrip structure is given as input, an EEGLAB
%               chanlocs structure is returned
%    Brainstrom Matlab file:
%               If a Brainstrom Matlab file is given as input, an EEGLAB
%               chanlocs structure is returned
%
% Author: Arnaud Delorme, Salk Institute, 8 Dec 2002
%
% See also: READELP, WRITELOCS, TOPO2SPH, SPH2TOPO, SPH2CART

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

function [eloc, labels, theta, radius, indices] = readlocs( filename, varargin );

if nargin < 1
	help readlocs;
	return;
end

% NOTE: To add a new channel format:
% ----------------------------------
% 1) Add a new element to the structure 'chanformat' (see 'ADD NEW FORMATS HERE' below):
% 2)  Enter a format 'type' for the new file format,
% 3)  Enter a (short) 'typestring' description of the format
% 4)  Enter a longer format 'description' (possibly multiline, see ex. (1) below)
% 5)  Enter format file column labels in the 'importformat' field (see ex. (2) below)
% 6)  Enter the number of header lines to skip (if any) in the 'skipline' field
% 7)  Document the new channel format in the help message above.
% 8)  After testing, please send the new version of readloca.m to us
%       at eeglab@sccn.ucsd.edu with a sample locs file.
% The 'chanformat' structure is also used (automatically) by the WRITELOCS
% and POP_READLOCS functions. You do not need to edit these functions.

chanformat(1).type         = 'polhemus';
chanformat(1).typestring   = 'Polhemus native .elp file';
chanformat(1).description  = [ 'Polhemus native coordinate file containing scanned electrode positions. ' ...
                               'User must select the direction ' ...
                               'for the nose after importing the data file.' ];
chanformat(1).importformat = 'readelp() function';
% ---------------------------------------------------------------------------------------------------
chanformat(2).type         = 'besa';
chanformat(2).typestring   = 'BESA spherical .elp file';
chanformat(2).description  = [ 'BESA spherical coordinate file. Note that BESA spherical coordinates ' ...
                               'are different from Matlab spherical coordinates' ];
chanformat(2).skipline     = 0; % some BESA files do not have headers
chanformat(2).importformat = { 'type' 'labels' 'sph_theta_besa' 'sph_phi_besa' 'sph_radius' };
% ---------------------------------------------------------------------------------------------------
chanformat(3).type         = 'xyz';
chanformat(3).typestring   = 'Matlab .xyz file';
chanformat(3).description  = [ 'Standard 3-D cartesian coordinate files with electrode numbers in ' ...
                               'the first column and X, Y, and Z coordinates in columns 2, 3, and 4' ...
                               ' and channel labels in column 5' ];
chanformat(3).importformat = { 'channum' '-Y' 'X' 'Z' 'labels'};
% ---------------------------------------------------------------------------------------------------
chanformat(4).type         = 'sfp';
chanformat(4).typestring   = 'BESA or EGI 3-D cartesian .sfp file';
chanformat(4).description  = [ 'Standard BESA 3-D cartesian coordinate files with electrode labels in ' ...
                               'the first column and X, Y, and Z coordinates in columns 2, 3, and 4.' ...
                               'Coordinates are re-oriented to fit the EEGLAB standard of having the ' ...
                               'nose along the +X axis.' ];
chanformat(4).importformat = { 'labels' '-Y' 'X' 'Z' };
chanformat(4).skipline     = 0;
% ---------------------------------------------------------------------------------------------------
chanformat(5).type         = 'loc';
chanformat(5).typestring   = 'EEGLAB polar .loc file';
chanformat(5).description  = [ 'EEGLAB polar .loc file' ];
chanformat(5).importformat = { 'channum' 'theta' 'radius' 'labels' };
% ---------------------------------------------------------------------------------------------------
chanformat(6).type         = 'sph';
chanformat(6).typestring   = 'Matlab .sph spherical file';
chanformat(6).description  = [ 'Standard 3-D spherical coordinate files in Matlab format' ];
chanformat(6).importformat = { 'channum' 'sph_theta' 'sph_phi' 'labels' };
% ---------------------------------------------------------------------------------------------------
chanformat(7).type         = 'asc';
chanformat(7).typestring   = 'Neuroscan polar .asc file';
chanformat(7).description  = [ 'Neuroscan polar .asc file, automatically recentered to fit EEGLAB standard' ...
                               'of having ''Cz'' at (0,0).' ];
chanformat(7).importformat = 'readneurolocs';
% ---------------------------------------------------------------------------------------------------
chanformat(8).type         = 'dat';
chanformat(8).typestring   = 'Neuroscan 3-D .dat file';
chanformat(8).description  = [ 'Neuroscan 3-D cartesian .dat file. Coordinates are re-oriented to fit ' ...
                               'the EEGLAB standard of having the nose along the +X axis.' ];
chanformat(8).importformat = 'readneurodat';
% ---------------------------------------------------------------------------------------------------
chanformat(9).type         = 'elc';
chanformat(9).typestring   = 'ASA .elc 3-D file';
chanformat(9).description  = [ 'ASA .elc 3-D coordinate file containing scanned electrode positions. ' ...
                               'User must select the direction ' ...
                               'for the nose after importing the data file.' ];
chanformat(9).importformat = 'readeetraklocs';
% ---------------------------------------------------------------------------------------------------
chanformat(10).type         = 'chanedit';
chanformat(10).typestring   = 'EEGLAB complete 3-D file';
chanformat(10).description  = [ 'EEGLAB file containing polar, cartesian 3-D, and spherical 3-D ' ...
                               'electrode locations.' ];
chanformat(10).importformat = { 'channum' 'labels'  'theta' 'radius' 'X' 'Y' 'Z' 'sph_theta' 'sph_phi' ...
                               'sph_radius' 'type' };
chanformat(10).skipline     = 1;
% ---------------------------------------------------------------------------------------------------
chanformat(11).type         = 'tsv';
chanformat(11).typestring   = 'BIDS .tsv file';
chanformat(11).description  = [ 'Standard 3-D cartesian coordinate files with electrode labels in ' ...
                               'the first column and X, Y, and Z coordinates in columns 2, 3, and 4' ];
chanformat(11).importformat = { 'labels' 'X' 'Y' 'Z' };
chanformat(11).skipline     = 1;
% ---------------------------------------------------------------------------------------------------
chanformat(12).type         = 'mat';
chanformat(12).typestring   = 'Brainstorm Matlab file format';
chanformat(12).description  = 'Custom Matlab file.';
chanformat(12).importformat = '';
% ---------------------------------------------------------------------------------------------------
chanformat(13).type         = 'lay';
chanformat(13).typestring   = 'Fieldtrip layout file';
chanformat(13).description  = 'Fieldtrip layout file';
chanformat(13).importformat = '';
% ---------------------------------------------------------------------------------------------------
chanformat(14).type         = 'txt';
chanformat(14).typestring   = 'Fieldtrip .txt spherical file';
chanformat(14).description  = [ 'Standard 3-D spherical coordinate files in text format' ];
chanformat(14).importformat = { 'labels' 'sph_theta_besa' 'sph_phi_besa' };
% ---------------------------------------------------------------------------------------------------
chanformat(15).type         = 'custom';
chanformat(15).typestring   = 'Custom file format';
chanformat(15).description  = 'Custom ASCII file format where user can define content for each file columns.';
chanformat(15).importformat = '';
% ---------------------------------------------------------------------------------------------------
% ----- ADD MORE FORMATS HERE -----------------------------------------------------------------------
% ---------------------------------------------------------------------------------------------------

listcolformat = { 'labels' 'channum' 'theta' 'radius' 'sph_theta' 'sph_phi' ...
      'sph_radius' 'sph_theta_besa' 'sph_phi_besa' 'gain' 'calib' 'type' ...
      'X' 'Y' 'Z' '-X' '-Y' '-Z' 'custom1' 'custom2' 'custom3' 'custom4' 'ignore' 'not def' };

% ----------------------------------
% special mode for getting the info
% ----------------------------------
if ischar(filename) && strcmp(filename, 'getinfos')
   eloc = chanformat;
   labels = listcolformat;
   return;
end

g = finputcheck( varargin, ...
   { 'filetype'	   'string'  {}                 '';
     'importmode'  'string'  { 'eeglab','native' } 'eeglab';
     'defaultelp'  'string'  { 'besa','polhemus' } 'polhemus';
     'skiplines'   'integer' [0 Inf] 			[];
     'elecind'     'integer' [1 Inf]	    	[];
     'format'	   'cell'	 []					{} }, 'readlocs');
if ischar(g), error(g); end
if ~isempty(g.format), g.filetype = 'custom'; end

if ischar(filename)

   % format auto detection
	% --------------------
   if strcmpi(g.filetype, 'autodetect'), g.filetype = ''; end
   g.filetype = strtok(g.filetype);
   [~,~,fileextension] = fileparts(filename);
   fileextension = fileextension(2:end);
   g.filetype = lower(g.filetype);
   if isempty(g.filetype)
       switch lower(fileextension)
        case {'loc' 'locs' 'eloc'}, g.filetype = 'loc'; % 5/27/2014 Ramon: 'eloc' option introduced.
        case 'xyz', g.filetype = 'xyz';
          fprintf( [ 'WARNING: Matlab Cartesian coord. file extension (".xyz") detected.\n' ...
                  'If importing EGI Cartesian coords, force type "sfp" instead.\n'] );
        case 'sph', g.filetype = 'sph';
        case 'ced', g.filetype = 'chanedit';
        case 'elp', g.filetype = g.defaultelp;
        case 'asc', g.filetype = 'asc';
        case 'dat', g.filetype = 'dat';
        case 'elc', g.filetype = 'elc';
        case 'eps', g.filetype = 'besa';
        case 'txt', g.filetype = 'txt';
        case 'sfp', g.filetype = 'sfp';
        case 'tsv', g.filetype = 'tsv';
        case 'mat', g.filetype = 'mat';
        case 'lay', g.filetype = 'lay';
        otherwise, g.filetype =  '';
       end
       fprintf('readlocs(): ''%s'' format assumed from file extension\n', g.filetype);
   else
       if strcmpi(g.filetype, 'locs'),  g.filetype = 'loc'; end
       if strcmpi(g.filetype, 'eloc'),  g.filetype = 'loc'; end
   end

   % assign format from filetype
   % ---------------------------
   if ~isempty(g.filetype) && ~strcmpi(g.filetype, 'custom') ...
           & ~strcmpi(g.filetype, 'asc') & ~strcmpi(g.filetype, 'elc') & ~strcmpi(g.filetype, 'dat')
      indexformat = strmatch(lower(g.filetype), { chanformat.type }, 'exact');
      g.format = chanformat(indexformat).importformat;
      if isempty(g.skiplines)
         g.skiplines = chanformat(indexformat).skipline;
      end
      if isempty(g.filetype)
         error( ['readlocs() error: The filetype cannot be detected from the \n' ...
                 '                  file extension, and custom format not specified']);
      end
   end

   % import file
   % -----------
   if strcmp(g.filetype, 'mat')
       elocIn = load('-mat', filename );
       if isfield(elocIn, 'Channel')
           % brainstorm file
           for iChan = 1:length(elocIn.Channel)
               eloc(iChan).labels = elocIn.Channel(iChan).Name;
               eloc(iChan).X      = elocIn.Channel(iChan).Loc(1);
               eloc(iChan).Y      = elocIn.Channel(iChan).Loc(2);
               eloc(iChan).Z      = elocIn.Channel(iChan).Loc(3);
               eloc(iChan).type   = elocIn.Channel(iChan).Type;
           end
           if isfield(elocBrainstrom, 'SCS')
               chans = { 'NAS' 'LPA' 'RPA' };
               for iChan = 1:length(chans)
                   if isfield(elocIn.SCS, chans{iChan})
                       eloc(end+1).labels = chans{iChan};
                       eloc(end).X      = elocIn.SCS.(chans{iChan})(1);
                       eloc(end).Y      = elocIn.SCS.(chans{iChan})(2);
                       eloc(end).Z      = elocIn.SCS.(chans{iChan})(3);
                       eloc(end).type   = elocIn.Channel(iChan).Type;
                   end
               end
           end
       else
           % fieldtrip layout file
           fprintf(2, 'Warning: You are a 2-D Layout file, do not use channel coordinates for source localization\n');
           if isfield(elocIn, 'layout') && ~isfield(elocIn, 'lay')
               elocIn.lay = elocIn.layout;
           end
           if any(elocIn.lay.pos(:,1) > 700)
               elocIn.lay.pos = (elocIn.lay.pos - 400)/800;
           elseif any(elocIn.lay.pos(:,1) > 400)
               elocIn.lay.pos = (elocIn.lay.pos - 250)/500;
           end
           radius = sqrt(elocIn.lay.pos(:,1).^2 + elocIn.lay.pos(:,2).^2);
           theta  = atan2d(elocIn.lay.pos(:,1), elocIn.lay.pos(:,2));
           for iChan = 1:length(elocIn.lay.label)
               eloc(iChan).labels = elocIn.lay.label{iChan};
               eloc(iChan).theta  = theta(iChan);
               eloc(iChan).radius = radius(iChan);
           end
       end
   elseif strcmp(g.filetype, 'lay')
       layout = readtable(filename, 'filetype', 'text');
       fprintf(2, 'Warning: You are a 2-D Layout file, do not use channel coordinates for source localization\n');
       radius = sqrt([layout{:,2}].^2 + [layout{:,3}].^2);
       theta  = atan2d([layout{:,2}], [layout{:,3}]);
       for iChan = 1:length(radius)
           eloc(iChan).labels = layout{iChan,1};
           if isnumeric(eloc(iChan).labels) eloc(iChan).labels = num2str(eloc(iChan).labels); end
           eloc(iChan).theta  = theta(iChan);
           eloc(iChan).radius = radius(iChan);
       end
   elseif strcmp(g.filetype, 'asc') || strcmp(g.filetype, 'dat')
       eloc = readneurolocs( filename );
       if isfield(eloc, 'type')
           for index = 1:length(eloc)
               eloc(index).labels = strtrim(eloc(index).labels);
               type = eloc(index).type;
               if ~ischar(type) && ~isempty(type)
                   if type == 69,     eloc(index).type = 'EEG';
                   elseif type == 88, eloc(index).type = 'REF';
                   elseif type >= 76 && type <= 82, eloc(index).type = 'FID';
                   else eloc(index).type = num2str(eloc(index).type);
                   end
               end
           end
       end
   elseif strcmp(g.filetype, 'txt')
       elocTmp = readtable(filename, 'filetype', 'text');
       for iChan = 1:size(elocTmp,1)
           eloc(iChan).labels = elocTmp{iChan,1};
           if isnumeric(eloc(iChan).labels) eloc(iChan).labels = num2str(eloc(iChan).labels); end
           if iscell(   eloc(iChan).labels) eloc(iChan).labels = eloc(iChan).labels{1}; end
           eloc(iChan).sph_theta_besa = elocTmp{iChan,2};
           eloc(iChan).sph_phi_besa  = elocTmp{iChan,3};
       end
       eloc = convertlocs(eloc, 'sphbesa2all');
       eloc = rmfield(eloc, 'sph_theta'); % for the conversion below
       eloc = rmfield(eloc, 'sph_theta_besa'); % for the conversion below
   elseif strcmp(g.filetype, 'elc')
       eloc = readeetraklocs( filename );
       eloc = convertlocs(eloc, 'cart2all');
       eloc = rmfield(eloc, 'sph_theta'); % for the conversion below
       eloc = rmfield(eloc, 'sph_theta_besa'); % for the conversion below
       eloc = convertlocs(eloc, 'cart2all');
       eloc = rmfield(eloc, 'sph_theta'); % for the conversion below
       eloc = rmfield(eloc, 'sph_theta_besa'); % for the conversion below
   elseif strcmp(lower(g.filetype(1:end-1)), 'polhemus') || ...
           strcmp(g.filetype, 'polhemus')
       try,
           [eloc labels X Y Z]= readelp( filename );
           if strcmp(g.filetype, 'polhemusy')
               tmp = X; X = Y; Y = tmp;
           end
           for index = 1:length( eloc )
               eloc(index).X = X(index);
               eloc(index).Y = Y(index);
               eloc(index).Z = Z(index);
           end
       catch,
           disp('readlocs(): Could not read Polhemus coords. Trying to read BESA .elp file.');
           [eloc, labels, theta, radius, indices] = readlocs( filename, 'defaultelp', 'besa', varargin{:} );
       end
   else
       % importing file
       % --------------
       if isempty(g.skiplines), g.skiplines = 0; end
       if strcmpi(g.filetype, 'chanedit')
           array = loadtxt( filename, 'delim', 9, 'skipline', g.skiplines, 'blankcell', 'off');
       else
           array = load_file_or_array( filename, g.skiplines);
       end
       if size(array,2) < length(g.format)
           fprintf(['readlocs() warning: Fewer columns in the input than expected.\n' ...
                    '                    See >> help readlocs\n']);
       elseif size(array,2) > length(g.format)
           fprintf(['readlocs() warning: More columns in the input than expected.\n' ...
                    '                    See >> help readlocs\n']);
       end

       % removing lines BESA
       % -------------------
       if isempty(array{1,2})
           disp('BESA header detected, skipping three lines...');
           array = load_file_or_array( filename, g.skiplines-1);
           if isempty(array{1,2})
               array = load_file_or_array( filename, g.skiplines-1);
           end
       end

       % xyz format, is the first col absent
       % -----------------------------------
       if strcmp(g.filetype, 'xyz')
           if size(array, 2) == 4
               array(:, 2:5) = array(:, 1:4);
           end
       end

       % removing comments and empty lines
       % ---------------------------------
       indexbeg = 1;
       while isempty(array{indexbeg,1}) || ...
               (ischar(array{indexbeg,1}) && array{indexbeg,1}(1) == '%' )
           indexbeg = indexbeg+1;
       end
       array = array(indexbeg:end,:);

       % converting file
       % ---------------
       for indexcol = 1:min(size(array,2), length(g.format))
           [str, mult] = checkformat(g.format{indexcol});
           for indexrow = 1:size( array, 1)
               if mult ~= 1
                   eval ( [ 'eloc(indexrow).'  str '= -array{indexrow, indexcol};' ]);
               else
                   eval ( [ 'eloc(indexrow).'  str '= array{indexrow, indexcol};' ]);
               end
           end
       end
   end

   % handling BESA coordinates
   % -------------------------
   if isfield(eloc, 'sph_theta_besa')
       if isfield(eloc, 'type')
           if isnumeric(eloc(1).type)
               disp('BESA format detected ( Theta | Phi )');
               for index = 1:length(eloc)
                   eloc(index).sph_phi_besa   = eloc(index).labels;
                   eloc(index).sph_theta_besa = eloc(index).type;
                   eloc(index).labels         = '';
                   eloc(index).type           = '';
               end
               eloc = rmfield(eloc, 'labels');
           end
       end
       if isfield(eloc, 'labels')
           if isnumeric(eloc(1).labels)
               disp('BESA format detected ( Elec | Theta | Phi )');
               for index = 1:length(eloc)
                   eloc(index).sph_phi_besa   = eloc(index).sph_theta_besa;
                   eloc(index).sph_theta_besa = eloc(index).labels;
                   eloc(index).labels         = eloc(index).type;
                   eloc(index).type           = '';
                   eloc(index).radius         = 1;
               end
           end
       end

       try
           eloc = convertlocs(eloc, 'sphbesa2all');
           eloc = convertlocs(eloc, 'topo2all'); % problem with some EGI files (not BESA files)
       catch, disp('Warning: coordinate conversion failed'); end
       fprintf('Readlocs: BESA spherical coords. converted, now deleting BESA fields\n');
       fprintf('          to avoid confusion (these fields can be exported, though)\n');
       eloc = rmfield(eloc, 'sph_phi_besa');
       eloc = rmfield(eloc, 'sph_theta_besa');

       % converting XYZ coordinates to polar
       % -----------------------------------
   elseif isfield(eloc, 'sph_theta') && any(~cellfun(@isempty, { eloc.sph_theta }))
       try
           eloc = convertlocs(eloc, 'sph2all');
       catch, disp('Warning: coordinate conversion failed'); end
   elseif isfield(eloc, 'X')
       try
           eloc = convertlocs(eloc, 'cart2all');
       catch, disp('Warning: coordinate conversion failed'); end
   else
       try
           eloc = convertlocs(eloc, 'topo2all');
       catch, disp('Warning: coordinate conversion failed'); end
   end

   % inserting labels if no labels
   % -----------------------------
   if ~isfield(eloc, 'labels')
       fprintf('readlocs(): Inserting electrode labels automatically.\n');
       for index = 1:length(eloc)
           eloc(index).labels = [ 'E' int2str(index) ];
       end
   else
       % remove trailing '.'
       for index = 1:length(eloc)
           if ischar(eloc(index).labels)
               tmpdots = find( eloc(index).labels == '.' );
               eloc(index).labels(tmpdots) = [];
           end
       end
   end

   % resorting electrodes if number not-sorted
   % -----------------------------------------
   if isfield(eloc, 'channum')
       if ~isnumeric(eloc(1).channum)
           error('Channel numbers must be numeric');
       end
       allchannum = [ eloc.channum ];
       if any( sort(allchannum) ~= allchannum )
           fprintf('readlocs(): Re-sorting channel numbers based on ''channum'' column indices\n');
           [tmp newindices] = sort(allchannum);
           eloc = eloc(newindices);
       end
       eloc = rmfield(eloc, 'channum');
   end
else
    if isstruct(filename)
        % detect Fieldtrip structure and convert it
        % -----------------------------------------
        if isfield(filename, 'pnt')
            neweloc = [];
            for index = 1:length(filename.label)
                neweloc(index).labels = filename.label{index};
                neweloc(index).X      = filename.pnt(index,1);
                neweloc(index).Y      = filename.pnt(index,2);
                neweloc(index).Z      = filename.pnt(index,3);
            end
            eloc = neweloc;
            eloc = convertlocs(eloc, 'cart2all');
        else
            eloc = filename;
        end
    else
        disp('readlocs(): input variable must be a string or a structure');
    end;
end
if ~isempty(g.elecind)
	eloc = eloc(g.elecind);
end
if nargout > 2
    if isfield(eloc, 'theta')
         tmptheta = { eloc.theta }; % check which channels have (polar) coordinates set
    else tmptheta = cell(1,length(eloc));
    end
    if isfield(eloc, 'theta')
         tmpx = { eloc.X }; % check which channels have (polar) coordinates set
    else tmpx = cell(1,length(eloc));
    end

    indices           = find(~cellfun('isempty', tmptheta));
    indices           = intersect_bc(find(~cellfun('isempty', tmpx)), indices);
    indices           = sort(indices);

    indbad            = setdiff_bc(1:length(eloc), indices);
    tmptheta(indbad)  = { NaN };
    theta             = [ tmptheta{:} ];
end
if nargout > 3
    if isfield(eloc, 'theta')
         tmprad = { eloc.radius }; % check which channels have (polar) coordinates set
    else tmprad = cell(1,length(eloc));
    end
    tmprad(indbad)    = { NaN };
    radius            = [ tmprad{:} ];
end

%tmpnum = find(~cellfun('isclass', { eloc.labels }, 'char'));
%disp('Converting channel labels to string');
for index = 1:length(eloc)
    if ~ischar(eloc(index).labels)
        eloc(index).labels = int2str(eloc(index).labels);
    end
end
labels = { eloc.labels };
if isfield(eloc, 'ignore')
    eloc = rmfield(eloc, 'ignore');
end

% process fiducials if any
% ------------------------
fidnames = { 'nz' 'lpa' 'rpa' 'nasion' 'left' 'right' 'nazion' 'fidnz' 'fidt9' 'fidt10' 'cms' 'drl' 'nas' 'lht' 'rht' 'lhj' 'rhj' };
for index = 1:length(fidnames)
    ind = strmatch(fidnames{index}, lower(labels), 'exact');
    if ~isempty(ind), for iInd = 1:length(ind) eloc(ind(iInd)).type = 'FID'; end; end
end

return;

% interpret the variable name
% ---------------------------
function array = load_file_or_array( varname, skiplines );
	 if isempty(skiplines),
       skiplines = 0;
    end
    if exist( varname ) == 2
        array = loadtxt(varname,'verbose','off','skipline',skiplines,'blankcell','off');
    else % variable in the global workspace
         % --------------------------
         try, array = evalin('base', varname);
	     catch, error('readlocs(): cannot find the named file or variable, check syntax');
		 end
    end;
return;

% check field format
% ------------------
function [str, mult] = checkformat(str)
	mult = 1;
	if strcmpi(str, 'labels'),         str = lower(str); return; end
	if strcmpi(str, 'channum'),        str = lower(str); return; end
	if strcmpi(str, 'theta'),          str = lower(str); return; end
	if strcmpi(str, 'radius'),         str = lower(str); return; end
	if strcmpi(str, 'ignore'),         str = lower(str); return; end
	if strcmpi(str, 'sph_theta'),      str = lower(str); return; end
	if strcmpi(str, 'sph_phi'),        str = lower(str); return; end
	if strcmpi(str, 'sph_radius'),     str = lower(str); return; end
	if strcmpi(str, 'sph_theta_besa'), str = lower(str); return; end
	if strcmpi(str, 'sph_phi_besa'),   str = lower(str); return; end
	if strcmpi(str, 'gain'),           str = lower(str); return; end
	if strcmpi(str, 'calib'),          str = lower(str); return; end
	if strcmpi(str, 'type') ,          str = lower(str); return; end
	if strcmpi(str, 'X'),              str = upper(str); return; end
	if strcmpi(str, 'Y'),              str = upper(str); return; end
	if strcmpi(str, 'Z'),              str = upper(str); return; end
	if strcmpi(str, '-X'),             str = upper(str(2:end)); mult = -1; return; end
	if strcmpi(str, '-Y'),             str = upper(str(2:end)); mult = -1; return; end
	if strcmpi(str, '-Z'),             str = upper(str(2:end)); mult = -1; return; end
	if strcmpi(str, 'custom1'), return; end
	if strcmpi(str, 'custom2'), return; end
	if strcmpi(str, 'custom3'), return; end
	if strcmpi(str, 'custom4'), return; end
    error(['readlocs(): undefined field ''' str '''']);


%% t_meshCurvature
%
% Use tricurve_v01 to calculate curvature of a mesh
%
%

%% Load the class file.  A sphere is 1 and everything else 0
fName = fullfile(mrvDataRootPath,'anatomy','harmonic.nii.gz');
niClass = niftiRead(fName);
% showMontage(niClass.data)

%% Use Matlab to build the faces and edges
fv = isosurface(niClass.data,0.9);
smoothMode = 1; nIter = 5;
fv = smoothpatch(fv,smoothMode,nIter);
% This was suggested by Peyre.  It may work in the end.  But it takes time,
% as well, so I may as well stick with the tricurv_v01 for now.
%
% options.method = 'slow';
% fv.faces = perform_faces_reorientation(fv.vertices,fv.faces,options)';

%% One solution.  Slow, but this is the one used in meshFV2msh.m
% curvature1 = tricurv_v01(fv.faces,fv.vertices);

%% A second solution is much faster.  But it fails a lot.

% I will probably remove it from meshFV2msh.m  But there is an interesting
% exchange about it with Peyre.  See email and notes.
%
%   Umin is the direction of minimum curvature
%   Umax is the direction of maximum curvature
%   Cmin is the minimum curvature
%   Cmax is the maximum curvature
%   Cmean=(Cmin+Cmax)/2
%   Cgauss=Cmin*Cmax
%   Normal is the normal to the surface

% BUT, this routine fails a lot.  I wrote the authors.  I put a try/catch
% around it in meshFV2msh.m
% tic
% [Umin,Umax,Cmin,Cmax,Cmean,Cgauss,Normal] = ...
%     compute_curvature(fv.vertices,fv.faces);
% toc

%% Convert the fv mesh to a vistasoft mesh

msh = meshFV2msh(fv);
meshVisualize(msh);

%% End


function spm_MDP_da(MDP)
% Simulated histograms of dopamine firing
% FORMAT spm_MDP_da(MDP)
%
% See also: spm_MDP_game, which generalises this scheme and replaces prior
% beliefs about KL control with minimisation of expected free energy.
%__________________________________________________________________________
% Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_MDP_da.m 6451 2015-05-26 09:26:03Z karl $

% deconvolve to simulate dopamine responses
%--------------------------------------------------------------------------
wn   = MDP.d;
da   = pinv( tril(toeplitz(exp(-((1:length(wn)) - 1)'/8))) )*wn;
da   = da(4:end);

% peristimulus time histogram
%--------------------------------------------------------------------------
pst  = (1:length(da))*256;
r    = 256;
psth = r*da + randn(size(da)).*sqrt(r*da);
bar(pst,psth,1)
title('Simulated dopamine responses','FontSize',16)
xlabel('Peristimulus time (ms)','FontSize',12)
ylabel('Spikes per bin','FontSize',12)
axis([pst(1) pst(end) 0 max(psth)*(1 + 1/4)])
axis square


function d = det(A)
    % Symbolic matrix determinant.
    %   DET(A) is the determinant of the symbolic matrix A.
    %
    %   Examples:
    %       det([a b;c d]) is a*d-b*c.

    % Convert inputs to SymExpression
    % A = SymExpression(A);

    % check if A is a square matrix
    ret = eval_math(['SquareMatrixQ[' A.s ']']);

    if strcmp('False',ret)
        error(message('symbolic:det:SquareMatrix'));
    end

    % construct the operation string
    sstr = ['Det[' A.s ']'];

    % create a new object with the evaluated string
    d = SymExpression(sstr);
end


function parameters = cohenimcra_estimation(ns_ps,parameters);
%         parameters = struct('n',2,'len',len_val,'noise_cap',ns_ps,'noise_tild',ns_ps,'gamma',ones(len_val,1),'Sf',Sf_val,...
%             'Smin',Sf_val,'S',Sf_val,'S_tild',Sf_val,'GH1',ones(len_val,1),'Smin_tild',Sf_val,'Smin_sw',Sf_val,'Smin_sw_tild',Sf_val,...
%             'stored_min',max(ns_ps)*ones(len_val,U_val),'stored_min_tild',max(ns_ps)*ones(len_val,U_val)','u1',1,'u2',1,'j',2,...
%             'alpha_d',0.85,'alpha_s',0.9,'U',8,'V',15,'Bmin',1.66,'gamma0',4.6,'gamma1',3,'psi0',1.67,'alpha',0.92,'beta',1.47,...
%             'b',b_val,'Sf_tild',Sf_tild_val);

n = parameters.n;
len = parameters.len;
gamma0 = parameters.gamma0;
psi0 = parameters.psi0;
alpha = parameters.alpha;
beta = parameters.beta;
b = parameters.b;
U = parameters.U;
V = parameters.V;
Bmin = parameters.Bmin;
gamma = parameters.gamma;
gamma1 = parameters.gamma1;
GH1 = parameters.GH1;
Sf = parameters.Sf;
Smin = parameters.Smin;
S = parameters.S;
S_tild = parameters.S_tild;
Sf_tild = parameters.Sf_tild;
Smin_tild = parameters.Smin_tild;
Smin_sw = parameters.Smin_sw;
Smin_sw_tild = parameters.Smin_sw_tild;
stored_min = parameters.stored_min;
stored_min_tild = parameters.stored_min_tild;
u1 = parameters.u1;
u2 = parameters.u2;
j = parameters.j;
alpha_d = parameters.alpha_d;
alpha_s = parameters.alpha_s;

noise_cap = parameters.noise_ps;
noise_tild = parameters.noise_tild;

gamma_old=gamma;
gamma=ns_ps./noise_cap;                                     %Eq 3 to compute a posteriori SNR
eps_cap=alpha*(GH1.^2).*gamma_old+(1-alpha)*max(gamma-1,0); %Eq 32 to compute a priori SNR
v=gamma.*eps_cap./(1+eps_cap);
exp_int=expint(v); %ei(v);
GH1=eps_cap.*exp(.5*exp_int)./(1+eps_cap);                    %Eq 33 to compute the value of GH1
Sf(1)=ns_ps(1);Sf(end)=ns_ps(end);
for f=2:len-1
    Sf(f)=sum(b.*[ns_ps(f-1); ns_ps(f); ns_ps(f+1)]);
end

S=alpha_s*S+(1-alpha_s)*Sf;                                 %Eq 14 and 15 for computing S(k,l)
Smin=min(Smin,S);Smin_sw=min(Smin_sw,S);
gamma_min=ns_ps./(Bmin*Smin);
psi=S./(Bmin*Smin);                                         %Eq 18 to compute gamma_min  and Psi
I=zeros(len,1);
index=find(gamma_min<gamma0 & psi<psi0);
I(index)=1;                                                 %Eq 21 to compute I(k,l)
for f=2:len-1
    if (I(f-1)+I(f)+I(f+1))==0
        Sf_tild(f)=S_tild(f);
    else
        Sf_tild(f)=sum(b.*[I(f-1); I(f); I(f+1)].*[ns_ps(f-1); ns_ps(f); ns_ps(f+1)])/sum(b.*[I(f-1); I(f); I(f+1)]);
    end                                                                   %Eq 26 for updating Sf_tild
end
if I(1)==0
    Sf_tild(1)=S_tild(1);
    Sf_tild(end)=S_tild(end);
else
    Sf_tild(1)=ns_ps(1);
    Sf_tild(end)=ns_ps(end);
end

S_tild=alpha_s*S_tild+(1-alpha_s)*Sf_tild;                              %Eq 27 for updating S_tild
Smin_tild=min(Smin_tild,S_tild);Smin_sw_tild=min(Smin_sw_tild,S_tild);
gamma_min_tild=ns_ps./(Bmin*Smin_tild);
psi_tild=S./(Bmin*Smin_tild);
q=zeros(len,1);                                                  %Eq 29 to find a priori speech absence probability
index=find(gamma_min_tild<=1 & psi_tild<psi0);
index1=setdiff([1:len],index);
if (~isempty(index))
    q(index)=1;
end
index=find(gamma_min_tild>1 & gamma_min_tild<gamma1 & psi_tild<psi0);
if (~isempty(index))
    q(index)=(gamma1-gamma_min_tild(index))/(gamma1-1);
end
%        p=1./(1+((q./(1-q)).*(1+eps_cap).*exp(-v)));
p=zeros(len,1);
if (~isempty(index1))
    temp1 = q(index1)./(1-q(index1));
    temp2 = 1 + eps_cap(index1);
    temp3 = exp(-v(index1));
    p(index1) = (1 + temp1.*temp2.*temp3).^-1;
end
%             p(index1)=1./(1+((q(index1)./(1-q(index1))).*(1+eps_cap(index1)).*exp(-v(index1))));    %Eq 7 to find conditional speech presence probability
alpha_d_tild=alpha_d+(1-alpha_d)*p;                                 %Eq 11 to update the time and frequency dependent smoothing factor
noise_tild=alpha_d_tild.*noise_tild+(1-alpha_d_tild).*ns_ps;        %Eq 10 to update noise estimate
noise_cap=beta*noise_tild;                                          %Eq 12 to update noise estimate for correction factor
j=j+1;
if j==V

    stored_min(:,u1)=Smin_sw;
    u1=u1+1;if u1==U+1; u1=1;end
    Smin=min(stored_min,[],2);
    Smin_sw=S;
    stored_min_tild(:,u2)=Smin_sw_tild;
    u2=u2+1;if u2==U+1; u2=1;end
    Smin_tild=min(stored_min_tild,[],2);
    Smin_sw_tild=S_tild;
    j=0;
end
ix=find(p>1 | q>1 | p<0 | q<0);
if (~isempty(ix))
    keyboard;
end
noise_ps = noise_cap;

parameters.n = n+1;
parameters.gamma = gamma;
parameters.GH1 = GH1;
parameters.Sf = Sf;
parameters.Smin = Smin;
parameters.S = S;
parameters.S_tild = S_tild;
parameters.Smin_tild = Smin_tild;
parameters.Smin_sw = Smin_sw;
parameters.Smin_sw_tild = Smin_sw_tild;
parameters.stored_min = stored_min;
parameters.stored_min_tild = stored_min_tild;
parameters.u1 = u1;
parameters.u2 = u2;
parameters.j = j;
parameters.noise_tild=noise_tild;
parameters.noise_ps = noise_ps;


function best_acc = FDDL_top(dataset, N_train, k, lambda1, lambda2)
% function FDDL_top(dataset, N_train, k, lambda1, lambda2)
    %% Dependencies
    addpath('utils');
    addpath('LRSDL_FDDL');
    addpath('ODL');
    %% test mode
    if nargin == 0
        dataset = 'myARgender';
        N_train = 350;
        k = 25;
        dataset = 'myYaleB';
        N_train = 10;
        k = 8;
        k0 = 5;
        lambda1 = 0.001;
        lambda2 = 0.05;
    end
    %% get data
    t = getTimeStr();
    [dataset, Y_train, Y_test, label_train, label_test] = train_test_split(...
        dataset, N_train);
    %% main
    [acc, rt] = FDDL_wrapper(Y_train, label_train, Y_test , label_test, ...
                            k, lambda1, lambda2)
    fprintf('rt = %5.1f\n', rt);
    %% output filename
    if ~exist('results', 'dir')
        mkdir('results');
    end
    if ~exist(fullfile('results', 'FDDL'), 'dir')
        mkdir('results', 'FDDL');
    end
    fn = fullfile('results', 'FDDL', strcat(dataset, ...
        '_N_', num2str(N_train), '_k_', num2str(k),'_l1_', ...
        num2str(lambda1), '_l2_', num2str(lambda2),'_', t, '.mat'));
    disp(fn);
    save(fn, 'acc', 'rt');
    best_acc = max(acc);
end


function ijk = points_to_idx(map, xyz)
% convert 3d points xyz (Nx3) into indices in occupancy grid
% @author: Yiren Lu
% @date: 02/13/2017
% @input:   map         map generated by load_map
%           xyz         Nx3 3d points in actual space
% @output:  ijk         Nx3 indices in map's occupancy grid
ijk = ones(size(xyz,1),3);
if size(xyz,1) > 0
ijk(:,1) = min(max(floor((xyz(:,1) - map.boundary(1))/map.xy_res + 1),1), map.nx);
ijk(:,2) = min(max(floor((xyz(:,2) - map.boundary(2))/map.xy_res + 1),1), map.ny);
ijk(:,3) = min(max(floor((xyz(:,3) - map.boundary(3))/map.z_res + 1),1), map.nz);
end
end


function [prediction,  weight,  RF] = rfMakePrediction(params, id);
% rfMakePrediction - makes time-series based on rf-profile and image
% sequence.
%
% [prediction,  weight,  rf] = rfMakePrediction(params, id);
%
% input:
%  params  : parameter struct
%  id      : id for grid search [n] or rf-parameters
%            [sigmaMajor,  sigmaMinor,  sigmaTheta,  x0, 0]
%
%

% 2006/01 SOD: wrote it.
% 2006/03 SOD: vectorized.
% 2006/06 SOD: moved Hrf convolution out of this function to rmMakeStimulus.
% 2007/04 RAS: revert to version 1.15 in repository; this restores the
% making of the RF, based on the id params. It seems that removing that
% part made the function obsolete (it was just a multiplication), and also
% broke the RF visualization code, so for now I'm restoring it.

% Programming note: This function is at the heart of the retinotopy
% model program and will be called lots. It is now vectorized so we
% can make all RFs in advance.

% Make (several) receptive field profiles.
% Ugly input check allowing different kinds of inputs.
if numel(id)==1,
    % if id == 0 then we make all the RFs
    if ~id,
        RF =  rfGaussian2d(params.analysis.X, params.analysis.Y, ...
                            params.analysis.sigmaMajor, ...
                            params.analysis.sigmaMajor, ...
                            0, ...
                            params.analysis.x0,  ...
                            params.analysis.y0);

    else,  % we make just a particular one
        RF =  rfGaussian2d(params.analysis.X, params.analysis.Y, ...
                            params.analysis.sigmaMajor(id), ...
                            params.analysis.sigmaMajor(id), ...
                            0, ...
                            params.analysis.x0(id),  ...
                            params.analysis.y0(id));

    end;

elseif numel(id)==5,
    RF =  rfGaussian2d(params.analysis.X, params.analysis.Y, ...
        id(1), id(2), id(3), id(4), id(5));

else,  % make lots
    RF =  rfGaussian2d(params.analysis.X, params.analysis.Y, ...
        id(:, 1), id(:, 2), id(:, 3), id(:, 4), id(:, 5));
end;

% Now we have to loop over each stimulus to convolve it with the RF. The
% stimulus is already convolved with the Hrf so we don't have to do that
% here,  also removing of initial time frames and time averaging is
% moved to the stimulus creation.
prediction = params.analysis.allstimimages * RF;

% compute the amount within the stimulus window to weight the
% fit
if nargout > 1,
    weight = sum(RF);
end;

return;


function [tSeries] = tSeriesRemoveOutliers(tSeries, baseImage)
%
%

if ~exist('baseImage')
    baseImage = tSeries(1,:,:);
end

nFrames = size(tSeries,1);
nVoxels = size(tSeries,2);
nSlices = size(tSeries,3);

indexes = [];
backup = tSeries;

for curSlice = 1:nSlices

	LSE_ref = tSeries(:,:,curSlice) - repmat(baseImage(:,:,curSlice),[nFrames 1]);
	MSE_ref = sqrt(sum(LSE_ref.^2,2)/(nVoxels));

	mn = mean(MSE_ref);
	sd = std(MSE_ref);

	frame = 1;

	while (frame <= nFrames)

        frameOutlier = frame;
        while (frameOutlier <= nFrames) & ((MSE_ref(frameOutlier) - mn) > 2*sd)
            frameOutlier = frameOutlier + 1;
        end

        if frameOutlier ~= frame
            prev = frame - 1;
            next = frameOutlier;

            if frame == 1
                for i = frame:(frameOutlier - 1)
                    tSeries(i,:) = tSeries(next,:);
                end

            elseif frameOutlier > nFrames
                for i = frame:(frameOutlier - 1)
                    tSeries(i,:) = tSeries(prev,:);
                end

            else
                for i = frame:(frameOutlier - 1)
                    tSeries(i,:) = (tSeries(next,:) - tSeries(prev,:))/(next - prev)*(i - prev) + tSeries(prev,:);
                end

            end

            if frameOutlier - frame > length(indexes)
                indexes = [indexes zeros(1,frameOutlier - frame + length(indexes))];
            end
            indexes(frameOutlier - frame) = indexes(frameOutlier - frame) + 1;

        end

        frame = max(frame + 1,frameOutlier);
	end
end

if sum(indexes) ~= 0

    qstring = 'Here are the number of spike artefacts detected:\n';
	for index = 1:length(indexes)
        if indexes(index) ~= 0
            if indexes(index) == 1
                occurence = 'occurence';
            else
                occurence = 'occurences';
            end

            qstring = [qstring sprintf('\n     - %d consecutive artefacts: %d %s ',index,indexes(index)),occurence];
        end
	end

	qstring = [qstring sprintf('\n\nWould you like to remove them?')];

	button = questdlg(sprintf(qstring),'Remove Outliers','Yes','No','default');

else
    button = 'No';
end

if strcmp(button,'Yes')
   return
else
   tSeries = backup;
   return
end


addpath('./code/') ;
mydir = {'train_1','train_2','train_3','test_1','test_2','test_3','test_1_new','test_2_new','test_3_new'};
srateNew = 256;
windL = 30; % window length in s
windS = 30; % window shift in s

for i1 = 1: size(mydir,2)
    names = dir(['../data/' mydir{i1}]);
    for i2=3:size(names,1)
        fprintf('\n%d-%d',i1,i2-2);
        load(['../data/' mydir{i1} '/' names(i2).name]);
        dataStruct.data = dataStruct.data';

        % Highpass Filter coefficient
        Fchp = 0.5;
        alpha = (2*pi*Fchp)/double(dataStruct.iEEGsamplingRate);

        % 60Hz notch filter
        fs = double(dataStruct.iEEGsamplingRate);               %#sampling rate
        f0 = 60;                %#notch frequency
        fn = fs/2;              %#Nyquist frequency
        freqRatio = f0/fn;      %#ratio of notch freq. to Nyquist freq.
        notchWidth = 0.05;       %#width of the notch
        %Compute zeros
        myzeros = [exp( sqrt(-1)*pi*freqRatio ), exp( -sqrt(-1)*pi*freqRatio )];
        %Compute poles
        mypoles = (1-notchWidth) * myzeros;
        b = poly( myzeros ); %# Get moving average filter coefficients
        a = poly( mypoles ); %# Get autoregressive filter coefficients

        for ii=1:size(dataStruct.data,1)
            dataStruct.data(ii,:) = dataStruct.data(ii,:) - mean(dataStruct.data(ii,:)); % centering
            LPOutput = filter(b,a,dataStruct.data(ii,:));
            HPOutput = zeros(size(LPOutput));
            HPOutput(1) = LPOutput(1);
            for iIndex = 2:length(LPOutput)
                HPOutput(iIndex) = (1 - alpha)*HPOutput(iIndex-1) + LPOutput(iIndex) - LPOutput(iIndex-1);
            end
            dataStruct.data(ii,:) = HPOutput;
        end
        dataStruct.data = double(dataStruct.data(:,dataStruct.iEEGsamplingRate*4:end-dataStruct.iEEGsamplingRate*4)); % removing 4 first and last seconds due to filtering
        dataStruct.data = (resample(dataStruct.data',srateNew,double(dataStruct.iEEGsamplingRate)))';
        feat = NaN(size(dataStruct.data,1),fix(((length(dataStruct.data(1,:)))-windL*srateNew+windS*srateNew)/(windS*srateNew)),102);
        for ii=1:size(dataStruct.data,1)
            fprintf('.');
            dataCh = enframe(dataStruct.data(ii,:),windL*srateNew,windS*srateNew);
            for iii=1:size(dataCh,1)
                if range(dataCh(iii,:))<1000
                    feat(ii,iii,:) = SPC_extract_features(dataCh(iii,:)');
                end
            end
        end
        %seq = dataStruct.sequence;
        if exist(['./feat/' mydir{i1} '/']) ~= 7
            mkdir(['./feat/' mydir{i1} '/']);
        end
        save(['./feat/' mydir{i1} '/' names(i2).name(1:end-4) '_feat'],'feat');
    end
end


function [testdata, target_interf_echo] = simulateDataImageRIR(sirdb, serdb, rt60, repeat, seed)
%
% Generate test data with simulated rir.
% sirdb:                specified SIR (dB)
% serdb:                specified SER (dB)
% rt60:                 reverberation time (s)
% testdata:             the generated data
% target_interf_echo:   target, interference, and echo signals
%

addpath('RIR-Generator-master');
% to reproduce experiments
rng(seed);

%% base directories
base_target='target/*.wav';
base_interf='interference/*.wav';
base_ref='reference/*.wav';

%% load sources
%
% target
%
sub=dir(base_target);
idx=randperm(size(sub, 1), 1);
target=audioread([sub(idx).folder, '/', sub(idx).name]);
siglen=length(target);
% set target signal activity
target=[zeros(siglen, 1);target;target;zeros(siglen, 1)];

%
% interference
%
sub=dir(base_interf);
idx=randperm(size(sub, 1), 1);
interf=audioread([sub(idx).folder, '/', sub(idx).name]);
% set interference activity
begin=randi(length(interf)-4*siglen);
interf=interf(begin+1:begin+4*siglen);

%
% reference
%
sub=dir(base_ref);
idx=randperm(size(sub, 1), 1);
ref=audioread([sub(idx).folder, '/', sub(idx).name]);
% set reference activity
begin=randi(length(ref)-2*siglen);
ref=ref(begin+1:begin+2*siglen);
ref=[zeros(length(ref), 1);ref];

% repeat the same utterance
if repeat > 1
    target_bk=target; interf_bk=interf; ref_bk=ref;
    for i=1:repeat-1
        target = [target;target_bk];
        interf = [interf;interf_bk];
        ref = [ref;ref_bk];
    end
end

%% generate simulated rirs
room_bound_x=[3, 6];
room_bound_y=[4, 8];
room_bound_z=[2.5, 4];
% sample the room size
room_x=round(rand*(room_bound_x(2)-room_bound_x(1))+room_bound_x(1), 2);
room_y=round(rand*(room_bound_y(2)-room_bound_y(1))+room_bound_y(1), 2);
room_z=round(rand*(room_bound_z(2)-room_bound_z(1))+room_bound_z(1), 2);

c = 340;                    % Sound velocity (m/s)
fs = 16000;                 % Sample frequency (samples/s)
L = [room_x, room_y, room_z];  % Room dimensions [x y z] (m)
beta = rt60;                % Reverberation time (s)
n = 4096;                   % Number of samples
mtype = 'omnidirectional';  % Type of microphone
order = -1;                 % -1 equals maximum reflection order!
dim = 3;                    % Room dimension
orientation = 0;            % Microphone orientation (rad)
hp_filter = 1;              % Enable high-pass filter
early_reverb = fs * 0.05;   % define early reverberation

%
% generate mic position
%
d = 0.1;                    % mic spacing (m)
theta=rand(1, 1)*2*pi;
R=[cos(theta), -sin(theta), 0; sin(theta), cos(theta), 0; 0, 0, 1];
m1=R*[-d/2; 0; 0];
m2=R*[d/2; 0; 0];

space=0.5;
r0=space*ones(1, 3)+rand(1, 3).*(L-2*space*ones(1, 3));
r = [r0+m1'; r0+m2'];       % Receiver positions [x_1 y_1 z_1 ; x_2 y_2 z_2] (m)

%
% generate source position
%
dist_bound = [0.2, 3];  % allowed source-receiver distance
while 1
    elevation=asin(2*rand - 1);
    azimuth=2*pi*rand;
    % favor large distance
    radii=dist_bound(1)+(dist_bound(2)-dist_bound(1))*(rand.^(1/3));
    [offset_x, offset_y, offset_z] = sph2cart(azimuth, elevation, radii);
    offset_xyz = [offset_x offset_y offset_z];
    s1 = offset_xyz + r0;
    % check if the source position is within the correct range, otherwise resample
    if s1 <= (L-space) & s1 >= space
        break
    end
end
while 1
    elevation=asin(2*rand - 1);
    azimuth=2*pi*rand;
    % favor large distance
    radii=dist_bound(1)+(dist_bound(2)-dist_bound(1))*(rand.^(1/3));
    [offset_x, offset_y, offset_z] = sph2cart(azimuth, elevation, radii);
    offset_xyz = [offset_x offset_y offset_z];
    s2 = offset_xyz + r0;
    % check if the source position is within the correct range, otherwise resample
    if s2 <= (L-space) & s2 >= space
        break
    end
end

% % show mic-source positions
% plot(r(:,1),r(:,2),'o'); xlim([0,L(1)]); ylim([0,L(2)]);
% hold on; plot(s1(1),s1(2), 'x'); plot(s2(1),s2(2), 'v'); hold off;

% loudspeaker is 15 cm below mic
s3=r0;
s3(3)=s3(3)-0.15;

%
% generate rir
%
h=rir_generator(c, fs, r, s1, L, beta, n, mtype, order, dim, orientation, hp_filter);
a11=h(1, :);
a21=h(2, :);
% tt=0:length(a11)-1;
% plot(tt, a11, tt, a21);

h=rir_generator(c, fs, r, s2, L, beta, n, mtype, order, dim, orientation, hp_filter);
a12=h(1, :);
a22=h(2, :);

h=rir_generator(c, fs, r, s3, L, beta, n, mtype, order, dim, orientation, hp_filter);
b1=h(1, :);
b2=h(2, :);
% tt=0:length(b1)-1;
% plot(tt, b1, tt, b2);

%% mix data
%
% generate data image
%
target_img=[conv(target, a11), conv(target, a21)];
target_img(length(target)+1:end, :)=[];
target_early_reverb=conv(target, a11(1:early_reverb));
target_early_reverb(length(target)+1:end, :)=[];

interf_img=[conv(interf, a12), conv(interf, a22)];
interf_img(length(interf)+1:end, :)=[];
interf_early_reverb=conv(interf, a12(1:early_reverb));
interf_early_reverb(length(interf)+1:end, :)=[];

echo=[conv(ref, b1), conv(ref, b2)];
echo(length(ref)+1:end, :)=[];

%
% adjust snr
%
[target_img, gain]=adjustSNR(target, target_img, 0);
target_early_reverb=target_early_reverb*gain;
[interf_img, gain]=adjustSNR(target_img, interf_img, sirdb);
interf_early_reverb=interf_early_reverb*gain;
[echo, gain]=adjustSNR(target_img, echo, serdb);

% generate the mixed signals
testdata=[target_img+interf_img+echo, ref];
target_interf_echo=[target_early_reverb, interf_early_reverb, echo(:, 1)];

end


function test_num = r8mat_exp_test_num ( )

%*****************************************************************************80
%
%% R8MAT_EXP_TEST_NUM returns the number of matrix exponential tests.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 October 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer TEST_NUM, the number of tests.
%
  test_num = 14;

  return
end


function [M,Vr,Vc] = meanShiftIm( X,sigSpt,sigRng,softFlag,maxIter,minDel )
% Applies the meanShift algorithm to a joint spatial/range image.
%
% See "Mean Shift Analysis and Applications" by Comaniciu & Meer for info.
%
% Assumes X is an MxNxP array, where an X(i,j,:) represents the range data
% at locations (i,j).  This function runs meanShift on each of the MxN data
% points.  It takes advantage of the lattice structure of an image for
% efficiency (it only needs to calculate full distance between two points
% if they are near each other spatially).
%
% In the original formulation of the algorithm, after normalization of the
% data, the search window around each point x has radius 1 (ie
% corresponding to 1 std of the data). That is the search window only
% encloses 2*s+1 pixels, and of those, all which fall within 1 unit from x
% are used to calcluate the new mean.  If softFlag==0 the original
% formulation is used.  If softFlag==1, instead of using a fixed radius,
% each point p is used in the calulation of the mean with points close to x
% given significantly more weight.  Specifically, each point p is given
% weight exp(-dist(x,p)).  So instead of having a fixed cutoff at r, the
% cutoff is 'soft' (same idea as in softmax), and occurs at approximately
% r.  The implementation remains efficient by actually using a hard cutoff
% at points further then 2r spatially from x.
%
% The resulting matrix M is of size MxNx(P+2).  M(i,j,1) represents the
% convergent row location of X(i,j,:) - (which had initial row location i)
% and M(i,j,2) represents the final column location.  M(i,j,p+2) represents
% the convergent value for X(i,j,p).  The optionaly outputs Vr and Vc are
% 2D arrays where Vr(i,j)=M(i,j,1)-i and Vc(i,j)=M(i,j,2)-j.  That is they
% represent the spatial offset between the original location of a point and
% its convergent location.  Display using quiver(Vc,Vr,0).
%
% USAGE
%  [M,Vr,Vc] = meanShiftIm( X,sigSpt,sigRng,[softFlag],[maxIter],[minDel] )
%
% INPUTS
%  X        - MxNxP data array, P may be 1
%  sigSpt   - integer specifying spatial standard deviation
%  sigRng   - value specifying the standard deviation of the range data
%  softFlag - [0]- see above
%  maxIter  - [100] maximum number of iterations per data point
%  minDel   - [.001] minimum amount of spatial change defining convergence
%
% OUTPUTS
%  M        - array of convergent locations [see above]
%  Vr       - spatial motion in row direction
%  Vc       - spatial motion in col direction
%
% EXAMPLE
%  I=double(imread('cameraman.tif'))/255;
%  [M,Vr,Vc] = meanShiftIm( I,5,.2 );
%  figure(1); im(I); figure(2); im( M(:,:,3) );
%  % color image:
%  I=double(imread('hestain.png'))/255;
%  [M,Vr,Vc] = meanShiftIm( I,5,.2 );
%  figure(1); im(I); figure(2); im( M(:,:,3:end) );
%
% See also MEANSHIFT, MEANSHIFTIMEXPLORE
%
% Piotr's Computer Vision Matlab Toolbox      Version 2.0
% Copyright 2014 Piotr Dollar.  [pdollar-at-gmail.com]
% Licensed under the Simplified BSD License [see external/bsd.txt]

[sigSpt,er] = checkNumArgs( sigSpt, 1, 0, 1 ); error(er);
if( nargin<4 || isempty(softFlag)); softFlag = 0; end
if( nargin<5 || isempty(maxIter) ); maxIter = 100; end
if( nargin<6 || isempty(minDel)); minDel = .001; end

[mrows, ncols, p] = size(X); p = p+2;
[gridRs, gridCs] = ndgrid( 1:mrows, 1:ncols );
data = cat( 3, cat( 3, gridRs/sigSpt, gridCs/sigSpt), X/sigRng );

%%% MAIN LOOP
M = data;
ticId = ticStatus('meanShiftIm');  %t0 = clock;  tlast = t0;
if( softFlag ); radius = sigSpt*2; else radius = sigSpt; end
for i=1:mrows; for j=1:ncols; %#ok<ALIGN>
    Mij = data(i,j,:); Mij = Mij(:)';
    itercount = 0; diff = 1;
    while( itercount < maxIter && diff>minDel )

      % get data which is possibly relevant (within spatial range)
      r = round( Mij(1)*sigSpt );  c = round( Mij(2)*sigSpt );
      boundsr = max(1,r-radius):min(mrows,r+radius);
      boundsc = max(1,c-radius):min(ncols,c+radius);
      dataWin = data( boundsr, boundsc, : );
      dataWinF = reshape( dataWin, [], p );

      % get next mean
      MijOld = Mij;
      n = size( dataWinF, 1);
      D = sum( (dataWinF - ones(n,1)*Mij).^2, 2 );
      if( softFlag )
        S = exp( -D ); sumS = sum(S); Srep = S(:,ones(1,p));
        Mij = sum( dataWinF .* Srep, 1 ) / sumS;
      else
        dataWinF = dataWinF( D < 1, : );
        Mij = sum( dataWinF, 1 ) / size( dataWinF,1 );
      end

      % check if Mij changed [only on basis of x,y location]
      diff = sum( (MijOld(1:2)-Mij(1:2)).^2 );
      itercount = itercount+1;

    end
    M(i,j,:) = Mij(:);
    fracdone = ((i-1)*ncols+j) / (mrows*ncols);
    tocStatus( ticId, fracdone );
  end
end
M = cat(3, M(:,:,1:2)*sigSpt, M(:,:,3:end)*sigRng );

%%% Output spatial difference
if( nargout>1 )
  Vr = M(:,:,1)-gridRs;  Vc = M(:,:,2)-gridCs;
end


function params = er_defaultParams
%
%  params = er_defaultParams;
%
% Returns default parameters for running
% event-related analyses. Chose them
% to be nice for most KGS-lab block-design
% extps.
%
%
% ras 04/05.
% ras 11/06: added HRF sub-params (for standard H.R.F.s)
% dar 3/07    fixed typo in glmHRF_params, added comments on each parameter
params.eventAnalysis = 1; % back compatibility w/ mrLoadRet code

% detrend flag:
%--------------
% -1 linear detrend, 0 no detrend, 1 multiple boxcar smoothing,
% 2 quartic trend removal
params.detrend = 1;

% detrend frames:
% for detrend option 1, # of frames for smoothing
% kernal (roughly equivalent to cutoff of highpass
% filter):
params.detrendFrames = 20;

% inhomogeneity correction flag:
%-------------------------------
%     0 do nothing
%     1 divide by the mean, independently at each voxel
%     2 divide by null condition
%     3 divide by spatial gradient estimate
params.inhomoCorrect = 1;

% temporal normalization flag:
params.temporalNormalization = 0;

% seconds relative to trial onset to take for each trial
params.timeWindow = -8:24;

% period to look for peaks in t-tests, in seconds
params.peakPeriod = 4:14;

% period to use as baseline in t-tests, in seconds
params.bslPeriod = -8:0;

% threshold for significant activations
params.alpha = 0.05;

% # secs to shift onsets in parfiles, relative to time course
params.onsetDelta = 0;

% conditions to use for calculating signal-to-noise, HRF
params.snrConds = 1;

% flag for which hemodynamic impulse response
% function to use if applying a GLM:
% -------------------------------------------
% 0: deconovolve (selective averaging)
% 1: estimate HRF from mean response to all non-null conditions
% 2: Use Boynton et all 1998 gamma function
% 3: Use SPM difference-of-gammas
% 4: Use HRF from Dale and Buckner, 1997 (very similar to Boynton
%    gamma)
% OR, if flag is a char: name of a saved HRF function
%    (stored in subject/HRFs/, where subject is the subject's
%     anatomy directory, where the vAnatomy is stored)
params.glmHRF = 2;                    % boynton hrf
params.glmHRF_params = [3 1.08 2.05]; % good params for Boynton HIRF

% flag for whether or not to estimate temporally-correlated
% noise in data when applying a GLM, referred to as 'whitening':
% (see Dale and Burock, HBM, 2000):
params.glmWhiten = 0;

% # of events per block: this indicates whether each event
% is actually a block of evenly-spaced sub-events (trials).
params.eventsPerBlock = 1; % if block-design, # of events per block

params.ampType = 'betas';

% flag to zero baseline or not
params.normBsl = 1;

% params.colorOrder = []; % will get from tc_colorOrder, but
%                         % depends on # of conditions specified
%                         % in parfiles.

return


function cS = titanite
% sphene

%
cs_Ttn = crystalSymmetry('2/m',[0.753 1 0.854], [90, 119.72, 90]*degree);
N = Miller({0,1,0},{0,0,1},{1,1,1},{0,1,1},cs_Ttn);
dist = [0.89, 1.39, 1, 1.4];
cS = crystalShape(N./dist);


function [A]=cmatrep(A,crit,v1,v2)

%CMATREP optimized matrep
%
%[A]=cmatrep(A,crit,v1,v2)
%Criteria   all values   will be replaced with
% 'eq'         =v1               v2
% 'lt'         <v1               v2
% 'gt'         >v1               v2

[a1 a2]=size(A);

if (crit=='lt') | (crit=='LT'),
for i=1:a1;
  for j=1:a2;
    if A(i,j)<v1,
    	A(i,j)=v2;
    end;
  end;
end;
end;

if (crit=='eq') | (crit=='EQ'),
for i=1:a1;
  for j=1:a2;
    if A(i,j)==v1,
    	A(i,j)=v2;
    end;
  end;
end;
end;

if (crit=='gt') | (crit=='GT'),
for i=1:a1;
  for j=1:a2;
    if A(i,j)>v1,
    	A(i,j)=v2;
    end;
  end;
end;
end;


function [bestLabels, bestEpsilon] = find_best_segmentation(result, sequenceData,  groupCount, epsilon)

% find_best_segmentation.m
%
%   Given a known group count, choose the segmentation in a list of segmentations
%   that best codes the data. The approach uses a modified voting scheme to
%   pick a segmentation that has the correct number of groups. If no such
%   segmentation exists, than the segmentation with the minimum penalized
%   coding length is returned, along with a warning.
%
% Inputs:
%   result              - a structure containing the results of applying
%                           greedy algorithm to a particular motion
%                           sequence for a range of epsilons.
%   sequenceData        - a matrix where each column is a vector obtained
%                           from a tracked feature in the motion sequence.
%   groupCount          - the known number of groups.
%   epsilon             - a list containing the range of epsilons for which these results
%                           were obtained.
%
% Outputs:
%   bestLabels          - a labeling of the motion data that is the "best"
%                           segmentation.
%   bestEpsilon         - a choice of epsilon that will cause ALC to
%                         produce this "best" segmentation.
% Dependencies:
%   distinct_labels, total_coding_length
%
% Mar. '08  Shankar Rao -- srrao@uiuc.edu
%
% Copyright 2008, University of Illinois. All rights reserved.

OUTLIER_GROUP_COUNT = 4;

[sampleCount, trialCount] = size(result.labels);
properGroupings = [];
isSingleGrouping = false(1,trialCount);

for trialIndex = 1:trialCount
    currentLabels = result.labels(:, trialIndex);
    distribution = histc(currentLabels, 1:max(currentLabels));
    if (sum(distribution > OUTLIER_GROUP_COUNT) == groupCount)
        properGroupings = [properGroupings trialIndex];
        % Label all outliers as one group, relabel inliers
        % modified 10-24-07
        outlierLabels = find(distribution <= OUTLIER_GROUP_COUNT);
        inlierLabels = find(distribution > OUTLIER_GROUP_COUNT);
        outlierIndices = find(ismember(currentLabels, outlierLabels));
        currentLabels(outlierIndices) = -1;
        for labelIndex = 1:length(inlierLabels)
            currentLabels(result.labels(:, trialIndex) == inlierLabels(labelIndex)) = labelIndex;
        end
        currentLabels(outlierIndices) = groupCount+1;
        result.labels(:, trialIndex) = currentLabels;
    elseif (max(currentLabels) == 1)
        isSingleGrouping(trialIndex) = true;
    end
end

if isempty(properGroupings)
    warning('No segmentation has the correct number of groups. Returning the one with minimal penalized coding length.');
    [ignore winnerIndex] = min(result.penalty);
    bestLabels = result.labels(:, winnerIndex);
    bestEpsilon = epsilon(winnerIndex);
else
    % ignore any epsilon that results in all of the samples being grouped
    % together.
    nonSingleGroupings = find(~isSingleGrouping);

    % only epsilons that result in the proper number of group can be
    % considered as candidate groupings.
    properGroupingsCount = length(properGroupings);

    [distinctLabels labelIndices] = distinct_labels(result.labels(:, properGroupings));
    candidateCount = size(distinctLabels, 2);
    codingLengths = zeros(candidateCount, length(nonSingleGroupings));

    % however, all non single-group segmentations get a vote
    for trialIndex = 1:length(nonSingleGroupings)
        for candidateIndex = 1:candidateCount
            codingLengths(candidateIndex, trialIndex) = ...
                total_coding_length(sequenceData, distinctLabels(:, candidateIndex), epsilon(nonSingleGroupings(trialIndex)), false);
        end
    end

    [ignore votes] = min(codingLengths, [] , 1);
    voteCounts = histc(votes, 1:candidateCount);
    [ignore winnerIndex] = max(voteCounts);
    bestLabels = distinctLabels(:, winnerIndex);
    winnerLabelIndices = find(labelIndices == winnerIndex);
    bestEpsilon = epsilon(uint32(floor(median(winnerLabelIndices))));
end


classdef tdropout < matlab.unittest.TestCase
    % tdropout   Unit tests for transformer.layer.dropout

    % Copyright 2020 The MathWorks, Inc.
    properties(TestParameter)
        Size = struct(...
            'Vector',[10000,1],...
            'Matrix',[100,100],...
            'Tensor',[5,60,70])
        Probability = struct(...
            'Zero',0,...
            'Half',0.5,...
            'OneIsh',0.95)
    end

    methods(TestMethodSetup)
        function resetGlobalSeed(~)
            rng(0);
        end
    end

    methods(Test)
        function doesDropout(test,Size,Probability)
            x = ones(Size);
            y = transformer.layer.dropout(x,Probability);
            % Expectation is that mean(y) is about 1 since we use inverted
            % dropout.
            actMean = mean(y,'all');
            expMean = 1;
            tol = 1e-1;
            test.verifyEqual(actMean,expMean,'AbsTol',tol);
        end

        function isRandom(test)
            % Verify dropout is random on repeated calls
            x = ones([5,4,3]);
            p = 0.5;
            y1 = transformer.layer.dropout(x,p);
            y2 = transformer.layer.dropout(x,p);
            test.verifyNotEqual(y1,y2);
        end

        function supportsDlarrayAndAutodiff(test)
            x = dlarray(ones([5,4,3]));
            p = 0.5;
            f = @(x) transformer.layer.dropout(x,p);
            test.verifyWarningFree(@() f(x));
            function [val,df_val] = df(x)
                val = f(x);
                df_val = dlgradient(sum(val,'all'),x);
            end
            [f_val,df_val] = dlfeval(@df,x);
            % Gradient of dropout is itself
            test.verifyEqual(df_val,f_val);
        end
    end
end


function w = demean (w)
   %DEMEAN remove offset voltage from signal
   %   waveform = demean(waveform)
   %   Removes the mean signal from the waveform object
   %
   %   Input Arguments
   %       WAVEFORM: a waveform object   N-DIMENSIONAL

   % AUTHOR: Celso Reyes, Geophysical Institute, Univ. of Alaska Fairbanks
   % $Date$
   % $Revision$

   m = mean(w);
   w = w - m;
end


function tapas_ehgf_plotTraj(r)
% Plots the estimated or generated trajectories for the HGF perceptual model
% Usage example:  est = tapas_fitModel(responses, inputs); tapas_hgf_plotTraj(est);
%
% --------------------------------------------------------------------------------------------------
% Copyright (C) 2012-2020 Christoph Mathys, TNU, UZH & ETHZ
%
% This file is part of the HGF toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

% Optional plotting of standard deviations (true or false)
plotsd = true;

% Set up display
scrsz = get(0,'screenSize');
outerpos = [0.2*scrsz(3),0.2*scrsz(4),0.8*scrsz(3),0.8*scrsz(4)];
figure(...
    'OuterPosition', outerpos,...
    'Name', 'HGF trajectories');

% Time axis
if size(r.u,2) > 1 && ~isempty(find(strcmp(fieldnames(r.c_prc),'irregular_intervals'))) && r.c_prc.irregular_intervals
    t = r.u(:,end)';
else
    t = ones(1,size(r.u,1));
end

ts = cumsum(t);
ts = [0, ts];

% Number of levels
l = length(r.p_prc.p)/5;

% Upper levels
for j = 1:l-1

    % Subplots
    subplot(l,1,j);

    if plotsd == true
        upperprior = r.p_prc.mu_0(l-j+1) +sqrt(r.p_prc.sa_0(l-j+1));
        lowerprior = r.p_prc.mu_0(l-j+1) -sqrt(r.p_prc.sa_0(l-j+1));
        upper = [upperprior; r.traj.mu(:,l-j+1)+sqrt(r.traj.sa(:,l-j+1))];
        lower = [lowerprior; r.traj.mu(:,l-j+1)-sqrt(r.traj.sa(:,l-j+1))];

        plot(0, upperprior, 'ob', 'LineWidth', 1);
        hold all;
        plot(0, lowerprior, 'ob', 'LineWidth', 1);
        fill([ts, fliplr(ts)], [(upper)', fliplr((lower)')], ...
             'b', 'EdgeAlpha', 0, 'FaceAlpha', 0.15);
    end
    plot(ts, [r.p_prc.mu_0(l-j+1); r.traj.mu(:,l-j+1)], 'b', 'LineWidth', 2);
    hold all;
    plot(0, r.p_prc.mu_0(l-j+1), 'ob', 'LineWidth', 2); % prior
    xlim([0 ts(end)]);
    title(['Posterior expectation of x_' num2str(l-j+1)], 'FontWeight', 'bold');
    ylabel(['\mu_', num2str(l-j+1)]);
end

% Input level
subplot(l,1,l);

if plotsd == true
    upperprior = r.p_prc.mu_0(1) +sqrt(r.p_prc.sa_0(1));
    lowerprior = r.p_prc.mu_0(1) -sqrt(r.p_prc.sa_0(1));
    upper = [upperprior; r.traj.mu(:,1)+sqrt(r.traj.sa(:,1))];
    lower = [lowerprior; r.traj.mu(:,1)-sqrt(r.traj.sa(:,1))];

    plot(0, upperprior, 'or', 'LineWidth', 1);
    hold all;
    plot(0, lowerprior, 'or', 'LineWidth', 1);
    fill([ts, fliplr(ts)], [(upper)', fliplr((lower)')], ...
         'r', 'EdgeAlpha', 0, 'FaceAlpha', 0.15);
end
plot(ts, [r.p_prc.mu_0(1); r.traj.mu(:,1)], 'r', 'LineWidth', 2);
hold all;
plot(0, r.p_prc.mu_0(1), 'or', 'LineWidth', 2); % prior
plot(ts(2:end), r.u(:,1), '.', 'Color', [0 0.6 0]); % inputs
if ~isempty(find(strcmp(fieldnames(r),'y'))) && ~isempty(r.y)
    plot(ts(2:end), r.y(:,1), '.', 'Color', [1 0.7 0]); % responses
    title(['Response y (orange), input u (green), and posterior expectation of x_1 ', ...
           '(red) for \rho=', num2str(r.p_prc.rho), ', \kappa=', ...
           num2str(r.p_prc.ka), ', \omega=', num2str(r.p_prc.om), ...
           ', \pi_u=', num2str(r.p_prc.pi_u)], ...
          'FontWeight', 'bold');
    ylabel('y, u, \mu_1');
else
    title(['Input u (green) and posterior expectation of x_1 ', ...
           '(red) for \rho=', num2str(r.p_prc.rho), ', \kappa=', ...
           num2str(r.p_prc.ka), ', \omega=', num2str(r.p_prc.om), ...
           ', \pi_u=', num2str(r.p_prc.pi_u)], ...
          'FontWeight', 'bold');
    ylabel('u, \mu_1');
end
xlim([0 ts(end)]);
xlabel({'Trial number', ' '}); % A hack to get the relative subplot sizes right
hold off;