classdef FminconOptimizer < AbstractGradientOptimizer
    %FminconOptimizer Summary of this class goes here
    %   Detailed explanation goes here

    properties(Access = private)
        options(1,1) FminconOptions = FminconOptions();
    end

    methods
        function obj = FminconOptimizer()
            obj.options = FminconOptions();
        end

        function [exitflag, message] = optimize(obj, lvdOpt, writeOutput, callOutputFcn, hLvdMainGUI)
            [x0All, actVars, varNameStrs] = lvdOpt.vars.getTotalScaledXVector();
            [lbAll, ubAll, lbUsAll, ubUsAll] = lvdOpt.vars.getTotalScaledBndsVector();
            typicalX = lvdOpt.vars.getTypicalScaledXVector();

            if(isempty(x0All) && isempty(actVars))
                exitflag = 0;
                message = 'No variables enabled on script.  Aborting optimization.';

                return;
            end

            bool = x0All < lbAll;
            x0All(bool) = lbAll(bool);

            bool = x0All > ubAll;
            x0All(bool) = ubAll(bool);

            evtNumToStartScriptExecAt = obj.getEvtNumToStartScriptExecAt(lvdOpt, actVars);
            evtToStartScriptExecAt = lvdOpt.lvdData.script.getEventForInd(evtNumToStartScriptExecAt);

            opts = obj.options.getOptionsForOptimizer(typicalX);

            objFuncWrapper = @(x) lvdOpt.objFcn.evalObjFcn(x, evtToStartScriptExecAt);

            if(opts.SpecifyConstraintGradient)
                nonlcon = @(x) lvdOpt.constraints.evalConstraintsWithGradients(x, true, evtToStartScriptExecAt, true, []);
            else
                nonlcon = @(x) lvdOpt.constraints.evalConstraints(x, true, evtToStartScriptExecAt, true, []);
            end

            if(obj.options.computeOptimalStepSizes == true)
                optimalStepSizes = CustomFiniteDiffsCalculationMethod.determineOptimalStepSizes(@(x) CustomFiniteDiffsCalculationMethod.combinedConstrFun(x, lvdOpt.lvdData), x0All, hLvdMainGUI);

                if(not(isempty(optimalStepSizes)))
                    opts.FiniteDifferenceStepSize = optimalStepSizes;
                    opts.TypicalX = ones(length(optimalStepSizes),1);
                end
            end

            if(lvdOpt.gradAlgo == LvdOptimizerGradientCalculationAlgoEnum.BuiltIn)
                objFunToPass = objFuncWrapper;
                opts = optimoptions(opts, 'SpecifyObjectiveGradient',false);
            elseif(lvdOpt.gradAlgo == LvdOptimizerGradientCalculationAlgoEnum.FiniteDifferences)
                gradCalcMethod = lvdOpt.customFiniteDiffsCalcMethod;
                objFunToPass = @(x) obj.objFuncWithGradient(objFuncWrapper, x, gradCalcMethod, obj.usesParallel());
                opts = optimoptions(opts, 'SpecifyObjectiveGradient',true);

                sparsityTF = gradCalcMethod.shouldComputeSparsity();
                if(sparsityTF && not(isempty(hLvdMainGUI)))
%                     hMsgBox = msgbox('Computing sparsity.  Please wait...');
                    hMsgBox = uiprogressdlg(hLvdMainGUI, 'Message','Computing sparsity.  Please wait...', 'Title','Computing Sparsity', 'Indeterminate',true, 'Icon','info');
                else
                    hMsgBox = NaN;
                end

                fAtX0 = objFunToPass(x0All);
                gradCalcMethod.computeGradientSparsity(objFuncWrapper, x0All, fAtX0, obj.usesParallel());

                if(sparsityTF && isgraphics(hMsgBox))
                    close(hMsgBox); drawnow;
                end
            end

            problem = createOptimProblem('fmincon', 'objective',objFunToPass, 'x0', x0All, 'lb', lbAll, 'ub', ubAll, 'nonlcon', nonlcon, 'options', opts);
            problem.lvdData = lvdOpt.lvdData; %need to get lvdData in somehow

            %%% Run optimizer
            recorder = ma_OptimRecorder();
            celBodyData = lvdOpt.lvdData.celBodyData;

            if(callOutputFcn)
                propNames = lvdOpt.lvdData.launchVehicle.tankTypes.getFirstThreeTypesCellArr();
%                 handlesObsOptimGui = ma_ObserveOptimGUI(celBodyData, problem, true, writeOutput, [], varNameStrs, lbUsAll, ubUsAll);

                out = AppDesignerGUIOutput();
                ma_ObserveOptimGUI_App(out);
                handlesObsOptimGui = out.output{1};

%                 outputFnc = @(x, optimValues, state) ma_OptimOutputFunc(x, optimValues, state, handlesObsOptimGui, problem.objective, problem.lb, problem.ub, celBodyData, recorder, propNames, writeOutput, varNameStrs, lbUsAll, ubUsAll);
                hOptimStatusLabel = handlesObsOptimGui.optimStatusLabel;
                hFinalStateOptimLabel = handlesObsOptimGui.finalStateOptimLabel;
                hDispAxes = handlesObsOptimGui.dispAxesPanel;
                hCancelButton = handlesObsOptimGui.cancelButton;
                optimStartTic = tic();

                outputFnc = @(x, optimValues, state) FminconOptimizer.getOutputFunction(x, optimValues, state, hOptimStatusLabel, hFinalStateOptimLabel, hDispAxes, hCancelButton, ...
                                                                                objFuncWrapper, problem.lb, problem.ub, celBodyData, recorder, propNames, writeOutput, varNameStrs, lbUsAll, ubUsAll, optimStartTic);
                problem.options.OutputFcn = outputFnc;
            end

            [exitflag, message] = lvd_executeOptimProblem(celBodyData, writeOutput, problem, recorder, callOutputFcn);

            if(callOutputFcn)
                close(handlesObsOptimGui.ma_ObserveOptimGUI);
            end
        end

        function options = getOptions(obj)
            options = obj.options;
        end

        function setGradientCalculationMethod(obj, newGradCalcMethod)
            obj.gradCalcMethod = newGradCalcMethod;
        end

        function openOptionsDialog(obj)
%             lvd_editFminconOptionsGUI(obj);

            output = AppDesignerGUIOutput({false});
            lvd_editFminconOptionsGUI_App(obj, output);
        end

        function tf = usesParallel(obj)
            tf = obj.options.useParallel.optionVal;
        end

        function numWorkers = getNumParaWorkers(obj)
            numWorkers = obj.options.getNumParaWorkers();
        end
    end

    methods(Access=private)
        function [f, g, stateLog] = objFuncWithGradient(~, objFun, x, gradCalcMethod, useParallel)
            [f, stateLog] = objFun(x);

            if(nargout >= 2)
                g = gradCalcMethod.computeGrad(objFun, x, f, useParallel);
            end
        end
    end

    methods(Static, Access=private)
        function stop = getOutputFunction(x, optimValues, state, hOptimStatusLabel, hFinalStateOptimLabel, hDispAxes, hCancelButton, ...
                                          objFcn, lb, ub, celBodyData, recorder, propNames, writeOutput, varLabels, lbUsAll, ubUsAll, optimStartTic)
            switch state
                case 'iter'
                    stop = get(hCancelButton,'Value');

                    recorder.iterNums(end+1) = optimValues.iteration;
                    recorder.xVals(end+1) = {x};
                    recorder.fVals(end+1) = optimValues.fval;
                    recorder.maxCVal(end+1) = optimValues.constrviolation;
                case {'init','interrupt','done'}
                    stop = get(hCancelButton,'Value');
            end

            if(stop == true)
                return;
            end

            [~, stateLog] = objFcn(x);

%             finalStateLogEntry = stateLog.getFinalStateLogEntry();
%             finalStateLogEntryMA = finalStateLogEntry.getMAFormattedStateLogMatrix(true);

            stateLogMA = stateLog.getMAFormattedStateLogMatrix(true);

            if(strcmpi(state,'init') || strcmpi(state,'iter'))
                try
                    FminconOptimizer.writeOptimStatus(hOptimStatusLabel, optimValues, state, writeOutput, optimStartTic);
                    ma_UpdateStateReadout(hFinalStateOptimLabel, 'final', propNames, stateLogMA, celBodyData);
                    FminconOptimizer.generatePlots(x, optimValues, state, hDispAxes, lb, ub, varLabels, lbUsAll, ubUsAll);
                    drawnow;
                catch ME
                    warning(ME.message);
                end
            end
        end

        function writeOptimStatus(hOptimStatusLabel, optimValues, state, writeOutput, timer)
            elapTime = toc(timer);

            outStr = {};
            outStr{end+1} = ['State                = ', state];
            outStr{end+1} = '                        ';
            outStr{end+1} = ['Iterations           = ', num2str(optimValues.iteration)];
            outStr{end+1} = ['Function Evals       = ', num2str(optimValues.funccount)];
            outStr{end+1} = ['Objective Value      = ', num2str(optimValues.fval)];
            outStr{end+1} = ['Constraint Violation = ', num2str(optimValues.constrviolation)];
            outStr{end+1} = ['Optimality           = ', num2str(optimValues.firstorderopt)];
            outStr{end+1} = ['Step Size            = ', num2str(optimValues.stepsize)];
            outStr{end+1} = '                       ';
            outStr{end+1} = ['Elapsed Time         = ', num2str(elapTime), ' sec'];

            set(hOptimStatusLabel, 'String', outStr);

            switch state
                case 'iter'
                    formatstr = ' %- 12.1i %- 12.0i %- 12.6g %- 12.3g %- 12.3g %- 12.3g';

                    iter = optimValues.iteration;
                    fcnt = optimValues.funccount;
                    val  = optimValues.fval;
                    feas = optimValues.constrviolation;
                    optm = optimValues.firstorderopt;
                    step = optimValues.stepsize;

                    hRow = sprintf(formatstr,iter,fcnt,val,feas,optm,step);
                    writeOutput(hRow,'append');
                case 'init'
                    hdrStr = sprintf('%- 13s%- 13s%- 13s%- 13s%- 13s%- 13s', 'Iteration','Fcn-Count','f(x)-Value', 'Feasibility', 'Optimality', 'Norm. Step');
                    writeOutput(hdrStr,'append');
            end
        end

        function generatePlots(x, optimValues, state, hDispAxes, lb, ub, varLabels, lbUsAll, ubUsAll)
            persistent fValPlotIsLog tLayout hPlot1 hPlot2 hPlot3

            if(isempty(fValPlotIsLog))
                fValPlotIsLog = true;
            end

            switch state
                case 'init'
                    if(isvalid(hDispAxes))
%                         set(hDispAxes,'Visible','on');
%                         subplot(hDispAxes);
                        tLayout = tiledlayout(hDispAxes, 3,1);
%                         axes(hDispAxes);
                    end
                    fValPlotIsLog = true;
            end

            hPlot1 = nexttile(tLayout, 1);
            if(strcmpi(state,'init'))
%                 hPlot1 = subplot(hDispAxes, 3,1,1);

                hPlot1.XTickLabel= [];
                hPlot1.YTickLabel= [];
                hPlot1.ZTickLabel= [];
%                 axes(hPlot1);
            end
            optimplotxKsptot(x, optimValues, state, lb, ub, varLabels, lbUsAll, ubUsAll);

            hPlot2 = nexttile(tLayout, 2);
            if(strcmpi(state,'init'))
%                 hPlot2 = subplot(3,1,2);

                hPlot2.XTickLabel= [];
                hPlot2.YTickLabel= [];
                hPlot2.ZTickLabel= [];
                h = hPlot2;
            else
                h = hPlot2;
%                 axes(hPlot2);
            end
            if(optimValues.fval<=0)
                fValPlotIsLog = false;
                set(h,'yscale','linear');
            end
            optimplotfvalKsptot(x, optimValues, state);
            if(fValPlotIsLog)
                set(h,'yscale','log');
            else
                set(h,'yscale','linear');
            end
            grid on;
            grid minor;

            hPlot3 = nexttile(tLayout, 3);
            if(strcmpi(state,'init'))
%                 hPlot3 = subplot(3,1,3);

                hPlot3.XTickLabel= [];
                hPlot3.YTickLabel= [];
                hPlot3.ZTickLabel= [];
                h = hPlot3;
            else
                h = hPlot3;
%                 axes(hPlot3);
            end
            optimplotconstrviolationKsptot(x, optimValues, state);

            if(not(isempty(h.Children)))
                hLine = h.Children(1);
                if(isa(hLine,'matlab.graphics.chart.primitive.Line'))
                    yDataLine = hLine.YData;
                    if(abs(max(yDataLine) / min(yDataLine)) >= 10 && all(yDataLine > 0))
                        set(h,'yscale','log');
                    else
                        set(h,'yscale','linear');
                    end
                else
                    set(h,'yscale','linear');
                end
            end

            grid on;
            grid minor;
        end
    end
end


function [h, T2] = ft_plot_slice(dat, varargin)

% FT_PLOT_SLICE plots a 2-D cut through a 3-D volume and interpolates if needed
%
% Use as
%   ft_plot_slice(dat, ...)
% or
%   ft_plot_slice(dat, mask, ...)
% where dat and mask are equal-sized 3-D arrays.
%
% Additional options should be specified in key-value pairs and can be
%   'transform'    = 4x4 homogeneous transformation matrix specifying the mapping from
%                    voxel coordinates to the coordinate system in which the data are plotted.
%   'location'     = 1x3 vector specifying a point on the plane which will be plotted
%                    the coordinates are expressed in the coordinate system in which the
%                    data will be plotted. location defines the origin of the plane
%   'orientation'  = 1x3 vector specifying the direction orthogonal through the plane
%                    which will be plotted (default = [0 0 1])
%   'unit'         = string, can be 'm', 'cm' or 'mm (default is automatic)
%   'resolution'   = number (default = 1 mm)
%   'datmask'      = 3D-matrix with the same size as the data matrix, serving as opacitymap
%                    If the second input argument to the function contains a matrix, this
%                    will be used as the mask
%   'maskstyle'    = string, 'opacity' or 'colormix', defines the rendering
%   'background'   = needed when maskstyle is 'colormix', 3D-matrix with
%                    the same size as the data matrix, serving as
%                    grayscale image that provides the background
%   'opacitylim'   = 1x2 vector specifying the limits for opacity masking
%   'interpmethod' = string specifying the method for the interpolation, see INTERPN (default = 'nearest')
%   'style'        = string, 'flat' or '3D'
%   'colormap'     = string, see COLORMAP
%   'clim'         = 1x2 vector specifying the min and max for the colorscale
%
% You can plot the slices from the volume together with an intersection of the slices
% with a triangulated surface mesh (e.g. a cortical sheet) using
%   'intersectmesh'       = triangulated mesh, see FT_PREPARE_MESH
%   'intersectcolor'      = string, color specification
%   'intersectlinestyle'  = string, line specification
%   'intersectlinewidth'  = number
%
% See also FT_PLOT_ORTHO, FT_PLOT_MONTAGE, FT_SOURCEPLOT

% Undocumented options
%   'plotmarker'     = Nx3 matrix with points to be plotted as markers, e.g. dipole positions
%   'markersize'
%   'markercolor'

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

persistent dim X Y Z

if isequal(dim, size(dat(:,:,:,1,1)))
  % reuse the persistent variables to speed up subsequent calls with the same input
else
  dim       = size(dat);
  [X, Y, Z] = ndgrid(1:dim(1), 1:dim(2), 1:dim(3));
end

% parse first input argument(s). it is either
% (dat, varargin)
% (dat, msk, varargin)
% (dat, [], varargin)
if numel(varargin)>0 && (isempty(varargin{1}) || isnumeric(varargin{1}) || islogical(varargin{1}))
  msk      = varargin{1};
  varargin = varargin(2:end);
end

% get the optional input arguments
transform           = ft_getopt(varargin, 'transform', eye(4));
loc                 = ft_getopt(varargin, 'location');
ori                 = ft_getopt(varargin, 'orientation', [0 0 1]);
unit                = ft_getopt(varargin, 'unit');       % the default will be determined further down
resolution          = ft_getopt(varargin, 'resolution'); % the default depends on the units and will be determined further down
datmask             = ft_getopt(varargin, 'datmask');
maskstyle           = ft_getopt(varargin, 'maskstyle', 'opacity');
background          = ft_getopt(varargin, 'background');
opacitylim          = ft_getopt(varargin, 'opacitylim');
interpmethod        = ft_getopt(varargin, 'interpmethod', 'nearest');
cmap                = ft_getopt(varargin, 'colormap');
clim                = ft_getopt(varargin, 'clim');
doscale             = ft_getopt(varargin, 'doscale', true); % only scale when necessary (time consuming), i.e. when plotting as grayscale image & when the values are not between 0 and 1
h                   = ft_getopt(varargin, 'surfhandle', []);

mesh                = ft_getopt(varargin, 'intersectmesh');
intersectcolor      = ft_getopt(varargin, 'intersectcolor', 'yrgbmyrgbm');
intersectlinewidth  = ft_getopt(varargin, 'intersectlinewidth', 2);
intersectlinestyle  = ft_getopt(varargin, 'intersectlinestyle');

plotmarker          = ft_getopt(varargin, 'plotmarker');
markersize          = ft_getopt(varargin, 'markersize', 'auto');
markercolor         = ft_getopt(varargin, 'markercolor', 'w');

% convert from yes/no/true/false/0/1 into a proper boolean
doscale = istrue(doscale);

if ~isa(dat, 'double')
  dat = cast(dat, 'double');
end

if exist('msk', 'var') && isempty(datmask)
  ft_warning('using the second input argument as mask rather than the one from the varargin list');
  datmask = msk; clear msk;
end

% normalise the orientation vector to one
ori = ori./sqrt(sum(ori.^2));

% set the default location
if isempty(loc) && (isempty(transform) || isequal(transform, eye(4)))
  loc = (dim+1)./2;
elseif isempty(loc)
  loc = [0 0 0];
end

% shift the location to be along the orientation vector
loc = ori*dot(loc,ori);

% it should be a cell-array
if isstruct(mesh)
  tmp = mesh;
  mesh = cell(size(tmp));
  for i=1:numel(tmp)
    mesh{i} = tmp(i);
  end
elseif iscell(mesh)
  % do nothing
else
  mesh = {};
end

% replace pnt by pos
for k = 1:numel(mesh)
  mesh{k} = fixpos(mesh{k});
end

dointersect = ~isempty(mesh);
if dointersect
  for k = 1:numel(mesh)
    if ~isfield(mesh{k}, 'pos') || ~isfield(mesh{k}, 'tri')
      % ft_error('the mesh should be a structure with pos and tri');
      mesh{k}.pos = [];
      mesh{k}.tri = [];
    end
  end
end

% check whether the mask is ok
domask = ~isempty(datmask);
if domask
  if ~isequal(size(dat), size(datmask)) && ~isequal(cmap, 'rgb')
    % the exception is when the functional data is to be interpreted as rgb
    ft_error('the mask data should have the same dimensions as the functional data');
  end
end

dobackground = ~isempty(background);
if dobackground
  if ~isequal(size(dat), size(background))
    error('the background data should have the same dimensions as the functional data');
  end
end

% determine the voxel center
% voxel_center_vc = [X(:) Y(:) Z(:)];
% voxel_center_hc = ft_warp_apply(transform, voxel_center_vc);

% determine the edges, i.e. the corner points of each voxel
% [Xe, Ye, Ze] = ndgrid(0:dim(1), 0:dim(2), 0:dim(3));
% Xe = Xe+0.5;
% Ye = Ye+0.5;
% Ze = Ze+0.5;
% voxel_edge_vc = [Xe(:) Ye(:) Ze(:)];
% voxel_edge_hc = ft_warp_apply(transform, voxel_edge_vc);

% determine the corner points of the box encompassing the whole data block
% extend the box with half a voxel  in all directions to get the outer edge
corner_vc = [
  0.5        0.5        0.5
  0.5+dim(1) 0.5        0.5
  0.5+dim(1) 0.5+dim(2) 0.5
  0.5        0.5+dim(2) 0.5
  0.5        0.5        0.5+dim(3)
  0.5+dim(1) 0.5        0.5+dim(3)
  0.5+dim(1) 0.5+dim(2) 0.5+dim(3)
  0.5        0.5+dim(2) 0.5+dim(3)
  ];
corner_hc = ft_warp_apply(transform, corner_vc);

if isempty(unit)
  if ~isequal(transform, eye(4))
    % estimate the geometrical units we are dealing with
    unit = ft_estimate_units(norm(range(corner_hc)));
  else
    % units are in voxels, these are assumed to be close to mm
    unit = 'mm';
  end
end
if isempty(resolution)
  % the default resolution is 1 mm
  resolution = ft_scalingfactor('mm', unit);
end

% determine whether interpolation is needed
dointerp = false;
dointerp = dointerp || sum(sum(transform-eye(4)))~=0;
dointerp = dointerp || ~all(round(loc)==loc);
dointerp = dointerp || sum(ori)~=1;
dointerp = dointerp || ~(resolution==round(resolution));
% determine the caller function and toggle dointerp to true, if ft_plot_slice has been called from ft_plot_montage
% this is necessary for the correct allocation of the persistent variables
st = dbstack;
if ~dointerp && numel(st)>1 && strcmp(st(2).name, 'ft_plot_montage'), dointerp = true; end

% define 'x' and 'y' axis in projection plane, the definition of x and y is more or less arbitrary
[x, y] = projplane(ori);
% z = ori;

% project the corner points onto the projection plane
corner_pc = zeros(size(corner_hc));
for i=1:8
  corner   = corner_hc(i, :) - loc(:)';
  corner_pc(i,1) = dot(corner, x);
  corner_pc(i,2) = dot(corner, y);
  corner_pc(i,3) = 0;
end

% get the transformation matrix from the projection plane to head coordinates
T2 = [x(:) y(:) ori(:) loc(:); 0 0 0 1];

% get the transformation matrix from projection plane to voxel coordinates
T3 = transform\T2;

min_corner_pc = min(corner_pc, [], 1);
max_corner_pc = max(corner_pc, [], 1);
% round the bounding box limits to the nearest mm
switch unit
  case 'm'
    min_corner_pc = ceil(min_corner_pc*100)/100;
    max_corner_pc = floor(max_corner_pc*100)/100;
  case 'cm'
    min_corner_pc = ceil(min_corner_pc*10)/10;
    max_corner_pc = floor(max_corner_pc*10)/10;
  case 'mm'
    min_corner_pc = ceil(min_corner_pc);
    max_corner_pc = floor(max_corner_pc);
end

% determine a grid of points in the projection plane
xplane = min_corner_pc(1):resolution:max_corner_pc(1);
yplane = min_corner_pc(2):resolution:max_corner_pc(2);
zplane = 0;
[Xi, Yi, Zi]      = ndgrid(xplane, yplane, zplane);
siz               = [size(squeeze(Xi)) size(dat,4)];
interp_center_pc  = [Xi(:) Yi(:) Zi(:)];
% interp_center_hc = ft_warp_apply(T2, interp_center_pc);

% get the positions of the points in the projection plane in voxel coordinates
interp_center_vc = ft_warp_apply(T3, interp_center_pc);

Xi = reshape(interp_center_vc(:, 1), siz(1:2));
Yi = reshape(interp_center_vc(:, 2), siz(1:2));
Zi = reshape(interp_center_vc(:, 3), siz(1:2));

% check whether the values in the axes are close enough to integer
tol = nanmean([diff(unique(Xi(:)));diff(unique(Yi(:)))])./100;
isintegerXi = issufficientlyinteger(Xi(:),tol);
isintegerYi = issufficientlyinteger(Yi(:),tol);
isintegerZi = issufficientlyinteger(Zi(:),tol);

% check whether it's possible to select an orthogonal plane
[islineXi, lineXi] = isline(Xi);
[islineYi, lineYi] = isline(Yi);
[islineZi, lineZi] = isline(Zi);

use_interpn = ~isequal(transform, eye(4)) || ~isequal(interpmethod, 'nearest') || ~all([isintegerXi isintegerYi isintegerZi]);
get_slice   = ~use_interpn && all([islineXi islineYi islineZi]) && all([isintegerXi isintegerYi isintegerZi]);
if use_interpn
  V  = interpn(X, Y, Z, dat, Xi, Yi, Zi, interpmethod);
  if domask,       Vmask = interpn(X, Y, Z, datmask,       Xi, Yi, Zi, interpmethod); end
  if dobackground, Vback = interpn(X, Y, Z, background, Xi, Yi, Zi, interpmethod); end
elseif get_slice
  %something more efficient than an interpolation can be done
  % just select the appropriate plane, and permute to get the orientation
  % right in the plots, something to do with ndgrid vs meshgrid I think
  permutevec = [2 1];
  if ndims(dat)>3
    permutevec = [permutevec 3:ndims(dat)];
  end
  if numel(unique(lineXi(:)))==1
    lineXi = lineXi(1);
  elseif numel(unique(lineYi(:)))==1
    lineYi = lineYi(1);
  elseif numel(unique(lineZi(:)))==1
    lineZi = lineZi(1);
  end
  V = permute(reshape(dat(lineXi,lineYi,lineZi,:), siz(permutevec(1:ndims(dat)-1))), permutevec);
  if domask,       Vmask = permute(reshape(datmask(lineXi,lineYi,lineZi,:),       siz(permutevec(1:2))), [2 1]); end
  if dobackground, Vback = permute(reshape(background(lineXi,lineYi,lineZi,:), siz(permutevec(1:2))), [2 1]); end
else
  % use sub2ind in the unlikely case that it's an oblique plane, parallel
  % to one of the axes with only integer indices
  % this fails for rgb data
  V = dat(sub2ind(dim, Xi(:), Yi(:), Zi(:)));
  V = reshape(V, siz);
end

if all(isnan(V(:)))
  % the projection plane lies completely outside the box spanned by the data
else
  % trim the edges of the projection plane
  [sel1, sel2] = tight(V(:,:,1));
  V  = V (sel1,sel2,:);
  Xi = Xi(sel1,sel2);
  Yi = Yi(sel1,sel2);
  Zi = Zi(sel1,sel2);
  if domask
    Vmask = Vmask(sel1,sel2);
  end
  if dobackground
    Vback = Vback(sel1,sel2);
  end
end

if dobackground
  % convert the background plane to a grayscale image
  bmin  = nanmin(background(:));
  bmax  = nanmax(background(:));
  Vback = (Vback-bmin)./(bmax-bmin);
  Vback(~isfinite(Vback)) = 0;
  Vback = cat(3, Vback, Vback, Vback);
end

interp_center_vc = [Xi(:) Yi(:) Zi(:)]; clear Xi Yi Zi
interp_center_pc = ft_warp_apply(inv(T3), interp_center_vc);

% determine a grid of points in the projection plane
% this reconstruction is needed since the edges may have been trimmed off
xplane = min(interp_center_pc(:, 1)):resolution:max(interp_center_pc(:, 1));
yplane = min(interp_center_pc(:, 2)):resolution:max(interp_center_pc(:, 2));
zplane = 0;

[Xi, Yi, Zi] = ndgrid(xplane, yplane, zplane); % 2D cartesian grid of projection plane in plane voxels
siz          = size(squeeze(Xi));

% extend with one voxel along dim 1
Xi = cat(1, Xi, Xi(end,:)+mean(diff(Xi,[],1),1));
Yi = cat(1, Yi, Yi(end,:)+mean(diff(Yi,[],1),1));
Zi = cat(1, Zi, Zi(end,:)+mean(diff(Zi,[],1),1));
% extend with one voxel along dim 2
Xi = cat(2, Xi, Xi(:,end)+mean(diff(Xi,[],2),2));
Yi = cat(2, Yi, Yi(:,end)+mean(diff(Yi,[],2),2));
Zi = cat(2, Zi, Zi(:,end)+mean(diff(Zi,[],2),2));
% shift with half a voxel along dim 1 and 2
Xi = Xi-0.5*resolution;
Yi = Yi-0.5*resolution;
% Zi = Zi; % do not shift along this direction

interp_edge_pc = [Xi(:) Yi(:) Zi(:)]; clear Xi Yi Zi
interp_edge_hc = ft_warp_apply(T2, interp_edge_pc);

if false
  % plot all objects in head coordinates
  ft_plot_mesh(voxel_center_hc,   'vertexmarker', 'o')
  ft_plot_mesh(voxel_edge_hc,     'vertexmarker', '+')
  ft_plot_mesh(corner_hc,         'vertexmarker', '*')
  ft_plot_mesh(interp_center_hc,  'vertexmarker', 'o', 'vertexcolor', 'r')
  ft_plot_mesh(interp_edge_hc,    'vertexmarker', '+', 'vertexcolor', 'r')
  axis on
  grid on
  xlabel('x')
  ylabel('y')
  zlabel('z')
end

if isempty(cmap)
  % treat as gray value: scale and convert to rgb
  if doscale
    dmin = min(dat(:));
    dmax = max(dat(:));
    V    = (V-dmin)./(dmax-dmin);
    clear dmin dmax
  end
  V(~isfinite(V)) = 0;

  % deal with clim for RGB data here, where the purpose is to increase the
  % contrast range, rather than shift the average grey value
  if ~isempty(clim)
    V = (V-clim(1))./clim(2);
    V(V>1)=1;
  end

  % convert into RGB values, e.g. for the plotting of anatomy
  V = cat(3, V, V, V);
end

% get positions of the voxels in the interpolation plane in head coordinates
Xh = reshape(interp_edge_hc(:,1), siz+1);
Yh = reshape(interp_edge_hc(:,2), siz+1);
Zh = reshape(interp_edge_hc(:,3), siz+1);

% do the actual plotting of the slice
if ~domask
  % no masked slice to be plotted
  if isempty(h)
    % create surface object
    h = surface(Xh, Yh, Zh, V);
    set(h, 'linestyle', 'none');
  else
    % update the colordata in the surface object
    set(h, 'Cdata', V);
    set(h, 'Xdata', Xh);
    set(h, 'Ydata', Yh);
    set(h, 'Zdata', Zh);
  end
elseif domask
  % what should be done depends on the maskstyle
  switch maskstyle
    case 'opacity'
      if dobackground
        ft_warning('specifying maskstyle = ''opacity'' causes the supplied background image not to be used');
      end
      if isempty(h)
        % create surface object
        h = surface(Xh, Yh, Zh, V);
        set(h, 'linestyle', 'none');
      else
        % update the colordata in the surface object
        set(h, 'Cdata', V);
        set(h, 'Xdata', Xh);
        set(h, 'Ydata', Yh);
        set(h, 'Zdata', Zh);
      end
      if islogical(Vmask), Vmask = double(Vmask); end
      set(h, 'FaceColor', 'texture');
      set(h, 'FaceAlpha', 'texturemap'); %flat
      set(h, 'AlphaDataMapping', 'scaled');
      set(h, 'AlphaData', Vmask);
      if ~isempty(opacitylim)
        alim(opacitylim)
      end

    case 'colormix'
      if isempty(cmap), error('using ''colormix'' as maskstyle requires an explicitly defined colormap'); end
      V = bg_rgba2rgb(Vback,V,cmap,clim,Vmask,'rampup',opacitylim);
      if isempty(h)
        % create surface object
        h = surface(Xh, Yh, Zh, V);
        set(h, 'linestyle', 'none');
      else
        % update the colordata in the surface object
        set(h, 'Cdata', V);
        set(h, 'Xdata', Xh);
        set(h, 'Ydata', Yh);
        set(h, 'Zdata', Zh);
      end
  otherwise
    error('unsupported maskstyle');
  end
end

% plot the intersection with a mesh
if dointersect
  % determine three points on the plane
  inplane = eye(3) - (eye(3) * ori') * ori;
  v1 = loc + inplane(1,:);
  v2 = loc + inplane(2,:);
  v3 = loc + inplane(3,:);

  for k = 1:numel(mesh)
    [xmesh, ymesh, zmesh] = intersect_plane(mesh{k}.pos, mesh{k}.tri, v1, v2, v3);

    % draw each individual line segment of the intersection
    if ~isempty(xmesh)
      p = patch(xmesh', ymesh', zmesh', nan(1, size(xmesh,1)));
      if ~isempty(intersectcolor),     set(p, 'EdgeColor', intersectcolor(k)); end
      if ~isempty(intersectlinewidth), set(p, 'LineWidth', intersectlinewidth); end
      if ~isempty(intersectlinestyle), set(p, 'LineStyle', intersectlinestyle); end
    end
  end
end

if ~isempty(cmap) && ~isequal(cmap, 'rgb')
  colormap(cmap);
  if ~isempty(clim)
    caxis(clim);
  end
end

if ~isempty(plotmarker)
  % determine three points on the plane
  inplane = eye(3) - (eye(3) * ori') * ori;
  v1 = loc + inplane(1,:);
  v2 = loc + inplane(2,:);
  v3 = loc + inplane(3,:);
  pr = nan(size(plotmarker,1), 3);
  d  = nan(size(plotmarker,1), 1);
  for k = 1:size(plotmarker,1)
    [pr(k,:), d(k,:)] = ptriprojn(v1, v2, v3, plotmarker(k,:));
  end
  sel = d<eps*1e8;
  if sum(sel)>0
    ft_plot_dipole(pr(sel,:), repmat([0;0;1], 1, size(pr,1)), 'length', 0, 'color', markercolor, 'diameter', markersize);
  end
end

% update the axes to ensure that the whole volume fits
ax = [min(corner_hc) max(corner_hc)];
axis(ax([1 4 2 5 3 6])); % reorder into [xmin xmax ymin ymaz zmin zmax]

st = dbstack;
if numel(st)>1
  % ft_plot_slice has been called from another function
  % assume the remainder of the axis settings to be handled there
else
  set(gca,'xlim',[min(Xh(:))-0.5*resolution max(Xh(:))+0.5*resolution]);
  set(gca,'ylim',[min(Yh(:))-0.5*resolution max(Yh(:))+0.5*resolution]);
  set(gca,'zlim',[min(Zh(:))-0.5*resolution max(Zh(:))+0.5*resolution]);

  set(gca,'dataaspectratio',[1 1 1]);
  % axis equal; % this for some reason does not work robustly when drawing intersections, replaced by the above
  axis vis3d
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [x, y] = projplane(z)
[u, s, v] = svd([eye(3) z(:)]);
x = u(:, 2)';
y = u(:, 3)';

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [sel1, sel2] = tight(V)
% make a selection to cut off the nans at the edges
sel1 = sum(~isfinite(V), 2)<size(V, 2);
sel2 = sum(~isfinite(V), 1)<size(V, 1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function bool = issufficientlyinteger(X, tolerance)
%isinteger only checks for integer class, so will always return false with
%double integers
bool = all(abs(X-round(X))<tolerance);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [bool, lineX] = isline(X)
%isline returns an array of the values in X are columnwise or rowwise the
%same, otherwise returns false
if isequal(X(ones(1,size(X,1)),:),X)
  lineX = X(1,:);
  bool = true;
elseif isequal(X(:,ones(1,size(X,2))),X)
  lineX = X(:,1)';
  bool = true;
else
  lineX = [];
  bool = false;
end


% POP_ICATHRESH - main menu for choosing threshold for component
%                      rejection in EEGLAB.
%
% Usage:
%   >> [OUTEEG rej] = pop_icathresh(INEEG, threshval, rejmethod,
%                                      rejvalue, interact);
%
% Inputs:
%   INEEG      - input dataset
%   threshval  - values of thresholds for each of the 3 statistical
%                measures. Default is [] and the program uses the value
%                in the dataset.
%   rejmethod  - either 'percent', 'dataset' or 'current'. 'percent'
%                will reject a given percentage of components with
%                the highest value in one or several statistical
%                measure. 'dataset' will use an other dataset for
%                calibration. 'current' will use the current dataset
%                for calibration. Default is 'current'.
%   rejvalue   - percentage if rejmethod is 'percent', dataset number
%                if rejmethod is 'dataset' (no input if 'current'). If it
%                is a percentage, '25' for instance means that the 25%
%                independent components with the highest values of one
%                statistical measure are  rejected. Note that, one can
%                also enter one percentage per statistical value (such as
%                25 20 30).
%   interact   - interactive windows or just rejection
%
% Inputs:
%   OUTEEG     - output dataset with updated thresholds
%   rej        - new rejection array
%
% Graphic interface:
%   The graphic interface is divided into 3 parts. On the top, the
% experimenter chooses the basis for the component rejection (see
% rejmethod input). On the middle panel, the user can tune thresholds
% manually and plot the distribution of statistical values. Each time
% that setting of one of these two top panels is modified, the curve
% on the third panel are redrawn.
%   The third panel is composed of 3 graphs, one for each statistical
% measure. The blue curve on each graph indicates the accuracy of the
% measure to detect artifactual components and non-artifactual
% components of a dataset. Note that 'artifactual components are
% defined with the rejection methods fields on the top (if you use
% the percentage methods, these artifactual components may not actually
% be artifactual). For accurate rejection, one should first reject
% artifactual component manually and then set up the threshold to
% approximate this manual rejection. The green curve indicate the
% rejection when all measure are considered. Points on the blue and
% on the green curves indicate the position of the current threshold on
% the parametric curve. Not that for the green cumulative curve, this
% point is at the same location for all graphs.
%   How to tune the threshold? To tune the threshold, one should try to
% maximize the detection of non-artifactual components (because it is
% preferable to miss some artifactual components than to classify as
% artifactual non-artifact components).
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: EEGLAB

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

%PROBLEM: when the % is set and we change manually the threshold,
% the software comes back to the percentage rejection

% 01-25-02 reformated help & license -ad

function [EEG, rej, com] = pop_icathresh( EEG, threshval, rejmethod, rejvalue, interact);

com = [];
rej = EEG.reject.gcompreject;
if nargin < 1
	help pop_icathresh;
	return;
end

if nargin < 2
	threshval = [];
end
if nargin < 3
	rejmethod = 'current';
end
if nargin < 4
	rejvalue = 25;
end
if nargin < 5
	interact = 1;
end
if ~isempty(threshval)
	EEG.reject.threshentropy = threshval(1);
	EEG.reject.threshkurtact = threshval(2);
	EEG.reject.threshkurtdist = threshval(3);
end

tagmenu = 'pop_icathresh';

if ~isempty( findobj('tag', tagmenu))
	error('cannot open two identical windows, close the first one first');
end

% the current rejection will be stored in userdata of the figure
% --------------------------------------------------------------
gcf = figure('visible', 'off', 'numbertitle', 'off', 'name', 'Choose thresholds', 'tag', tagmenu, 'userdata', rej);
pos = get(gca, 'position');
q = [pos(1) pos(2) 0 0];
s = [pos(3) pos(4) pos(3) pos(4)]./100;
axis off;

% definition of callbacks
% -----------------------

cb_cancel  = [  'userdat = get(gcbo, ''userdata'');' ... % restore thresholds
				'EEG.reject.threshentropy  = userdat{1};' ...
				'EEG.reject.threshkurtact  = userdat{2};' ...
				'EEG.reject.threshkurtdist = userdat{3};' ...
				'clear userdat; close(gcbf);' ];

drawgraphs  = [ 'if isempty( gcbf ), fig = gcf; else fig = gcbf; end;' ... % determine the figure handler
                'if get( findobj(''parent'', fig, ''tag'', ''Ipercent''), ''value'') == 1, ' ... % test if percentage
				'   perc = str2num(get( findobj(''parent'', fig, ''tag'', ''Ipercenttext''), ''String''));' ...
				'   if length(perc < 2), perc = [perc perc perc]; end;' ...
				'   perc = round((100-perc) * length( EEG.stats.compenta) / 100);' ... % convert the percentage
				'   method = zeros( size( EEG.stats.compenta ) );' ...
				'   [tmprej tmpindex] = sort(EEG.stats.compenta(:));' ...
				'   method( tmpindex(perc(1)+1:end) ) = 1;' ...
				'   set( findobj(''parent'', fig, ''tag'', ''entstring''), ''string'', num2str(tmprej(perc(1)+1)));' ... % update threshold
				'   [tmprej tmpindex] = sort(EEG.stats.compkurta(:));' ...
				'   method( tmpindex(perc(2)+1:end) ) = 1;' ...
				'   set( findobj(''parent'', fig, ''tag'', ''kurtstring''), ''string'', num2str(tmprej(perc(1)+1)));' ... % update threshold
				'   [tmprej tmpindex] = sort(EEG.stats.compkurtdist(:));' ...
				'   method( tmpindex(perc(3)+1:end) ) = 1;' ...
				'   set( findobj(''parent'', fig, ''tag'', ''kurtdiststring''), ''string'', num2str(tmprej(perc(1)+1)));' ... % update threshold
				'   allvalues = [EEG.stats.compenta(:) EEG.stats.compkurta(:) EEG.stats.compkurtdist(:) ];' ...
				'   clear perc tmprej tmpindex;' ...
                'end;' ...
				'if get( findobj(''parent'', fig, ''tag'', ''Iother''), ''value'') == 1, ' ... % test if other dataset
				'   di = str2num(get( findobj(''parent'', fig, ''tag'', ''Iothertext''), ''String''));' ...
				'   if isempty( di ), clear fig; return; end;' ...
				'   method    = ALLEEG(di).reject.gcompreject'';' ...
				'   allvalues = [ALLEEG(di).stats.compenta(:) ALLEEG(di).stats.compkurta(:) ALLEEG(di).stats.compkurtdist(:) ];' ...
				'   clear di;' ...
                'end;' ...
				'if get( findobj(''parent'', fig, ''tag'', ''Icurrent''), ''value'') == 1, ' ... % test if current dataset
				'   method = EEG.reject.gcompreject'';' ...
				'   allvalues = [EEG.stats.compenta(:) EEG.stats.compkurta(:) EEG.stats.compkurtdist(:) ];' ...
                'end;' ...
				'axes( findobj( ''parent'', fig, ''tag'', ''graphent'')); cla;' ...
                '[tmp1 tmp2 tmp3] = drawproba( method, allvalues, [0 EEG.reject.threshkurtact EEG.reject.threshkurtdist ], ' ...
				'   { ''&'' ''|'' }, EEG.reject.threshentropy, ''Entropy of activity'',''Artifact detection (%)'', ''Non-artifact detection (%)'');' ...
				'set(gca, ''tag'', ''graphent'');' ...
				'axes( findobj( ''parent'', fig, ''tag'', ''graphkurt'')); cla;' ...
                '[tmp1 tmp2 tmp3] = drawproba( method, allvalues, [EEG.reject.threshentropy 0 EEG.reject.threshkurtdist ], ' ...
				'   { ''&'' ''|'' }, EEG.reject.threshkurtact, ''Kurtosis of activity'', ''Artifact detection (%)'', '''');' ...
				'set(gca, ''tag'', ''graphkurt'');' ...
				'axes( findobj( ''parent'', fig, ''tag'', ''graphkurtdist'')); cla;' ...
                '[tmp1 tmp2 tmp3] = drawproba( method, allvalues, [EEG.reject.threshentropy EEG.reject.threshkurtact 0 ], ' ...
				'   { ''&'' ''|'' }, EEG.reject.threshkurtdist, ''Kurtosis of topography'', ''Artifact detection (%)'', '''');' ...
				'set(gca, ''tag'', ''graphkurtdist'');' ...
				'clear method allvalues fig;' ...
				];

cb_percent = [  'if isempty( gcbf ), fig = gcf; else fig = gcbf; end;' ... % determine the figure handler
                'set( findobj(''parent'', fig, ''tag'', ''Ipercent''), ''value'', 1);'...
				'set( findobj(''parent'', fig, ''tag'', ''Iother''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Icurrent''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Ipercenttext''), ''enable'', ''on'');' ...
				'set( findobj(''parent'', fig, ''tag'', ''Iothertext''), ''enable'', ''off''); clear fig;' drawgraphs ];

cb_other   = [  'if isempty( gcbf ), fig = gcf; else fig = gcbf; end;' ... % determine the figure handler
                'set( findobj(''parent'', fig, ''tag'', ''Iother''), ''value'', 1);'...
				'set( findobj(''parent'', fig, ''tag'', ''Ipercent''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Icurrent''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Ipercenttext''), ''enable'', ''off'');' ...
				'set( findobj(''parent'', fig, ''tag'', ''Iothertext''), ''enable'', ''on''); clear fig;' drawgraphs ];

cb_current = [  'if isempty( gcbf ), fig = gcf; else fig = gcbf; end;' ... % determine the figure handler
                'set( findobj(''parent'', fig, ''tag'', ''Icurrent''), ''value'', 1);'...
				'set( findobj(''parent'', fig, ''tag'', ''Iother''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Ipercent''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Ipercenttext''), ''enable'', ''off'');' ...
				'set( findobj(''parent'', fig, ''tag'', ''Iothertext''), ''enable'', ''off''); clear fig;' drawgraphs ];

cb_entropy  = [ 'EEG.reject.threshentropy = str2num(get(gcbo, ''string''));' ...
				drawgraphs ];
cb_kurtact  = [ 'EEG.reject.threshkurtact = str2num(get(gcbo, ''string''));' ...
				drawgraphs ];
cb_kurtdist  = [ 'EEG.reject.threshkurtdist = str2num(get(gcbo, ''string''));' ...
				drawgraphs ];

if interact
	cb_calrej = [ 'ButtonName=questdlg2( ''This will erase previous projections'', ''Confirmation'', ''CANCEL'', ''OK'', ''OK'');' ]
else
	cb_calrej = [ 'ButtonName= ''OK''' ];
end
cb_calrej = [ cb_calrej ...
    		  'switch ButtonName,' ...
       	 	  '   case ''OK'',' ...
			  '    rej1 = find(EEG.stats.compenta > EEG.reject.threshentropy);' ...
			  '    rej2 = find(EEG.stats.compkurta > EEG.reject.threshkurtact);' ...
			  '    rej3 = find(EEG.stats.compkurtdist > EEG.reject.threshkurtdist);' ...
			  '    EEG.reject.gcompreject = (rej1 & rej2) | rej3;' ...
			  '    clear rej1 rej2 rej3;' ...
			  'end; clear ButtonName;' ];

% default value for rejection methods
% -----------------------------------
rejvalother = '';
rejvalpercent = '25';
switch rejmethod
	case 'percent', rejvalpercent = num2str( rejvalue);
	case 'dataset', rejvalother = num2str( rejvalue);
end

% -----------------------------------------------------
allh = supergui(gcf, { 	[1] ...
					[2 1] [2 1] [2 1] ...
					[1] ...
					[1] ...
					[1.5 0.5 1] [1.5 0.5 1] [1.5 0.5 1] ...
					[1] [1] [1] [1] [1] [1] [1] [1] [1] [1] ...
					[1 1 1 1 1] ...
					}, [], ...
	{ 'Style', 'text', 'string', 'Calibration method', 'FontSize', 13, 'fontweight', 'bold' }, ...
	...
	{ 'style', 'checkbox', 'String', '% of artifactual components (can also put one % per rejection)', 'tag', 'Ipercent', 'value', 1, 'callback', cb_percent}, ...
	{ 'style', 'edit', 'String', rejvalpercent, 'tag', 'Ipercenttext', 'callback', drawgraphs }, ...
	...
	{ 'style', 'checkbox', 'String', 'Specific dataset (enter dataset number)', 'tag', 'Iother', 'value', 0, 'callback', cb_other}, ...
	{ 'style', 'edit', 'String', rejvalother, 'tag', 'Iothertext', 'enable', 'off', 'callback', drawgraphs }, ...
	...
	{ 'style', 'checkbox', 'String', 'Current dataset', 'tag', 'Icurrent', 'value', 0, 'callback', cb_current}, ...
	{ }, ...
	...
	{ }, ...
	...
	{ 'Style', 'text', 'string', 'Threshold values', 'FontSize', 13, 'fontweight', 'bold' }, ...
	...
	{ 'style', 'text', 'String', 'Entropy of activity threshold' }, ...
	{ 'style', 'edit', 'String', num2str(EEG.reject.threshentropy), 'tag', 'entstring', 'callback',  cb_entropy }, ...
	{ 'style', 'pushbutton', 'String', 'Histogram', 'callback', 'figure; hist(EEG.stats.compenta,20); title(''Entropy of activity'');' }, ...
	...
	{ 'style', 'text', 'String', 'Kurtosis of activity threshold' }, ...
	{ 'style', 'edit', 'String', num2str(EEG.reject.threshkurtact), 'tag', 'kurtstring', 'callback', cb_kurtact }, ...
	{ 'style', 'pushbutton', 'String', 'Histogram', 'callback', 'figure; hist(EEG.stats.compkurta,200); title(''Kurtosis of activity'');' },  ...
	...
	{ 'style', 'text', 'String', 'Kurtosis of topography threshold' }, ...
	{ 'style', 'edit', 'String', num2str(EEG.reject.threshkurtdist), 'tag', 'kurtdiststring', 'callback', cb_kurtdist }, ...
	{ 'style', 'pushbutton', 'String', 'Histogram', 'callback', 'figure; hist(EEG.stats.compkurtdist,20); title(''Kurtosis of topography'');' }, ...
	...
	{ }, { }, { }, { }, { }, { }, { }, { }, { }, { }, ...
	...
	{ 'style', 'pushbutton', 'String', 'Cancel', 'callback', cb_cancel, 'userdata', { EEG.reject.threshentropy EEG.reject.threshkurtact EEG.reject.threshkurtdist }}, ...
	{ 'style', 'pushbutton', 'String', 'Auto thresh'  , 'callback', '', 'enable', 'off' }, ...
	{ 'style', 'pushbutton', 'String', 'Help'  , 'callback', 'pophelp(''pop_icathresh'');' }, ...
	{ 'style', 'pushbutton', 'String', 'Accept thresh.' , 'callback', 'close(gcbf);' }, ...
	{ 'style', 'pushbutton', 'String', 'Calc. rejection' , 'callback', 'close(gcbf);' } ...
	...
	);

h = axes('position', [0  15 30 30].*s+q, 'tag', 'graphent');
h = axes('position', [35 15 30 30].*s+q, 'tag', 'graphkurt');
h = axes('position', [70 15 30 30].*s+q, 'tag', 'graphkurtdist');

rejmethod
switch rejmethod
	case 'dataset', eval([ 'gcbf = [];' cb_other]);
	case 'current', eval([ 'gcbf = [];' cb_current]);
	otherwise, eval([ 'gcbf = [];' cb_percent]);
end

return;


function fiberPath = dtiFiberTensorlinePreinterp(seedPoint, dt6, faImg, voxSize, faThresh, angleThresh, ...
    stepSizeMm, wPuncture, whichAlgorithm)

% fiberPath = dtiFiberTensorlinePreinterp(seedPoint, dt6, faImg, voxSize, faThresh, angleThresh, stepSizeMm, wPuncture, whichAlgorithm)
%
% Implementation of Lazar's Tensorline algorithm. Eg:
% White Matter Tractography Using Diffusion Tensor Deflection.
% Lazar, et. al. Human Brain Mapping 18:306 321(2003).
%
%
% Can be used to find Tensorline, FACT, or TEND fiber tracing
% Choosing Algorithm using whichAlgorithm:
%   0 = TensorLine
%   1 = FACT
%   2 = TEND
%
% Step Size:
% Determines resolution of DTI grid; default is 2x2x2mm voxels
% 1. Step Size < voxel size of inputted DTI matrix.
% Algorithm is forced to reinterpolate tensors at each point (SLOW!).
% 2. Step Size > voxel size of inputted matrix
% Step Size is reinitialized to voxel size of inputted matrix.
% Algorithm uses "nearest neighbor" concept to find proper tensor
% from the inputted dt6 file
%
% RETURNS:
% fiberPath, a list of coordinates (in voxels, but may be real-valued)
% that define the fiber path.
%
% HISTORY:
%   2004.02.09 GSM (gmulye@stanford.edu) wrote it.
%   2004.02.09 GSM Minor updates, more userdefined parameters
%   2004.02.13 GSM Modified to use pre-interpolated tensors

%voxSize = [1 1 1]'; %%%FORCE SMALL VOXELS
%oneMmDt6GridSize = [145 196 131 6]; %Size of dt6 array with 1x1x1 voxels
%origDt6GridSize = size(dt6); %Size of dt6 array inputted into function
%origDt6VoxSize = (origDt6GridSize + 1) ./ oneMmDt6GridSize; %vox size of inputted array

stepSize = stepSizeMm*ones(3,1);

if all(voxSize <= stepSize)
    reinterp = 0;
else
    reinterp = 1;
end

%stepSize = stepSizeMm./voxSize; %Step size in voxels - voxSize is 3x1 column vector

% Initialize variables for tracing
% Find major direction (originalDir) of seedPoint voxel
if (reinterp == 0)
    %   voxCoords = nearestNeighbor(seedPoint,voxSize);
    voxCoords = round(seedPoint);
    dt6Tensor = dt6(voxCoords(1),voxCoords(2),voxCoords(3),1:6);
    dt6Tensor = dt6Tensor(:); %Vectorize
elseif (reinterp == 1)
    dt6Tensor = findTensor(seedPoint,dt6,voxSize);
end
[originalDir junk] = majorEigVec(dt6Tensor);
nextDir = originalDir; % Initialize to seedPoint direction
nextPosition = seedPoint; %Absolute position in voxels
fiberPath = seedPoint; % First point is seed point
fiberPath = tracer(whichAlgorithm,nextPosition,originalDir,voxSize,dt6,reinterp,faImg,faThresh,angleThresh,wPuncture,stepSize,fiberPath,1);
fiberPath = tracer(whichAlgorithm,nextPosition,originalDir,voxSize,dt6,reinterp,faImg,faThresh,angleThresh,wPuncture,stepSize,fiberPath,-1);
return;

function fiberPath = tracer(whichAlgorithm,nextPosition,nextDir,voxSize,dt6,reinterp,faImg,faThresh,angleThresh,wPuncture,stepSize,fiberPath,fwdBkwd)
%==================
% MAIN FUNCTION
%==================
%Traces fiberpath forwards and backwards
iter = 0;
done = 0;
maxIter = 1000;
imSize = size(dt6(:,:,:,1));
nextDir = fwdBkwd*nextDir;
while (~done & iter<maxIter)
    dir = nextDir; %Direction vectors are all 3x1 column vectors
    currentPosition = nextPosition; %Position coordinates are 1x3 row vectors
    if(any(currentPosition<1) | any(currentPosition>imSize))
        disp('Tracking terminated: path wandered outside image data.');
        done = 1;
    else
        % Get the FA for this voxel
        vCoord = floor(currentPosition);
        fa = faImg(vCoord(1), vCoord(2), vCoord(3));

        % check dir data is valid (we are in range)
        if (fa <= faThresh | sum(dir) == 0 | isnan(fa))
            disp(['Tracking terminated: fa=',num2str(fa)]);
            done = 1;
        else
            nextPosition = currentPosition + (stepSize'./voxSize') .*dir'; %convert stepSize to voxels
            % Find next diffusion tensor
            if (reinterp == 0)
                %voxCoords = nearestNeighbor(nextPosition,voxSize);
                voxCoords = round(nextPosition);
                if(any(voxCoords==0) | any(voxCoords>imSize) | ~any(isfinite(voxCoords)))
                    disp(['Tracking terminated: path wandered outside image']);
                    done = 1;
                    voxCoords(voxCoords==0) = 1;
                else
                    nextDt6Tensor = dt6(voxCoords(1),voxCoords(2),voxCoords(3),1:6);
                    nextDt6Tensor = nextDt6Tensor(:); %Vectorize
                end
            elseif (reinterp == 1)
                nextDt6Tensor = findTensor(nextPosition,dt6,voxSize);
            end
            % FACT direction, checked to see if angle is less than
            % threshold
            [factDir, nextTensor] = majorEigVec(nextDt6Tensor);
            [smallAngle,direction,angle] = checkAngle(dir,factDir,angleThresh);
            if (smallAngle & (direction == -1))
                factDir = -factDir;
            end
            % TEND direction
            tendDir = nextTensor*dir;
            nd = norm(tendDir);
            if(nd<=0)
                tendDir = tendDir/nd;
            else
                tendDir = NaN;
            end
            % Tensorline Algorithm
            if (whichAlgorithm == 0)
                if(tendDir==NaN)
                    disp(['Tracking terminated: tendDir = NaN']);
                    done = 1;
                else
                    if (~smallAngle) % Turning too sharp, ignore FACT vector
                        nextDir = (1-wPuncture)*dir + wPuncture*tendDir;
                    else  % Normal case: Use FACT vector
                        nextDir = fa*factDir + (1-fa)*((1-wPuncture)*dir + wPuncture*tendDir);
                    end
                end
                % FACT only
            elseif (whichAlgorithm == 1)
                if (~smallAngle) % Angle too big
                    done = 1; % End tracing due to sharp turn
                    disp(['Tracking terminated: angle (' num2str(round(angle)) ') exceeds threshold.']);
                else
                    nextDir = factDir;
                end
                % TEND only
            elseif (whichAlgorithm == 2)
                if(tendDir==NaN)
                    disp(['Tracking terminated: tendDir = NaN']);
                    done = 1;
                else
                    nextDir = tendDir;
                end
            end
            % Append to fiberpath
            if (fwdBkwd == 1)
                fiberPath = [fiberPath; nextPosition];
            elseif (fwdBkwd == -1)
                fiberPath = [nextPosition;fiberPath];
            end
        end
    end
end
return;

function dt6Tensor = findTensor(point,dt6,voxSize)
persistent initialized;
% Finds tensor interpolation at any point and return dt6 tensor
curPosMm = point.*voxSize';
if(isempty(initialized))
    dt6Tensor = dtiTensorInterp(dt6, curPosMm, voxSize', 1);
    initialized = 1;
else
    dt6Tensor = dtiTensorInterp([], curPosMm, voxSize', 1);
end
return;

function intVox = nearestNeighbor(realCoord,voxSize)
% Rounds mm input into voxel coordinates
decVox = realCoord./voxSize'; %decimal voxels is 1x3
intVox = round(decVox);
return;

function [majorDir, fullTensor] = majorEigVec(dt6Tensor)
% Finds major direction for given tensor (in 3x3 format)
fullTensor = [dt6Tensor(1) dt6Tensor(4) dt6Tensor(5); ...
        dt6Tensor(4) dt6Tensor(2) dt6Tensor(6); ...
        dt6Tensor(5) dt6Tensor(6) dt6Tensor(3)];
[eigVec,eigVal] = eig(fullTensor);
[maxVal,i] = max(max(eigVal));
majorDir = eigVec(:,i);
%majorDir = [majorDir(2) majorDir(3) majorDir(1)]';
return;

function [angleCheck, direction, angle] = checkAngle(a,b,angleThresh)
% Checks the angle between 2 vectors, returns if angle is less than thresh
% The angle between two vectors is given by acos(aDOTb/{mag(a)*mag(b)})
anglePos = 180*acos(a'*b)/pi; % In degrees; both vectors are unit vectors
angleNeg = 180*acos(-a'*b)/pi; % Angle with one vector reversed
[angle,i] = min(abs([anglePos angleNeg]));
direction = 0;
if (angle <= angleThresh)
    angleCheck = 1; % Angle is within permissable range
    if (i==2)
        direction = -1; % Use FACT vector in opposite direction
    end
else
    angleCheck = 0; % Does not pass check
end
return


% DEMO_BBCIONLINE_APPLY_LSL_STREAMING
% this is just for testing / demonstrating the streaming of EEG data using
% lsl

% set up dummy classifier
C= struct('b', 0);
C.w= randn(8*2, 1);  % 2 log-bandpower feature per channel

% setup the bbci variable to define the online processing chain
bbci= struct;
bbci.source.acquire_fcn= @bbci_acquire_lsl;

% define the dummy electrode setting
clab = {'AF5' 'AF3' 'AF1' 'AFz' 'AF2' 'AF4' 'AF6' ...
        'F5' 'F3', 'F1' 'Fz' 'F2' 'F4' 'F6' ...
        'FC7' 'FC5'};

bbci.signal.clab = clab;
% provide clab and markerstreamname to lsl acquire function
bbci.source.acquire_param = {'clab', clab, 'markerstreamname', 'MyMarkerStream'};

bbci.feature.proc= {@proc_variance, @proc_logarithm};
bbci.feature.ival= [-500 0];

bbci.classifier.C= C;

% specify file locations and logging
% bbci.log.output= 'screen&file';
% bbci.log.file= fullfile(BTB.DataDir, 'tmp\log');
bbci.source.record_signals = 0;
bbci.source.record_basename = fullfile(BTB.DataDir,'tmp\lsl_test');
bbci.quit_condition.running_time = 170;
bbci_apply(bbci);


function varargout = acos(varargin)

switch class(varargin{1})

    case 'sdpvar'
        varargout{1} = InstantiateElementWise(mfilename,varargin{:});

    case 'char'

        operator = CreateBasicOperator('decreasing','callback');
        operator.derivative = @(x)real(-((1 - x.^2).^-0.5));
        operator.inverse = @(x)cos(x);
        operator.inflection = [-inf 1 0 -1];
        operator.range = [0 pi];
        operator.domain = [-1 1];

        varargout{1} = [];
        varargout{2} = operator;
        varargout{3} = varargin{3};

    otherwise
        error(['SDPVAR/' upper(mfilename) ' called with weird argument']);
end


function kds1 = kdelsum1QPOTTS(IESM)
kd=zeros(1,8);
if IESM(2,2)==IESM(1,1);kd(1,1)=1;end;
if IESM(2,2)==IESM(1,2);kd(1,2)=1;end;
if IESM(2,2)==IESM(1,3);kd(1,3)=1;end;
if IESM(2,2)==IESM(2,3);kd(1,4)=1;end;
if IESM(2,2)==IESM(3,3);kd(1,5)=1;end;
if IESM(2,2)==IESM(3,2);kd(1,6)=1;end;
if IESM(2,2)==IESM(3,1);kd(1,7)=1;end;
if IESM(2,2)==IESM(2,1);kd(1,8)=1;end;
kds1=sum(sum(kd));

github-repos/MATLAB/Sable-mcbench-benchmarks/mcbench-benchmarks-ba13b2f0296ef49491b95e3f984c7c41fccdb6d8/34784-monte-carlo-simulation-of-two-dimensional-grain-growth-code-version-no-1-basic/Monte Carlo Simulation Q-state Potts model 2D square-lattice - microstructure/kdelsum1QPOTTS.m


function plotAlongDim(asObj,pos,plotDim)

% settings --------------
STAT_Y = 1;   % static y scale
STAT_Y_MODE = 2; % 1 scale image statistic object
                 % 2 scale from global min an max
                 % 3 manual
MANUAL_YLIM = [0,1]; % used only if STAT_Y_MODE = 3

PLOT_STD      = false;  % plot errorbars in ROI mode
DISPLAY_STATS = true;  % BETA: Print some statistics

% complex plot representations
CPLOT_MODE = 3; % 1 = magnitude and phase,
                % 2 = real and imag
                % 3 = real and imag in one window
        % ONLY MODE 3 SUPPORTED YET!!!

START_AT_ZERO = true;   % always start plots at zero point rather than first available TE

DO_NOT_USE_ROIS = false;    % ignore rois in image and always plot single pixel positions

% ----------------------

% check if we should plot ROI means rather than single pixel values
if DO_NOT_USE_ROIS || isempty(asObj.roi) || ~isvalid(asObj.roi)
    use_roi_mean = false;
else
    use_roi_mean = true;
end

% get all images in asObject
s = asObj.getAllImages;

% check validity of plotDim
sel = asObj.selection.getValueAsCell;
colDims = sort(asObj.selection.getColonDims);
if isempty(plotDim)
    fprintf('no plot dimension given\n');
    asObj.cursor.togglePlotAlongDim(false);
    return;
end
if plotDim > length(sel)
    fprintf('Selected plot dimension (%d) > number of dims (%d)\n', plotDim, length(sel));
    asObj.cursor.togglePlotAlongDim(false);
    return;
end
if plotDim == colDims(1) || plotDim == colDims(2)
    fprintf('Selected plot dimension (%d) is not allowed to be a colon dim\n', plotDim);
    asObj.cursor.togglePlotAlongDim(false);
    return;
end

% create a selection string for the current cursor position and the
% plotDimension
if use_roi_mean
    sel{colDims(1)} = ':';   % if we have a roi, get the complete images
    sel{colDims(2)} = ':';
else
    sel{colDims(1)} = num2str(pos(1));
    sel{colDims(2)} = num2str(pos(2));
end
sel{plotDim} = ':';
selStr = '';
for i = 1 : length(sel)
    selStr = [selStr,sel{i},','];
end
selStr(end) = []; % remove last comma from string
eval(['s=s(',selStr,');']); % get selection

% get selected complex part
cplxFun = asObj.complexSelect.getFunPointer;
isComplexPhasePlot = false;
if strcmp(asObj.complexSelect.getSelection,'Pha') && use_roi_mean
    isComplexPhasePlot = true; % to avoid phase wrapping problems when
                               % deriving a mean phase value of a roi, we
                               % need to keep the data complex at this
                               % point
else
    s = cplxFun(s);            % for all selections except phase, we apply
                               % the selection before possible roi summations
end

% if we want to use the ROI, derive mean within ROI area
if use_roi_mean
    remainingDims = 1:length(size(s));
    remainingDims([colDims,plotDim]) = [];
	s = permute(s,[colDims,plotDim,remainingDims]); % make colon dims the first dimensions
    s = squeeze(s);
    si = size(s);
    StDev = zeros(1, si(1,3));
    roiMask = asObj.roi.createMask;   % apply mask to all images
    s = bsxfun(@times,s,roiMask);

    % get the standart deviation
    for i = 1:1:si(1,3)
        StDev(i) = std(nonzeros(s(:,:,i)));
    end

    % derive means
    s = squeeze(sum(sum(s,1),2))/asObj.roi.getN;

    if isComplexPhasePlot
        s = cplxFun(s); % if we are dealing with a phase plot, we have to
                        % derive the phase from the mean complex value now
    end
else
    roiMask = [];
    s = squeeze(s);
end

% if this is the first call...
if isempty(asObj.UserData) ||...
        ~isfield(asObj.UserData,'plotFigHandle') ||...
        ~ishandle(asObj.UserData.plotFigHandle)||...
        ~strcmp(get(asObj.UserData.plotFigHandle,'UserData'),'plotFig')

    % create plot window below asObject
    figPos = asObj.getFigureOuterPosition;
    figPos(2) = figPos(2) - figPos(4) - 26;
    asObj.UserData.plotFigHandle = figure('OuterPosition',figPos,...
        'MenuBar','figure',...
        'ToolBar','none',...
        'UserData','plotFig',...
        'name',asObj.getFigureTitle,...
        'IntegerHandle','off',...
        'CloseRequestFcn',@(src, evnt)closeReqCb(src,asObj));
    asObj.UserData.plotAxisHandle = axes('parent',asObj.UserData.plotFigHandle);

    % lead asObj to calculate and store the global min and max
    updateGlobalRange(asObj,plotDim);

    % store current complex selection (so that we can recognize possible
    % changes later)
    asObj.UserData.cplxSelection = asObj.complexSelect.getSelection;

    % set focus to new plot figure
    figure(asObj.getFigureHandle);
end

% check, if the complex selection has changed
if ~strcmp(asObj.complexSelect.getSelection, asObj.UserData.cplxSelection)
    % if so, recalculate global minima and maxima
    updateGlobalRange(asObj,plotDim);
    asObj.UserData.cplxSelection = asObj.complexSelect.getSelection;
end

% create x ticks
if isfield(asObj.UserData,'TE')
    x = asObj.UserData.TE;
else
    N = length(s);
    x = 1 : N;
end

% set plot start x
if START_AT_ZERO
    xStart =0;
else
    xStart = x(1);
end

% get the axis handle for the plot
ah = asObj.UserData.plotAxisHandle;

% plot
if isfield(asObj.UserData,'map')
    datatipStyle = 'x';
else
    datatipStyle = 'x-';
end
if isreal(s)
    if use_roi_mean && PLOT_STD
        errorbar(x, s, StDev, datatipStyle,'parent',ah);
    else
        plot(ah,x,s,datatipStyle);
    end
    ylabel(ah,asObj.complexSelect.getSelection);
else
    % complex plot (real and imaginary part)
    cPlot(x,s,'mode',CPLOT_MODE,'parent',ah,datatipStyle);
%     cPlot(s,'x-','parent',ah);
    ylabel(ah,'real / imag    (blue / green)');
end
xlim(ah,[xStart,x(end)]);

% set ylim from global mini and maximum
if STAT_Y
    switch(STAT_Y_MODE)
        case 1
            YLIM = [asObj.statistics.getMin, asObj.statistics.getMax];
            if ~isreal(YLIM)
                YLIM(1) = min(real(YLIM(1)),imag(YLIM(1)));
                YLIM(2) = max(real(YLIM(2)),imag(YLIM(2)));
            end
        case 2
            YLIM = asObj.UserData.range;
        case 3
            YLIM = MANUAL_YLIM;
    end
    ylim(ah,YLIM);
end

% annotations
if use_roi_mean
    title(ah,sprintf('ROI mean values over dim %d',plotDim));
else
    title(ah,sprintf('Pixel %d / %d over dim %d',pos(1),pos(2),plotDim));
end

% BETA: Print some statistics
if isreal(s) && DISPLAY_STATS  % only supported for real values yet
    mi = min(s);
    ma = max(s);
    me = mean(s);
    ra = ma - mi;
    str = sprintf('\nMin  : %2.2f\nMax  : %2.2f\nRange: %2.2f\nMean : %2.2f',mi,ma,ra,me);
%     fprintf([str,'\n']);
%     text(0,YLIM(1)',str,'Parent',ah,'VerticalAlignment','bottom');
    text(0,0,str,'Parent',ah,'VerticalAlignment','bottom');
end

end

function updateGlobalRange(asObj,plotDim)
    fprintf('getting global minimum and maximum...');
    th = tic;
    all = asObj.getAllImages;

    % (BETA) isolate nonColonDim & nonPlotDim dimension...
    % The current implementation does not call this function at selection
    % changes. This can causes problems, when selection is changed.
    if(true)
        sel = asObj.selection.getValueAsCell;
        sel{plotDim} = ':';
        selStr = '';
        for i = 1 : length(sel)
            selStr = [selStr,sel{i},','];
        end
        selStr(end) = []; % remove last comma from string
        eval(['all=all(',selStr,');']); % get selection
    end

    % get selected complex part
    cplxFun = asObj.complexSelect.getFunPointer;
    all = cplxFun(all);

    if isreal(all)
        mi = min(all(:));
        ma = max(all(:));
    else
        mir = min(real(all(:)));
        mar = max(real(all(:)));

        mii = min(imag(all(:)));
        mai = max(imag(all(:)));

        mi = min(mir,mii);
        ma = max(mar,mai);
    end
    asObj.UserData.range = [mi,ma];
    fprintf('   done in %f\n',toc(th));
end

function closeReqCb(src, asObj)
    if isvalid(asObj)
        asObj.cursor.togglePlotAlongDim(false)
    end
    delete(src);
end


function eval_result=eval_holisticScencePR(predictedBbs,groundTruthBbs,thresh_iou,cls)
    % input :
    % cls : object categorys that in consideration
    % thresh_iou: iou threshold for detection with ground truth
    % ouput :
    % label_precision: measure the recall of recognition for both semantics and geometry
    % iou_recall : measure the geometric prediction recall
    % iou_precision : measure the geometric prediction precision
    if ~exist('thresh_iou','var')
        thresh_iou = [0.01,0.05:0.05:0.6,0.8:0.2:1];
    end
    if ~exist('cls','var')
        cls = {'bathtub','bed','bookshelf','box','chair','counter','desk','door','dresser','garbage_bin','lamp','monitor','night_stand','pillow','sink','sofa','table','tv','toilet'};
    end

    allOverlaps = bb3dOverlapCloseForm(predictedBbs,groundTruthBbs);
    matchpg =[];
    maxOverlaps =[];
    while sum(allOverlaps(:)>0)>0
        [os,ind] = max(allOverlaps(:));
        [i,j] = ind2sub(size(allOverlaps),ind);
        matchpg(end+1,:) =[i,j];
        maxOverlaps(end+1) = os;
        allOverlaps(i,:) =0;
        allOverlaps(:,j) =0;
    end

    iou_recall = zeros(1,length(thresh_iou));
    iou_precision = zeros(1,length(thresh_iou));
    label_precision = zeros(1,length(thresh_iou));
    label_recall = zeros(1,length(thresh_iou));
    if ~isempty(matchpg)
        for i = 1:length(thresh_iou)
            iou_match = find(maxOverlaps>thresh_iou(i));
            pclass = [predictedBbs(matchpg(iou_match,1)).classid];
            [~,gtclass] = ismember({groundTruthBbs(matchpg(iou_match,2)).classname},cls);
            if length(pclass) > 0
                pclass = double(pclass);
            end
            correctLabel = sum([pclass-gtclass]==0);
            label_precision(i) = correctLabel/length(predictedBbs);
            label_recall(i) = correctLabel/length(groundTruthBbs);
            iou_recall(i) = length(iou_match)/length(groundTruthBbs);
            iou_precision(i) = length(iou_match)/length(predictedBbs);
        end
    end
    eval_result = struct('label_precision',label_precision,'label_recall',label_recall,'iou_recall',iou_recall,'iou_precision',iou_precision);
end


%% computeTRNrisk.m
% This script does validation of vectors W acquired from training data
% (see test_bmrm.m)
%
% 27-04-11 Michal Uricar

clc;
close all; clearvars;

%% Timestamp

fprintf(1,'Started on %s\n\n', datestr(now));

%% Add path

addpath('./Functions/');
addpath('../../matlab_toolbox/mex/');

%% Select functions

load('./MAT/functions_gdisp.mat');

%%
% load config
load('./MAT/config.mat');
lbpconfig_fname = ['./MAT/exp03_lbpconfig_nImages-' config.nImages '_hop-' num2str(config.heightOfPyramid) '.mat'];
images_fname = ['./MAT/Images_nImages-' config.nImages '.mat'];
gt_fname = ['./MAT/GT_nImages-' config.nImages '.mat'];

fprintf('Loading VAL data...\n');
load(lbpconfig_fname);
load(images_fname);
load(gt_fname);
load('./results/exp03_options.mat');
S = options.S;

switch (config.nImages)
    case 'all'
        nImages = size(Images, 2);
    case 'half'
        nImages = size(Images, 2)/2;
    otherwise
        nImages = str2num(config.nImages);
end;

tic
data.lbp = lbpconfig; data.imSize = imSize; data.Images = Images; data.nImages = nImages;
options.S = S; data.Y = gt; data.options = options;
data.tmpData = getPsiMat(data, 1);
if (displacement)
    data.options.PsiG = getDisplacements(data.options);
end;
clear lbpconfig imSize Images nImages gt gt_fname images_fname lbpconfig_fname options S

% create mapTable for extracting components of W
data.mapTable = f_createMapTable(data.options, data.tmpData);
toc
fprintf('Done.\n');

%%

lambdas = [1e-2, 1e-1, 1];

% start matlabpool
try
    matlabpool;
catch ME1
    idSegLast = regexp(ME1.identifier, '(?<=:)\w+$', 'match');
    if (strcmp(idSegLast, 'OpenConnection'))
        fprintf('Already connected to matlab pool. Skipping...\n');
    end;
end

fprintf('Running validation...\n');

Rtrn = zeros(1, length(lambdas));
% for lambda = lambdas
for j = 1 : length(lambdas)
    lambda = lambdas(j);
    load(['./results/exp03_W_nImages-' config.nImages '_hop-' num2str(config.heightOfPyramid) '_lambda_' num2str(lambda) '.mat']);
    L = zeros(1, data.nImages);
    fprintf('TRN: Calculating Rtrn for lambda %f.\n', lambda);
%     for i = 1 : data.nImages
    parfor par_i = 1 : data.nImages
        GT = data.Y{par_i};
        Test = getPsiMat(data, par_i);
        [ q, g ] = getQG(data.options, W, Test, data.mapTable);
        P = f_argmax(data.options, q, g);
        L(par_i) = 1/data.options.M * sum( sqrt( sum( (GT - P ).^2 ) ) );
    end;
    Rtrn(j) = 1/data.nImages * sum(L);
end;

try
    matlabpool close;
catch ME2
    idSegLast = regexp(ME2.identifier, '(?<=:)\w+$', 'match');
    if (strcmp(idSegLast, 'OpenConnection'))
        fprintf('Cannot close matlabpool. Skipping...\n');
    end;
end;

fprintf('TRN: lambda = %s\n', num2str(lambdas, '%4.5f '));
fprintf('TRN: R      = %s\n', num2str(Rtrn, ' %4.5f '));

fprintf('Saving lambdas and Rtrns... ');
save(['./results/exp03_Rtrns_nImages-' config.nImages '_hop-' num2str(config.heightOfPyramid) '.mat'], 'lambdas', 'Rtrn');
fprintf('done.\n');

%% Timestamp

fprintf(1,'Finished on %s\n\n', datestr(now));


function display(X)
%DISPLAY (overloaded)

switch(X.typeflag)
    case {0,9}
        n = X.dim(1);
        m = X.dim(2);
        if (n*m==1)

            linearbilinearquadraticsigmonial = is(X,'LBQS');
            if linearbilinearquadraticsigmonial(1)
                classification = 'Noncommuting linear scalar ';
            elseif linearbilinearquadraticsigmonial(4)
                classification = 'Noncommuting sigmonial scalar ';
            elseif linearbilinearquadraticsigmonial(2)
                classification = 'Noncommuting bilinear scalar ';
            elseif linearbilinearquadraticsigmonial(3)
                classification = 'Noncommuting quadratic scalar ';
            else
                classification = 'Noncommuting polynomial scalar ';
            end

            if ~isreal(X.basis)
                classification = [classification '(complex'];
            else
                classification = [classification '(real'];
            end

            if is(X,'compound')
                classification = [classification ', derived'];
            end

            if ~islinear(X)
                variables = getvariables(X);
                monomtable = yalmip('monomtable');
                if ((nnz(getbasematrix(X,0))==0) ) & (sum(diff(sum(monomtable(variables,:),2)))==0)
                    classification = [classification ', homogeneous'];
                end
            end
            if any(ismember(depends(X),yalmip('intvariables')))
                classification = [classification ', integer'];
            else
                if any(ismember(depends(X),yalmip('binvariables')))
                    classification = [classification ', binary'];
                else
                    if any(ismember(depends(X),yalmip('uncvariables')))
                        classification = [classification ', uncertain'];
                    end
                end
            end

            nvars = length(depends(X));
            if nvars == 1
                classification = [classification ', ' num2str(nvars) ' variable'];
            else
                classification = [classification ', ' num2str(nvars) ' variables'];
            end

            if any(ismember(depends(X),yalmip('parvariables')))
                classification = [classification ', parametric'];
            end
            if ~isnan(double(X))
                classification = [classification ', current value : ' num2str(double(X))];
            end
            classification = [classification ')'];

            disp([classification]);
        else

            if islinear(X)
                classification = 'Noncommuting linear matrix variable ';
            elseif is(X,'sigmonial')
                classification = 'Noncommuting sigmonial matrix variable ';
            elseif is(X,'bilinear')
                classification = 'Noncommuting bilinear matrix variable ';
            elseif is(X,'quadratic')
                classification = 'Noncommuting quadratic matrix variable ';
            else
                classification = 'Noncommuting polynomial matrix variable ';
            end

            if isreal(X.basis)
                if issymmetric(X)
                    info = ' (symmetric, ';
                else
                    info = ' (full, ';
                end;
                info = [info 'real'];
            else
                if issymmetric(X)
                    info = ' (symmetric, ';
                elseif ishermitian(X)
                    info = ' (hermitian, ';
                else
                    info = ' (full, ';
                end;
                info = [info 'complex'];
            end;

            if is(X,'compound')
                info = [info ', derived'];
            end

            if X.typeflag==9
                info = [info ', KYP'];
            end
            if any(ismember(depends(X),yalmip('intvariables')))
                info = [info ', integer'];
            else
                if any(ismember(depends(X),yalmip('binvariables')))
                    info = [info ', binary'];
                else
                    if any(ismember(depends(X),yalmip('uncvariables')))
                        info = [info ', uncertain'];
                    end
                end
            end
            if any(ismember(depends(X),yalmip('parvariables')))
                info = [info ', parametric'];
            end

            xvars = depends(X);
            nvars = length(xvars);
            if nvars == 1
                info = [info ', ' num2str(nvars) ' variable'];
            else
                info = [info ', ' num2str(nvars) ' variables'];
            end

            n = X.dim(1);
            m = X.dim(2);

            if (n<100) & (n==m)
                x = recover(xvars);
                if ~any(any(isnan(double(x))))
                    doubleX = double(X);
                    try
                    eigX = eig(doubleX);
                    info = [info ', eigenvalues between [' num2str(min(eigX)) ',' num2str(max(eigX)) ']'];
                    catch
                    end
                end
            elseif n~=m
                x = recover(xvars);
                if ~any(any(isnan(double(x))))
                    doubleX = double(X);
                    try
                        info = [info ', values in range [' num2str(min(min(doubleX))) ',' num2str(max(max(doubleX))) ']'];
                    catch
                    end
                end
            end

            info = [info ')'];
            disp([classification num2str(n) 'x' num2str(m) info]);
        end;
    case 1
        disp('Relational object');
    case 3
        disp('Relational object');
    case 4
        disp('Relational object');
    case 5
        disp('Cone object');
    case 6
        disp('logdet object');
    case 7
        disp('Integrality constraint');
    case 10
        disp('Eigenvalue object');
    case 11
        disp('SOS object');
    otherwise
end


function planC = saveDVHMatrix(DVHNum, doseBinsV, volsHistV, planC)
%"saveDVHMatrix"
%   Store the doseBinsV and volsHistV with the binWidth shift removed.
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.
%
%Usage:
%   function planC = saveDVHMatrix(DVHNum, doseBinsV, volsHistV, planC)
if isempty(doseBinsV) || isempty(volsHistV)
    error('Cannot save DVH for empty structures');
end
indexS = planC{end};

if length(doseBinsV) == 1
    doseBinsV(2) = 2*doseBinsV(1);
    volsHistV(2) = 0;
end

%Calculate width of bins, use to find middle of each bin.
binWidthsV = diff(doseBinsV);
lastBinWidth = binWidthsV(end);
binWidthsV(end+1) = lastBinWidth;

%Extract dose bin values, adding half to binwidth to get lower edge.
planC{indexS.DVH}(DVHNum).DVHMatrix(:,1) = doseBinsV - binWidthsV/2;
planC{indexS.DVH}(DVHNum).DVHMatrix(:,2) = volsHistV;
return;


% Test file for ADCHEBFUN exp, log related functions

function pass = test_expLog

% List of trigonometric functions to test.
funcList = {@exp, @expm1, @log, @log10, @log1p, @log2};

% Call the ADCHEBFUN testUnary() method to do the tests.
pass = adchebfun.testUnary(funcList);

end


function [fSet] = featureSetReduction_LGG(pathMINE,outcome,setSize,nonTextStruct,textCells,textCellsName,paramAll,paramUsed,baseline,alpha,delta,nBoot,seed,batchNum)
% -------------------------------------------------------------------------
% function [fSet] = featureSetReduction_LGG(pathMINE,outcome,setSize,nonTextStruct,textCells,textCellsName,paramAll,paramUsed,baseline,alpha,delta,nBoot,seed,batchNum)
% -------------------------------------------------------------------------
% DESCRIPTION:
% This function computes feature set reduction for an experiment with a
% specific degree of freedom on texture extraction parameters as defined by
% 'paramUsed', according to the methodology described in ref. [1].
% -------------------------------------------------------------------------
% REFERENCE:
% [1] Vallieres, M. et al. (2015). A radiomics model from joint FDG-PET and
%     MRI texture features for the prediction of lung metastases in soft-tissue
%     sarcomas of the extremities. Physics in Medicine and Biology, 60(14),
%     5471-5496. doi:10.1088/0031-9155/60/14/5471
% -------------------------------------------------------------------------
% INPUTS:
% 1. pathMINE: Full path to the MINE.jar executable. The executable can be
%              downloaded at: <http://www.exploredata.net/>.
% 2. outcome: Column vector of size [nInst X 1] specifying the outcome status
%             (1 or 0) for all instances.
% 3. setSize: Size of the output feature set (typically set to 25 in ref. [1]).
% 4. nonTextStruct: Structure data for non-texture features. This structure
%                   is of the same format as the one saved as output to
%                   computeAllNonTextureFeatures_LGG.m, for example.
% 5. textCells: Cell vector of organized texture cells for all the
%               different scans. Format: textCells = {cell1, cell2, etc.},
%               where cell1, cell2, etc. are the files saved as output to
%               organizeData_LGG.m
% 6. textCellsName: Cell of strings corresponding to the name of the
%                   corresponding cells in textCells.
% 7. paramAll: Cell vector incorporating all texture extraction parameters
%              tested in textCells. See EXAMPLE below for more details.
% 8. paramUsed: Vector of 1's and 0's to specify the degree of freedom on
%               texture extraction parameters for the current experiment.
%               For example, for an experiment where extraction parameters
%               1, 2 and 3 in paramAll are allowed to vary, use
%               paramUsed = [1,1,1].
% 9. baseline: Vector of numerical values specifying the baseline texture
%              extraction parameters for each entry in paramAll. See EXAMPLE
%              below for more details.
% 10. alpha: Numerical values specifying the coefficient of the first part of
%            the Gain equation, as defined in ref. [1].
% 11. delta: Numerical values specifying the coefficient of the second part
%            of the Gain equation, as defined in ref. [1] (third part is set
%            to 0 in this function).
% 12. nBoot: Number of bootstrap samples to use.
% 13. batchNum: (optional input). If present, integer that specifies the
%               batch number for parallelization purposes
%
% See masterScript_LGG.m for a complete example of how to utilize the
% current function.
% -------------------------------------------------------------------------
% OUTPUTS:
% 1. fSET: Structure specifying the resulting feature set for the current
%          experiment.
%          --> fSET.Data: Array of size [nPatient X setSize], specifying the
%                         numerical data of the chosen features, where 'nInst'
%                         refers to the number of instances.
%          --> fSET.Info: Vector of cells with strings specifying information
%                         about the chosen features.
% -------------------------------------------------------------------------
% EXAMPLE:
% scale_mat = [1,2,3,4,5];
% algo_cell = {'Equal','Uniform'};
% Ng_mat = [8,16,32,64];
%
% paramAll = {scale_mat,algo_cell,Ng_mat};
% paramUsed = [1 1 1]; (example for a given experiment)
% baseline = [1,2,3];
% -------------------------------------------------------------------------
% AUTHOR(S): Martin Vallieres <mart.vallieres@gmail.com>
% -------------------------------------------------------------------------
% HISTORY:
% - Creation: January 2017
%--------------------------------------------------------------------------
% STATEMENT:
% This file is part of <https://github.com/mvallieres/radiomics/>,
% a package providing MATLAB programming tools for radiomics analysis.
% --> Copyright (C) 2015-2017  Martin Vallieres
%
%    This package is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    This package is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this package.  If not, see <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

% RANDOM NUMBER GENERATOR SEED
rng(seed);

% INITIALIZATION
nInst = numel(outcome); % Number of patients
nScan = numel(textCellsName); % Number of scans included in that feature set experiment
fSet = struct; fSet.Data=zeros(nInst,setSize); fSet.Info=cell(setSize,1); % Initializing final feature set structure
if nargin == 15
    micName = ['batch',num2str(batchNum)];
else
    micName = 'master';
end
if ~isempty(strfind(textCellsName{1},'CT'))
    name = 'CT';
else
    name = 'MR';
end

% Initializing names
nonTextName = fieldnames(nonTextStruct); nNonText = numel(nonTextName);
textTypeName = fieldnames(textCells{1}{1}); nTextType = numel(textTypeName);
nameF = cell(1,nTextType);
nText = 0;
for t = 1: nTextType
    nameF{t} = fieldnames(textCells{1}{1}.(textTypeName{t}));
    nText = nText + numel(nameF{t});
end
textName = cell(nText,1);
count = 1;
for t = 1:nTextType
    for f = 1:numel(nameF{t})
        textName{count} = [textTypeName{t},'-',nameF{t}{f}];
        count = count +1;
    end
end
nFeatures = nNonText + nScan*nText;
cellNames = cell(nFeatures,2);
count = 1;
for i = 1:nScan
    for j = 1:nText
        cellNames{count,1} = textCellsName{i};
        cellNames{count,2} = textName{j};
        count = count + 1;
    end
end
for i = 1:nNonText
    cellNames{count,1} = nonTextName{i};
    count = count + 1;
end

% Extraction parameters used in that experiment
nParamType = numel(paramUsed);
param = cell(1,nParamType);
paramSize = ones(1,nParamType);
nParam = 1;
for i = 1:nParamType
    if paramUsed(i)
        temp = length(paramAll{i});
        nParam = nParam * temp;
        paramSize(i) = temp;
        param{i} = paramAll{i};
    end
end

% FILLING UP WORKING DATA MATRIX
matData = zeros(nFeatures,nParam,nInst); % Matrix containing all the data vectors for each feature (used for part 2 of Gain equation)
count = 1;
for i = 1:nScan
    textCell = textCells{i};
    textCell = removeParam(textCell,paramUsed,baseline);
    for t = 1:nTextType
        for f = 1:numel(nameF{t})
            for p = 1:numel(textCell)
                matData(count,p,:) = textCell{p}.(textTypeName{t}).(nameF{t}{f}).Data;
            end
            count = count + 1;
        end
    end
end
for i = 1:nNonText
    matData(nText*nScan + i,1,:) = nonTextStruct.(nonTextName{i}).Data;
    for j = 2:nParam
        matData(nText*nScan + i,j,:) = matData(nText*nScan + i,1,:);
    end
end

% IMPORTANT: IF NAN, IT WOULD MEAN SOMETHING WENT WRONG IN SOME TEXTURE CALCULATIONS
matData(isnan(matData(:))) = 0;

% GETTING BOOTSTRAP SAMPLES TO BE USED FOR ALL EXPERIMENTS (using imbalance-adjusted resampling)
[bootSam,~] = buildBootSet(outcome,nBoot,'adjust');

% GETTING BOOTSTRAP RESULTS FOR THE FIRST PART OF THE GAIN EQUATION (ref. [1])
matCorr = zeros(nFeatures,nParam); % Matrix of Spearman correlation of each feature with the outcome (part 1 of Gain equation)
if sum(paramUsed(:)) % Need a transpose
    for n = 1:nBoot
        dataBoot = matData(:,:,bootSam(:,n));
        outcomeBoot = outcome(bootSam(:,n));
        for i = 1:size(dataBoot,1)
            matCorr(i,:) = matCorr(i,:) + corr(squeeze(dataBoot(i,:,:))',outcomeBoot,'type','Spearman','rows','pairwise')';
        end
    end
else % No transpose
    for n = 1:nBoot
        dataBoot = matData(:,:,bootSam(:,n));
        outcomeBoot = outcome(bootSam(:,n));
        for i = 1:size(dataBoot,1)
            matCorr(i,:) = matCorr(i,:) + corr(squeeze(dataBoot(i,:,:)),outcomeBoot,'type','Spearman','rows','pairwise')';
        end
    end
end
matCorr = abs(matCorr./nBoot);

% CHOOSING FIRST FEATURE(depends only on Spearman's correlation)
indChosen = zeros(setSize-1,1);

% Choosing feature
[~,index] = max(matCorr(:));
[row,col] = ind2sub([nFeatures,nParam],index);
indChosen(1) = row;
fSet.Data(:,1) = squeeze(matData(row,col,:));

% Obtaining feature name
if row <= nScan*nText
    [ind1,ind2,ind3] = ind2sub(paramSize,col);
    indBase = [ind1,ind2,ind3];
    indFinal = zeros(1,3);
    for i = 1:3
        if isempty(param{i})
            indFinal(i) = baseline(i);
        else
            indFinal(i) = indBase(i);
        end
    end
    string = [cellNames{row,1},'(R=',num2str(1,'%.2f'),',Scale=',num2str(paramAll{1}(indFinal(1))),',Quant.algo=',paramAll{2}{indFinal(2)},',Ng=',num2str(paramAll{3}(indFinal(3))),')--',cellNames{row,2}];
else % This is a nonTexture feature
    string = cellNames{row,1};
end
fSet.Info{1} = string;

% COMPUTING FOR OTHER FEATURES
PICtest = zeros(nFeatures,setSize-1);
for f = 1:setSize-1

    % Computing PIC for all bootstrap samples
    for n = 1:nBoot
        varBoot = fSet.Data(bootSam(:,n),f);
        dataBoot = matData(:,:,bootSam(:,n));
        dataBootAv = squeeze(mean(dataBoot,2))';
        try
            PICtest(:,f) = PICtest(:,f) + (1 - applyMIC(pathMINE,varBoot,dataBootAv,micName));
        catch % SOLVE THAT PROBLEM
            PICtest(:,f) = PICtest(:,f) + zeros(nFeatures,1);
        end
    end
    PICtest(:,f) = PICtest(:,f)./nBoot;
    PICtemp = zeros(nFeatures,1);
    for k = 1:f
        PICtemp = PICtemp + 2*(f-k+1)/(f*(f+1)).*PICtest(:,k);
    end
    PIC = repmat(PICtemp,1,nParam);

    % Choosing feature
    Gain = alpha.*matCorr + delta.*PIC;
    [~,index] = sort(Gain(:),'descend'); best = 1;
    [row,col] = ind2sub([nFeatures,nParam],index(best));
    while ~isempty(find(indChosen==row))
        best = best + 1;
        [row,col] = ind2sub([nFeatures,nParam],index(best));
    end
    indChosen(f+1) = row;
    fSet.Data(:,f+1) = squeeze(matData(row,col,:));

    % Obtaining feature name
    if row <= nScan*nText
        [ind1,ind2,ind3] = ind2sub(paramSize,col);
        indBase = [ind1,ind2,ind3];
        indFinal = zeros(1,3);
        for i = 1:3
            if isempty(param{i})
                indFinal(i) = baseline(i);
            else
                indFinal(i) = indBase(i);
            end
        end
        string = [cellNames{row,1},'(R=',num2str(1,'%.2f'),',Scale=',num2str(paramAll{1}(indFinal(1))),',Quant.algo=',paramAll{2}{indFinal(2)},',Ng=',num2str(paramAll{3}(indFinal(3))),')--',cellNames{row,2}];
    else % This is a nonTexture feature
        string = cellNames{row,1};
    end
    fSet.Info{f+1} = string;
end

end


function [ama] = loadama(filename)

% LOADAMA read an inverted A-matrix and associated geometry information
% from an ama file that was written by Tom Oostendorp's DIPOLI
%
% Use as
%   [ama] = loadama(filename)
%
% See also LOADTRI, LOADMAT

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

fid = fopen(filename, 'rb', 'ieee-le');
version = fread(fid, 1, 'int');

% TFO 2021-08-10
% version 11 and higher of dipoli uses double precision so all 'float's have been replaced by 'float64's
switch version
  case 10
    floatFormat='float';
  case 11
    floatFormat='float64';
  otherwise
    ft_error('%s is either not an inverted A matrix, or neither version 10 nor 11', filename);
end

mode = fread(fid, 1, 'int');
ngeo = fread(fid, 1, 'int');

totpnt = 0;
tottri = 0;
nrow   = 0;

% read the boundaries
geo  = [];
for i=1:ngeo
  geo(i).name    = char(fread(fid, [1 80], 'uchar'));
  geo(i).npos    = fread(fid, 1, 'int');
  geo(i).pos     = fread(fid, [3 geo(i).npos], floatFormat)';
  geo(i).ntri    = fread(fid, 1, 'int');
  geo(i).tri     = fread(fid, [3 geo(i).ntri], 'int')' + 1;  % MATLAB indexing starts at 1
  geo(i).sigmam  = fread(fid, 1, floatFormat);
  geo(i).sigmap  = fread(fid, 1, floatFormat);
  geo(i).geocon  = fread(fid, ngeo, 'int');
  geo(i).deflat  = fread(fid, ngeo, floatFormat);
  totpnt = totpnt + geo(i).npos;
  tottri = tottri + geo(i).ntri;
end

% read the electrodes
if mode~=1
  elec.name    = char(fread(fid, [1 80], 'uchar'));
  elec.npos    = fread(fid, 1, 'int');
  for i=1:(elec.npos+1)
    elec.el(i).tri  = fread(fid, 1, 'int') + 1; % MATLAB indexing starts at 1
    % TFO 2021-08-10
    % In the 64-bit version, each field is padded to a multiple of 8 bytes, so we need to read 4 dummy bytes
    if version>10
      dum = fread(fid, 4, 'char');
    end
    elec.el(i).la   = fread(fid, 1, floatFormat);
    elec.el(i).mu   = fread(fid, 1, floatFormat);
    elec.el(i).name = char(fread(fid, [1 10], 'char'));
    % the ELECTRODE c-structure is padded to word boundaries, i.e. to 4 bytes
    dum = fread(fid, 2, 'char');
    % TFO 2021-08-10
    % In the 64-bit version, each field is padded to a multiple of 8 bytes, so we need to read 4 more dummy bytes
    if version>10
      dum = fread(fid, 4, 'char');
    end
  end
  elec.vertex  = fread(fid, 1, 'int');
  elec.surface = fread(fid, 1, 'int');
  nrow = nrow + elec.npos;
else
  elec = [];
end

% read the gradiometers
if mode~=0
  ft_error('gradiometers not yet implemented');
else
  grad = [];
end

% read the inverted A-matrix
bi = fread(fid, [totpnt nrow], floatFormat)';

% read the isolated source compartment information, if present
iso_sur    = fread(fid, 1, 'int') + 1;  % Matlab indexing starts at 1
inner_only = fread(fid, 1, 'int');
if iso_sur~=0
  iso_totpnt = geo(iso_sur).npos;
  iso_b      = fread(fid, [iso_totpnt iso_totpnt], floatFormat)';
else
  iso_b = [];
end

fclose(fid);
clear floatFormat;
clear dum;
clear i;

% put all local variables into a structure, this is a bit unusual programming style
% the output structure is messy, but contains all relevant information
tmp = whos;
ama = [];
for i=1:length(tmp)
  if isempty(strmatch(tmp(i).name, {'tmp', 'fid', 'ans', 'handles'}))
    ama = setfield(ama, tmp(i).name, eval(tmp(i).name));
  end
end


classdef ConfusionMatrix < handle
    properties (GetAccess = public)
        confusionMatrixData;
        nClasses;
        classNames;
        containsNullClass;
    end

    methods (Access = public)
        function obj = ConfusionMatrix(truthClasses,predictedClasses,classes,classNames)
            if nargin > 1
                if nargin == 3
                    classNames = [];
                end

                if(any(predictedClasses == Labeling.kNullClass))
                    obj.confusionMatrixData = confusionmat(truthClasses,predictedClasses,'Order',[classes 0]);
                    obj.classNames = [classNames, Labeling.kNullClassStr];
                    obj.containsNullClass = true;
                else
                    obj.confusionMatrixData = confusionmat(truthClasses,predictedClasses,'Order',classes);
                    obj.classNames = classNames;
                    obj.containsNullClass = false;
                end

                obj.nClasses = size(obj.confusionMatrixData,1);
            end
        end
    end

    methods (Access = public, Static)
        function confusionMatrix = CreateConfusionMatrixWithData(confusionMatrixData)
            confusionMatrix = ConfusionMatrix();
            confusionMatrix.confusionMatrixData = confusionMatrixData;
        end
    end

end


%% fnc_SelectInput: select the input indexes from a generic list
%
% Usage:
%   index = fnc_SelectInput(pro, iset)
%
% Inputs:
%    pro                project structure
%    iset               cell array or array of inputs of the considered set, they can be selected
%                       by index (1,2,3 ...) or by name ('in1','x',..) or
%                       mixed
%
% Output:
%     index              vector of indexes corresponding to the iset inputs
%
% ------------------------------------------------------------------------
%
% Author : Flavio Cannavo'
% e-mail: flavio(dot)cannavo(at)gmail(dot)com
% Release: 1.0
% Date   : 02-02-2011
%
% History:
% 1.0  02-02-2011  First release.
%%

function index = fnc_SelectInput(pro, iset)

index = nan(size(iset));

if iscell(iset)
    for i=1:length(iset)
        in = iset{i};
        if isnumeric(in)
            index(i) = floor(in);
        else
            for j=1:length(pro.Inputs.pdfs)
                if strcmp(in,pro.Inputs.Names{j})
                    index(i) = j;
                end
            end
        end
    end
else
    index = iset;
end

if sum(isnan(index))>0
    disp('Warning: some input is not well defined');
end

index = sort(unique(index));