function [varargout]=subHex(varargin)

% function [E,V,C,CV]=subHex(E,V,n,splitMethod)
% ------------------------------------------------------------------------
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
%
%
% 2017/08/31 Added function description to top of function
% ------------------------------------------------------------------------

%% Parse input

switch nargin
    case 2
        E=varargin{1};
        V=varargin{2};
        n=1;
        splitMethod=1;
    case 3
        E=varargin{1};
        V=varargin{2};
        n=varargin{3};
        splitMethod=1;
    case 4
        E=varargin{1};
        V=varargin{2};
        n=varargin{3};
        splitMethod=varargin{4};
end

C=(1:1:size(E,1))'; %Element colors or indices
CV=[];

%%
if n>0
    for qIter=1:1:n
        switch splitMethod
            case 1
                %% Mid edge sets
                edgeMat=[E(:,[1 2]); E(:,[2 3]);  E(:,[3 4]); E(:,[4 1]);... %top
                    E(:,[5 6]); E(:,[6 7]);  E(:,[7 8]); E(:,[8 5]);... %bottom
                    E(:,[1 5]); E(:,[2 6]);  E(:,[3 7]); E(:,[4 8])];   %top-bottom edges

                E_sort=sort(edgeMat,2); %Sorted edges matrix
                [~,ind1,~]=unique(E_sort,'rows');
                edgeMat=edgeMat(ind1,:);

                numPoints = size(V,1);
                numEdges = size(edgeMat,1);

                % Get indices of the four edges associated with each face
                A = sparse(edgeMat(:,1),edgeMat(:,2),(1:numEdges)+numPoints,numPoints,numPoints,numEdges);
                A = max(A,A'); %Copy symmetric

                %Indices for A matrix
                indA_12=E(:,1)+(E(:,2)-1)*numPoints;
                indA_23=E(:,2)+(E(:,3)-1)*numPoints;
                indA_34=E(:,3)+(E(:,4)-1)*numPoints;
                indA_41=E(:,4)+(E(:,1)-1)*numPoints;

                indA_56=E(:,5)+(E(:,6)-1)*numPoints;
                indA_67=E(:,6)+(E(:,7)-1)*numPoints;
                indA_78=E(:,7)+(E(:,8)-1)*numPoints;
                indA_85=E(:,8)+(E(:,5)-1)*numPoints;

                indA_15=E(:,1)+(E(:,5)-1)*numPoints;
                indA_26=E(:,2)+(E(:,6)-1)*numPoints;
                indA_37=E(:,3)+(E(:,7)-1)*numPoints;
                indA_48=E(:,4)+(E(:,8)-1)*numPoints;

                %Get indices for vertex array
                indV_12=full(A(indA_12));
                indV_23=full(A(indA_23));
                indV_34=full(A(indA_34));
                indV_41=full(A(indA_41));

                indV_56=full(A(indA_56));
                indV_67=full(A(indA_67));
                indV_78=full(A(indA_78));
                indV_85=full(A(indA_85));

                indV_15=full(A(indA_15));
                indV_26=full(A(indA_26));
                indV_37=full(A(indA_37));
                indV_48=full(A(indA_48));

                %% Mid element
                indV_mid=(1:1:size(E,1))'+numPoints+size(edgeMat,1);

                %% Mid face

                %Element faces matrix
                F =[E(:,[4 3 2 1]);... %top
                    E(:,[5 6 7 8]);... %bottom
                    E(:,[1 2 6 5]);... %side 1
                    E(:,[3 4 8 7]);... %side 2
                    E(:,[2 3 7 6]);... %front
                    E(:,[5 8 4 1]);]; %back

                F_sort=sort(F,2); %Sorted edges matrix
                [~,ind1,ind2]=unique(F_sort,'rows');
                F=F(ind1,:);

                indV_midFace=(1:1:size(F_sort,1))';
                indOffset=numPoints+size(edgeMat,1)+size(E,1);

                indV_midFace4321=ind2(indV_midFace((1-1)*size(E,1)+(1:size(E,1))))+indOffset;
                indV_midFace5678=ind2(indV_midFace((2-1)*size(E,1)+(1:size(E,1))))+indOffset;
                indV_midFace1265=ind2(indV_midFace((3-1)*size(E,1)+(1:size(E,1))))+indOffset;
                indV_midFace3487=ind2(indV_midFace((4-1)*size(E,1)+(1:size(E,1))))+indOffset;
                indV_midFace2376=ind2(indV_midFace((5-1)*size(E,1)+(1:size(E,1))))+indOffset;
                indV_midFace5841=ind2(indV_midFace((6-1)*size(E,1)+(1:size(E,1))))+indOffset;

                %% Create element array
                Es=[E(:,1) indV_12 indV_midFace4321 indV_41 indV_15 indV_midFace1265 indV_mid indV_midFace5841;...%Corner hex 1
                    indV_12 E(:,2) indV_23 indV_midFace4321 indV_midFace1265 indV_26 indV_midFace2376 indV_mid;... %Corner hex 2
                    indV_midFace4321 indV_23 E(:,3) indV_34 indV_mid indV_midFace2376 indV_37 indV_midFace3487;... %Corner hex 3
                    indV_41 indV_midFace4321 indV_34 E(:,4) indV_midFace5841 indV_mid indV_midFace3487 indV_48;... %Corner hex 4
                    indV_15 indV_midFace1265 indV_mid indV_midFace5841 E(:,5) indV_56 indV_midFace5678 indV_85 ;...%Corner hex 5
                    indV_midFace1265 indV_26 indV_midFace2376 indV_mid  indV_56 E(:,6) indV_67 indV_midFace5678;... %Corner hex 6
                    indV_mid indV_midFace2376 indV_37 indV_midFace3487 indV_midFace5678 indV_67 E(:,7) indV_78 ;... %Corner hex 7
                    indV_midFace5841 indV_mid indV_midFace3487 indV_48 indV_85 indV_midFace5678 indV_78 E(:,8) ;... %Corner hex 8
                    ];

                %% Create vertex array
                Vn=0.5*(V(edgeMat(:,1),:)+V(edgeMat(:,2),:)); %new mid-edge points
                Vm=patchCentre(E,V); %Mid element nodes

                Vf=zeros(size(F,1),3);
                for q=1:1:size(V,2)
                    X=V(:,q);
                    Vf(:,q)=mean(X(F),2);
                end
                Vs = [V; Vn; Vm; Vf]; %Join point sets

                CV=[0*ones(size(V,1),1); 1*ones(size(Vn,1),1); 2*ones(size(Vm,1),1); 3*ones(size(Vf,1),1);];

            case 2

                %% Mid edge sets
                edgeMat=[E(:,[1 5]); E(:,[2 6]);  E(:,[3 7]); E(:,[4 8])];   %top-bottom edges

                E_sort=sort(edgeMat,2); %Sorted edges matrix
                [~,ind1,~]=unique(E_sort,'rows');
                edgeMat=edgeMat(ind1,:);

                numPoints = size(V,1);
                numEdges = size(edgeMat,1);

                % Get indices of the four edges associated with each face
                A = sparse(edgeMat(:,1),edgeMat(:,2),(1:numEdges)+numPoints,numPoints,numPoints,numEdges);
                A = max(A,A'); %Copy symmetric

                %Indices for A matrix
                indA_15=E(:,1)+(E(:,5)-1)*numPoints;
                indA_26=E(:,2)+(E(:,6)-1)*numPoints;
                indA_37=E(:,3)+(E(:,7)-1)*numPoints;
                indA_48=E(:,4)+(E(:,8)-1)*numPoints;

                %Get indices for vertex array
                indV_15=full(A(indA_15));
                indV_26=full(A(indA_26));
                indV_37=full(A(indA_37));
                indV_48=full(A(indA_48));

                %% Create element array
                Es=[E(:,1:4) indV_15 indV_26 indV_37 indV_48;...
                    indV_15 indV_26 indV_37 indV_48 E(:,5:8)];

                %% Create vertex array
                Vn=0.5*(V(edgeMat(:,1),:)+V(edgeMat(:,2),:)); %new mid-edge points
                Vs = [V; Vn;]; %Join point sets
                CV=[0*ones(size(V,1),1); 1*ones(size(Vn,1),1);];

            case 3

                %% Mid edge sets
                edgeMat=[E(:,[1 2]); E(:,[5 6]);  E(:,[7 8]); E(:,[3 4])]; %left-right edges

                E_sort=sort(edgeMat,2); %Sorted edges matrix
                [~,ind1,~]=unique(E_sort,'rows');
                edgeMat=edgeMat(ind1,:);

                numPoints = size(V,1);
                numEdges = size(edgeMat,1);

                % Get indices of the four edges associated with each face
                A = sparse(edgeMat(:,1),edgeMat(:,2),(1:numEdges)+numPoints,numPoints,numPoints,numEdges);
                A = max(A,A'); %Copy symmetric

                %Indices for A matrix
                indA_12=E(:,1)+(E(:,2)-1)*numPoints;
                indA_56=E(:,5)+(E(:,6)-1)*numPoints;
                indA_78=E(:,7)+(E(:,8)-1)*numPoints;
                indA_34=E(:,3)+(E(:,4)-1)*numPoints;

                %Get indices for vertex array
                indV_12=full(A(indA_12));
                indV_56=full(A(indA_56));
                indV_78=full(A(indA_78));
                indV_34=full(A(indA_34));

                %% Create element array
                Es=[E(:,1) indV_12 indV_34 E(:,4) E(:,5) indV_56 indV_78 E(:,8);...
                    indV_12 E(:,2) E(:,3) indV_34 indV_56  E(:,6) E(:,7) indV_78];

                %% Create vertex array
                Vn=0.5*(V(edgeMat(:,1),:)+V(edgeMat(:,2),:)); %new mid-edge points
                Vs = [V; Vn;]; %Join point sets
                CV=[0*ones(size(V,1),1); 1*ones(size(Vn,1),1);];

            case 4

                %% Mid edge sets
                edgeMat=[E(:,[4 1]); E(:,[8 5]);  E(:,[6 7]); E(:,[2 3])]; %front-back edges

                E_sort=sort(edgeMat,2); %Sorted edges matrix
                [~,ind1,~]=unique(E_sort,'rows');
                edgeMat=edgeMat(ind1,:);

                numPoints = size(V,1);
                numEdges = size(edgeMat,1);

                % Get indices of the four edges associated with each face
                A = sparse(edgeMat(:,1),edgeMat(:,2),(1:numEdges)+numPoints,numPoints,numPoints,numEdges);
                A = max(A,A'); %Copy symmetric

                %Indices for A matrix
                indA_41=E(:,4)+(E(:,1)-1)*numPoints;
                indA_85=E(:,8)+(E(:,5)-1)*numPoints;
                indA_67=E(:,6)+(E(:,7)-1)*numPoints;
                indA_23=E(:,2)+(E(:,3)-1)*numPoints;

                %Get indices for vertex array
                indV_41=full(A(indA_41));
                indV_85=full(A(indA_85));
                indV_67=full(A(indA_67));
                indV_23=full(A(indA_23));

                %% Create element array
                Es=[E(:,[1 2]) indV_23 indV_41 E(:,[5 6]) indV_67 indV_85;...
                    indV_41 indV_23 E(:,[3 4]) indV_85 indV_67 E(:,[7 8])];

                %% Create vertex array
                Vn=0.5*(V(edgeMat(:,1),:)+V(edgeMat(:,2),:)); %new mid-edge points
                Vs = [V; Vn;]; %Join point sets
                CV=[0*ones(size(V,1),1); 1*ones(size(Vn,1),1);];

        end

        %% Override input
        C=repmat(C,[size(Es,1)/size(E,1),1]);
        E=Es;
        V=Vs;
    end
end

varargout{1}=E;
varargout{2}=V;
varargout{3}=C;
varargout{4}=CV;

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function h = m_scatter(long,lat,varargin)
% M_SCATTER Scatter/bubble plot
%    M_SCATTER(LON,LAT,Y,S,C) displays colored circles at the locations specified
%    by the vectors LON and LAT (which must be the same size).
%
%    S determines the area of each marker (in points^2). S can be a
%    vector the same length a X and Y or a scalar. If S is a scalar,
%    MATLAB draws all the markers the same size. If S is empty, the
%    default size is used.
%
%    C determines the colors of the markers. When C is a vector the
%    same length as X and Y, the values in C are linearly mapped
%    to the colors in the current colormap. When C is a
%    length(X)-by-3 matrix, it directly specifies the colors of the
%    markers as RGB values. C can also be a color string. See ColorSpec.
%
%    M_SCATTER(LON,LAT) draws the markers in the default size and color.
%    M_SCATTER(LON,LAT,S) draws the markers at the specified sizes (S)
%    with a single color. This type of graph is also known as
%    a bubble plot.
%    M_SCATTER(...,M) uses the marker M instead of 'o'.
%    M_SCATTER(...,'filled') fills the markers.
%
%    H = M_SCATTER(...) returns handles to the scatter objects created.
%
%    Use M_PLOT for single color, single marker size scatter plots.
%

% RP 2016

global MAP_PROJECTION MAP_VAR_LIST

if isempty(MAP_PROJECTION)
  disp('No Map Projection initialized - call M_PROJ first!');
  return;
end

if nargin < 2
  help m_scatter
  return
end

[x,y] = m_ll2xy(long,lat);

h=scatter(x,y,varargin{:});

set(h,'tag','m_scatter');

if nargout == 0
  clear h
end

return


function perm = shuffle_text_file(filename,dest_file,perm)

the_lines = fileread(filename);
the_lines = regexp(the_lines,'(.*?)\n','tokens');

if(~exist('perm','var'))
    perm = randperm(length(the_lines));
end

dest_lines = the_lines(perm);

fp = fopen(dest_file,'wt');
for i = 1 : length(dest_lines)
    fprintf(fp,'%s\n',dest_lines{i}{1});
end
fclose(fp);


% Test file for SPINOP2:

function pass = test_spinop2()

% Construction from STRING for GL equation:
S = spinop2('GL');
N = S.nonlin;
pass(1) = strcmpi(func2str(N), '@(u)u-(1+1.5i)*u.*(abs(u).^2)');

% Construction from DOM/TSPAN:
dom = [0 2*pi 0 2*pi];
tspan = [0 1];
S = spinop2(dom, tspan);
pass(2) = isequal(S.domain, dom);
pass(3) = isequal(S.tspan, tspan);

% Test recursive SUBSREF:
pass(4) = isequal(S.domain([2 4]), [2*pi 2*pi]);

end


function [fx,J,dfdp,d2fdxdp] = f_fullDCM4fmri(Xt,Theta,ut,inF)
% DCM for fMRI evolution function (attn: embedding of HRF!)
% function [fx,dF_dX,dF_dTheta] = f_fullDCM4fmri(Xt,Theta,ut,inF)
% This function evaluates the evolution funciton of the neuronal level in
% DCM for fMRI. For the sake of HRF convolution purposes, it also
% internally calls g_fullDCM4fmri.m so that the hemodynamic states are
% updated properly.

%- Neuronal states evolution
[fx,J,dfdp] = f_dcm4fmri(Xt,Theta,ut,inF);
d2fdxdp = [];

%- HRF convolution
g_fullDCM4fmri(Xt,[],[],inF.inG);
% This call is used to update the hemodynamic states that are convolved
% outputs of the neuronal states (Xt), as well as the necessary gradient,
% i.e. Jacobian and derivative w.r.t. hemodynamic parameters.


function k = rbfard2KernDiagCompute(kern, x)

% RBFARD2KERNDIAGCOMPUTE Compute diagonal of RBFARD2 kernel.
% FORMAT
% DESC computes the diagonal of the kernel matrix for the automatic relevance determination radial basis function kernel given a design matrix of inputs.
% ARG kern : the kernel structure for which the matrix is computed.
% ARG x : input data matrix in the form of a design matrix.
% RETURN k : a vector containing the diagonal of the kernel matrix
% computed at the given points.
%
% SEEALSO : rbfard2KernParamInit, kernDiagCompute, kernCreate, rbfard2KernCompute
%
% COPYRIGHT : Neil D. Lawrence, 2004, 2005, 2006
%
% COPYRIGHT : Michalis K. Titsias, 2009

% KERN

k = repmat(kern.variance, size(x, 1), 1);


function bench_ssc_mc_omp(md)

configs = cell(1, 4);
configs{1} = create_config([1 1 1 1 1 1 1 1 1 1], 4, '1-4');
configs{2} = create_config([2 1 1 1 1 1 1 1 1 1], 4, '2.1-4');
configs{3} = create_config([4 2 1 1 1 1 1 1 1 1], 4, '42.1-4');
configs{4} = create_config([2 2 2 2 2 2 2 2 2 2], 4, '2-4');
num_samples_per_digit_arr = [50 80 100 150 200 300 400];

nns = numel(num_samples_per_digit_arr);
nc = numel(configs);
for ns=1:nns
    num_samples_per_digit = num_samples_per_digit_arr(ns);
    for c=1:nc
        config = configs{c};
        solver_name = sprintf('ssc_mc_omp_%s', config.name);
        fprintf('Simulating: %s, for %d samples per digit\n', solver_name, num_samples_per_digit);
        result = check_digits(md, num_samples_per_digit, @ssc_mc_omp, solver_name, config);
        filepath = sprintf('bin/%s_digits=%d.mat', solver_name, num_samples_per_digit);
        save(filepath, 'result');
    end
end

end


%      Copyright (C) 2009-2013 Biomedizinische NMR Forschungs GmbH
%                     http://www.biomednmr.mpg.de
%            Author: Tilman Johannes Sumpf <tsumpf@gwdg.de>
%
%       Distributed under the Boost Software License, Version 1.2.
%          (See accompanying file LICENSE_1_0.txt or copy at
%                 http://www.boost.org/LICENSE_1_0.txt)

classdef asDataClass < handle

    properties (GetAccess = public, SetAccess = private)
        dat         = [];   % the data dataArrayay
    end

    properties (Access = private)
        selection       = [];     % asSelectionClass object containing the valueChanger array

        updFig      = [];   % update figure callback from the main gui

        % allows methods to alter the image array, making it different
        % from the original that might still be in Workspace
        enableDestrFun  = true;

    end

    methods

        function enableDestructiveFunctions(obj, toggle)
            if nargin < 2
                toggle = true;
            else
                if ~isscalar (toggle)
                    warning('asDataClass:invalidArgument','invalid argument\n');
                end
            end
            obj.enableDestrFun = toggle;
        end

        function obj = asDataClass(dataArray, figureUpdateCallback)

            % validate input data
            obj.dat = asDataClass.validateImageArray(dataArray);

            % store figure update callback to local property
            obj.updFig = figureUpdateCallback;

        end

        function linkToSelectionClassObject(obj, selectionClassObject)
            obj.selection = selectionClassObject;
        end

        function fft2SelectedFrames(obj)
            if obj.enableDestrFun
                str = obj.selection.getValue;

                % create a command string from the gathered informations
                command = strcat('obj.dat(',str,') = asDataClass.mrFft(obj.dat(',str,'));');

                % execute command
                eval(command);

                obj.updFig();
            end
        end

        function ifft2SelectedFrames(obj)
            if obj.enableDestrFun
                str = obj.selection.getValue;

                % create a command string from the gathered informations
                command = strcat('obj.dat(',str,') = asDataClass.mrIfft(obj.dat(',str,'));');

                % execute command
                eval(command);

                obj.updFig();
            end
        end

        function fft2All(obj)
            if obj.enableDestrFun
                if numel(obj.dat) > 1e7
                    %                 mbh = waitbar(0,'deriving FFT of all
                    %                 images...','MenuBar','none');
                    mbh = msgbox('deriving FFT of all images...');
                    obj.dat = asDataClass.mrFft(obj.dat);
                    close(mbh);
                else
                    obj.dat = asDataClass.mrFft(obj.dat);
                end
                obj.updFig();
            end
        end

        function ifft2All(obj)
            if obj.enableDestrFun
                if numel(obj.dat) > 1e7
                    mbh = msgbox('deriving iFFT of all images...');
                    obj.dat = asDataClass.mrIfft(obj.dat);
                    close(mbh);
                else
                    obj.dat = asDataClass.mrIfft(obj.dat);
                end
                obj.updFig();
            end
        end

        function fftshift2All(obj)
            if obj.enableDestrFun
                if numel(obj.dat) > 1e7
                    %                 mbh = waitbar(0,'deriving FFT of all
                    %                 images...','MenuBar','none');
                    mbh = msgbox('deriving FFTshift2 of all images...');
                    obj.dat = asDataClass.fftshift2(obj.dat);
                    close(mbh);
                else
                    obj.dat = asDataClass.fftshift2(obj.dat);
                end
                obj.updFig();
            end
        end

        function rot90(obj, k)
            if obj.enableDestrFun
                if nargin < 2
                    k = 1;
                else
                    if k ~= 1 && k ~=-1
                        warning('arrShow:rot90','k can be either -1 or 1');
                        k = 1;
                    end
                end

                si = size(obj.dat);
                noDims = length(si);

                % get original selection
                origSel = obj.selection.getValueAsCell;

                % get colon dims
                colDims = obj.selection.getColonDims;

                if any(colDims == 0)
                    warning('arrShow:rot90','both colon dimensions need to be selected for rot90');
                else
                    colDims = sort(colDims);
                    pOrder = 1 : noDims;  % original panel ordering

                    newOrder = pOrder;
                    newSel = origSel;

                    newOrder(colDims(1)) = pOrder(colDims(2));
                    newOrder(colDims(2)) = pOrder(colDims(1));
                    newSel{colDims(1)} = origSel{colDims(2)};
                    newSel{colDims(2)} = origSel{colDims(1)};

                    obj.dat = permute(obj.dat,newOrder);
                    if k == 1
                        obj.dat = flipdim(obj.dat,colDims(1));
                    else
                        obj.dat = flipdim(obj.dat,colDims(2));
                    end

                    % valueChanger array
                    newDims = size(obj.dat);
                    obj.selection.reInit(newDims, newSel);

                    obj.updFig();
                end
            end
        end

        function flipDim(obj,dim)
            if obj.enableDestrFun
                obj.dat = flipdim(obj.dat,dim);
                obj.updFig();
            end
        end

        function sumSqr(obj,dim)
            if obj.enableDestrFun
                if nargin ==1
                    dim = length(size(obj.dat)); % use the last dimensions
                end
                si = size(obj.dat);
                l = length(si);
                if dim > l
                    fprintf('dimension %d > number of available dimensions (%d)\n',dim, l);
                else
                    obj.dat = sqrt(sum(obj.dat .* conj(obj.dat),dim));

                    % get original selection
                    si(dim) = 1;
                    sel = obj.selection.getValueAsCell;
                    sel{dim} = '1';

                    % update selection class
                    obj.selection.reInit(si, sel);

                    obj.updFig();
                end
            end
        end

        function max(obj,dim)
            obj.maxMin(dim,@max);
        end

        function min(obj,dim)
            obj.maxMin(dim,@min);
        end

        function squeeze(obj)
            if obj.enableDestrFun
                % get original selection
                sel = obj.selection.getValueAsCell;
                si = size(obj.dat);

                if length(sel) > 2
                    % find dims which will be kept alive
                    sd = si ~= 1;

                    obj.dat = squeeze(obj.dat);
                    sel = sel(sd);

                    % avoid dealing with less than 2 dimensions
                    if length(sel) == 1
                        sel = [sel,{'1'}];
                    end

                    obj.selection.reInit( size(obj.dat), sel);

                    obj.updFig();
                else
                    fprintf('squeezing away one of the last 2 dimensions is not implemented yet :-(\n');
                end
            end
        end

        function setDestructiveSelectionString(obj)
            A = obj.dat;

            noDims = length(size(A));
            colonStr = repmat(': , ',[1,noDims]);
            initStr = ['A = A( ',colonStr,';'];
            initStr(end-2) = ')';

            str = mydlg('Enter selection','Set selection string',initStr);
            if isempty(str)
                return;
            end

            try
                eval(str);
            catch err
                disp(err);
                return;
            end

            obj.overwriteImageArray(A);
        end

        function permute(obj,order)
            if obj.enableDestrFun

                % if no reordering vector is given: open permute dialog
                if nargin < 2 || isempty(order)
                    noDims = length(size(obj.dat));
                    prevValue = num2str(1:noDims,'%d,');
                    prevValue(end) = []; % remove last ','
                    newValue = mydlg('Enter selection string','Selection input dlg',prevValue);
                    if ~isempty(newValue)
                        order = str2num(newValue); % need to use str2num instead of str2double as this is not a scalar
                        if (length(order) ~= noDims ||...
                                min(order) ~= 1 ||...
                                max(order) ~= noDims)
                            warning('PermuteDlg:valueCheck','invalid value');
                            return;
                        end
                    else
                        return;
                    end
                end

                % get original selection
                sel = obj.selection.getValueAsCell;

                % permute array and selection
                obj.dat = permute(obj.dat,order);
                sel = sel(order);

                si = size(obj.dat);
                obj.selection.reInit( si, sel);
                obj.updFig();
            end
        end

        function overwriteImageArray(obj, arr)
            if obj.enableDestrFun

                % get original selection
                origSel = obj.selection.getValueAsCell;
                origSi = size(obj.dat);

                % accept new array
                obj.dat = asDataClass.validateImageArray(arr);
                newSi = size(obj.dat);

                % check if dimensions are equal
                if length(newSi) == length(origSi)
                    dimEqual = true;
                    for i = 1 : length(newSi)
                        if(origSi(i) ~= newSi(i))
                            dimEqual = true;
                            break;
                        end
                    end
                else
                    dimEqual = false;
                end

                % create init selection cell array
                if dimEqual
                    sel = origSel;
                else
                    sel = cell(length(newSi),1);
                    sel{1} = ':';
                    sel{2} = ':';
                    for i = 3 : length(newSi)
                        sel{i} = '1';
                    end
                end

                % reinit selection class
                obj.selection.reInit(newSi, sel);

                obj.updFig();
            end

        end
    end

    methods (Static)

        function dataArray = validateImageArray(dataArray)
            if iscell(dataArray)
                dataArray = asDataClass.cell2imageMat(dataArray);
            end

            if ~isnumeric(dataArray)
                warning('asDataClass:validateImageArray','Input dataArrayay seems not to be numeric. Trying to convert it into double...');
                dataArray = double(dataArray);
            end

            si      = size(dataArray);
            if length(si) < 2
                error('asDataClass:validateImageArray','input dataArrayay has to be at least 2 dimensional');
            end

            if issparse(dataArray);
                dataArray = full(dataArray);
            end

            if any(~isnumeric(dataArray(:)))
                warning('asDataClass:validateImageArray','There are invalid entries in the image dataArrayay. Replacing these entries with zeros...');
                dataArray(~isnumeric(dataArray(:))) = 0;
            end
        end

        function arr = cell2imageMat(cellArr)

            fprintf('isolating images from input cell vector...');

            % check if first cell content has at least 2 dimensions
            refSi = size(cellArr{1});
            if length(refSi) >= 2
                refN = prod(refSi);
            else
                error('asDataClass:cell2imageMat','arrays in input cell must be at least 2 dimensional');
            end

            % if all other cells contain arrays with same number of
            % elements, sort them into an image array
            arr = zeros([refN,numel(cellArr)]);
            for i = 1 : numel(cellArr)
                if numel(cellArr{i}) == refN
                    arr(:,i) = cellArr{i}(:);
                else
                    error('asDataClass:cell2imageMat','arrays in input cell have different size');
                end
            end
            si  = [refSi, squeeze(size(cellArr))];
            arr = reshape(arr,si);
            fprintf('  done.\n');
        end

        function out = fftshift2(in)
            out = fftshift(fftshift(in,1),2);
        end

        %------------------------------------------------------------------
        %Change mrFft & mrIfft for MRiLab compatibility <Fang Liu>
        %28-April-2013  change fft2 to fftn
        %16-May-2013    apply different fft & ifft based on input dimension for multi Rx coil recon

%         function out = mrFft(in)
%             si = size(in);
%             a = 1 / (sqrt(si(1)) * sqrt(si(2)));
%             out = asDataClass.fftshift2(fft2(asDataClass.fftshift2(in))) * a;
%
%         end
%
%         function out = mrIfft(in)
%             si = size(in);
%             a = sqrt(si(1)) * sqrt(si(2));
%             out = asDataClass.fftshift2(ifft2(asDataClass.fftshift2(in))) * a;
%         end

        function out = mrFft(in)
            switch ndims(in)
                case 5 % multi echo
                    d = size(in);
                    out = zeros(d);
                    for j = 1: d(5)
                        for i = 1: d(4)
                            out(:,:,:,i,j) = fftshift(fftn(fftshift(in(:,:,:,i,j))));
                        end
                    end
                case 4 % multi Rx coil
                    d = size(in);
                    out = zeros(d);
                    for i = 1: d(4)
                        out(:,:,:,i) = fftshift(fftn(fftshift(in(:,:,:,i))));
                    end
                otherwise % normal
                    out = fftshift(fftn(fftshift(in)));
            end
        end

        function out = mrIfft(in)
           switch ndims(in)
                case 5 % multi echo
                    d = size(in);
                    out = zeros(d);
                    for j = 1: d(5)
                        for i = 1: d(4)
                            out(:,:,:,i,j) = fftshift(ifftn(fftshift(in(:,:,:,i,j))));
                        end
                    end
                case 4 % multi Rx coil
                    d = size(in);
                    out = zeros(d);
                    for i = 1: d(4)
                        out(:,:,:,i) = fftshift(ifftn(fftshift(in(:,:,:,i))));
                    end
                otherwise % normal
                    out = fftshift(ifftn(fftshift(in)));
            end
        end
        %-----------------End----------------------------------------------

    end

    methods (Access = private)
        function maxMin(obj,dim,funPtr)
            if obj.enableDestrFun
                if nargin ==1
                    dim = length(size(obj.dat)); % use the last dimensions
                end
                si = size(obj.dat);
                l = length(si);
                if dim > l
                    fprintf('dimension %d > number of available dimensions (%d)\n',dim, l);
                else
                    obj.dat = funPtr(obj.dat,[],dim);

                    % get original selection
                    si(dim) = 1;
                    sel = obj.selection.getValueAsCell;
                    sel{dim} = '1';

                    % update selection class
                    obj.selection.reInit(si, sel);

                    obj.updFig();
                end
            end
        end
    end
end


function [xg, yg, zg, tg] = scimat_ndgrid(scimat, ri, ci, si, fi)
% SCIMAT_NDGRID  Generation of arrays for 2D to 4D SCIMAT image volumes.
%
% [XG, YG, ZG] = scimat_ndgrid(SCIMAT,RI,CI,SI,FI)
%
%   SCIMAT is a struct with an image volume (see "help scimat" for
%   details).
%
%   XG, YG, ZG are arrays with the x-, y-, z-coordinates of the voxels in
%   SCIMAT.
%
%   Note that XG values change with columns, and YG values change with
%   rows, to accommodate the usual coordinate frame convention.
%
% [XG, YG, ZG] = scimat_ndgrid(SCIMAT, RI, CI, SI, FI)
%
%   RI, CI, SI, FI are vectors of voxel indices (rows, columns, slices and frames).
%   The output grid will be generated only for the corresponding image block.
%   For example, RI=1:4, CI=3:6, SI=5:7 means that the grid of coordinates
%   will be generated only for the block of voxels (1:4, 3:6, 5:7).
%
% See also: ndgrid, scimat_index2world.

% Author(s): Ramon Casero <rcasero@gmail.com>,
% Ben Villard <b.016434@gmail.com>
% Copyright © 2010-2015 University of Oxford
% Version: 0.4.1
%
% University of Oxford means the Chancellor, Masters and Scholars of
% the University of Oxford, having an administrative office at
% Wellington Square, Oxford OX1 2JD, UK.
%
% This file is part of Gerardus.
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details. The offer of this
% program under the terms of the License is subject to the License
% being interpreted in accordance with English Law and subject to any
% action against the University of Oxford being under the jurisdiction
% of the English Courts.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.

% check arguments
D = length(scimat.axis);
narginchk(1, 5);
nargoutchk(0, D);

% simplify notation
NR = size(scimat.data, 1);
NC = size(scimat.data, 2);
NS = size(scimat.data, 3);
NF = size(scimat.data, 4);

% defaults
if (nargin < 2 || isempty(ri))
    ri = 1:NR; % Creates indices of data length (rows).
end
if (nargin < 3 || isempty(ci))
    ci = 1:NC; % Creates indices of data length (columns).
end
if (nargin < 4 || isempty(si))
    si = 1:NS; % Creates indices of data length (number of slices).
end
if (nargin < 5 || isempty(fi))
    fi = 1:NF; % Creates indices of data length (number of time frames).
end

% generate 3D grid of coordinates. X and Y have to be swapped so that the
% grid has the right number of rows and columns
if (D == 2)

    [rg, cg] = ndgrid(ri, ci);
    xyzt = scimat_index2world([rg(:), cg(:)], scimat); % Converts indices to world coordinates
    xg = reshape(xyzt(:, 1), size(rg));
    yg = reshape(xyzt(:, 2), size(cg));

elseif (D == 3)

    [rg, cg, sg] = ndgrid(ri, ci, si);
    xyzt = scimat_index2world([rg(:), cg(:), sg(:)], scimat);% Converts indices to world coordinates
    xg = reshape(xyzt(:, 1), size(rg));
    yg = reshape(xyzt(:, 2), size(cg));
    zg = reshape(xyzt(:, 3), size(sg));

elseif (D == 4)
    [rg, cg, sg, fg] = ndgrid(ri, ci, si, fi);
    xyzt = scimat_index2world([rg(:), cg(:), sg(:), fg(:)], scimat);% Converts indices to world coordinates
    xg = reshape(xyzt(:, 1), size(rg));
    yg = reshape(xyzt(:, 2), size(cg));
    zg = reshape(xyzt(:, 3), size(sg));
    tg = reshape(xyzt(:, 4), size(fg));

else
    error('Wrong number of dimensions in scimat.data')
end

end


% This function performs the binary decision tree training.

% Copyright (C) 2012 Quan Wang <wangq10@rpi.edu>,
% Signal Analysis and Machine Perception Laboratory,
% Department of Electrical, Computer, and Systems Engineering,
% Rensselaer Polytechnic Institute, Troy, NY 12180, USA
%
% You are free to use this software for academic purposes if you cite our paper:
% Q. Wang, Y. Ou, A.A. Julius, K.L. Boyer, M.J. Kim,
% Tracking tetrahymena pyriformis cells using decision trees,
% in: 2012 International Conference on Pattern Recognition, Tsukuba Science City, Japan.
%
% For commercial use, please contact the authors.

function T=create01Tree(X,label,Depth,Splits,MinNode)

% X: N*M training data matrix, each row is one sample
% label: N*1 labels of training data, each entry takes value 0 or 1
% Depth: maximal depth of decision tree
% Splits: number of candidate thresholds at each node
% MinNode: minimal size of a non-leaf node
% T: resulting decision tree

T=struct('feature',zeros(2^(Depth-1)-1,1),...
    'threshold',zeros(2^(Depth-1)-1,1),...
    'leaf',zeros(2^(Depth-1),2),...
    'leaf_prob',zeros(2^(Depth-1),1),...
    'depth',Depth);

T=get01Tree(1,T,X,label,Depth,Splits,MinNode);


function out = run_sqrs(ecg,HRVparams,rs)
%out = run_sqrs(ecg,s,rs)
%	OVERVIEW:
%       QRS onset detector
%   INPUT:
%       ecg = single channel of ECG in digital values
%       s   = settings struct
%       rs  = resampling option; 1 = resample original signal, 0 = don't
%   OUTPUT:
%       out = sample points of onset of each QRS complex
%   DEPENDENCIES & LIBRARIES:
%   REFERENCE:
%	REPO:
%       https://github.com/cliffordlab/hrv_toolbox
%   ORIGINAL SOURCE AND AUTHORS:
%       Converted from sqrs.c at:
%       http://www.physionet.org/physiotools/wfdb/app/sqrs.c
%       to  sqrs.m (Matlab)     by J. Perry,    July        2006
%           sqrs.c	(C)         by	G.B. Moody  27 October  1990
%
%	Last revised by John:  25 February 2006
%	Last revised by Gari:  07 February 2007
%
%   03-06-2017
%   Edited by Adriana Vest
%   Now requires settings struct HRVparams, which defines debug mode and
%   sampling frequency, and resampling option rs.
%   LICENSE AND COPYRIGHT:
%       See Below
%
% if debug>0, then plot final data (default; debug=0)
%
% This algorithm is sensitive to high frequency noise, so you
% might want to use an FIR band-pass filter first.
%
% Avaialble under the GPL (see below)
%-------------------------------------------------------------------------------
% sqrs: Single-channel QRS detector
% Copyright (C) 1990-2006 George B. Moody
%
% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public License as
% published by the Free Software Foundation; either version 2 of the
% License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
% General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
% 02111-1307, USA.
%
% You may contact the author by e-mail (george@mit.edu) or postal
% mail (MIT Room E25-505A, Cambridge, MA 02139 USA).  For updates to
% this software, please visit PhysioNet (http://www.physionet.org/).
% _________________________________________________________________
%
% The detector algorithm is based on example 10 in the WFDB
% Programmer's Guide, which in turn is based on a Pascal program
% written by W.A.H. Engelse and C. Zeelenberg, "A single scan
% algorithm for QRS-detection and feature extraction", Computers in
% Cardiology 6:37-42 (1979).  `sqrs' does not include the feature
% extraction capability of the Pascal program.  The output of `sqrs'
% is an annotation file (with annotator name `qrs') in which all
% detected beats are labelled normal;  the annotation file may also
% contain `artifact' annotations at locations which `sqrs' believes
% are noise-corrupted.
%
% 'sqrs' has been optimized for adult human ECGs. For other ECGs,
% it may be necessary to experiment with the input sampling
% frequency and the time constants indicated below.
%
% This program is provided as an example only, and is not intended
% for any clinical application.  At the time the algorithm was
% originally published, its performance was typical of
% state-of-the-art QRS detectors.  Recent designs, particularly
% those that can analyze two or more input signals, may exhibit
% significantly better performance.
%%

if nargin<2
    error('Incorrect number of input arguments: must provide ECG signal and HRV paramters struct')
end
if nargin < 3
    rs = 1;
end

%debug = s.debug;
debug = 0;
fs = HRVparams.Fs;

if ~rs
    %% 1. Use Fs of Input
    time = 0;
    now = 10;

    %freq = 256;
    freq = fs;
    ms160 = ceil(0.16*freq);
    ms200 = ceil(0.2*freq);
    s2 = ceil(2*freq);
    scmin = 500;
    % number of ADC units corresponding to scmin microvolts
    % scmin = muvadu(signal, scmin);
    scmax = 10 * scmin;
    slopecrit = 10 * scmin;
    maxslope = 0;
    nslope = 0;
    out = [];

    while (now < length(ecg)) %   && (to == 0)
        filter = [1 4 6 4 1 -1 -4 -6 -4 -1] * ecg((now-9):now);
        if (mod(time, s2) == 0)
	    % Adjust slope
            if (nslope == 0)
	      slopecrit = max(slopecrit - slopecrit/16, scmin);
            elseif (nslope >= 5)
	      slopecrit = min(slopecrit + slopecrit/16, scmax);
            end
        end
        if (nslope == 0  && abs(filter) > slopecrit)
            nslope = nslope + 1;
	    maxtime = ms160;
	    if (filter > 0)
	      sign = 1;
	    else
	      sign = -1;
	    end
            qtime = time;
        end
        if (nslope ~= 0)
            if (filter * sign < -slopecrit)
                sign = -sign;
                nslope = nslope + 1;
                if (nslope > 4)
                  maxtime = ms200;
                else
                  maxtime = ms160;
                end
            elseif (filter * sign > slopecrit &&  abs(filter) > maxslope)
                maxslope = abs(filter);
            end

            if (maxtime < 0)
                if (2 <= nslope && nslope <= 4)
                    slopecrit = slopecrit + ((maxslope/4) - slopecrit)/8;
                    if (slopecrit < scmin)
                        slopecrit = scmin;
                    elseif (slopecrit > scmax)
                        slopecrit = scmax;
                    end
                    out = [out; now - (time - qtime) - 4];
                    %annot.anntyp = NORMAL;
                    time = 0;
                elseif (nslope >= 5)
                    out = [out; now - (time - qtime) - 4];
                    %annot.anntyp = ARFCT;
                end
                nslope = 0;
            end
            maxtime = maxtime - 1;
        end
	time = time + 1;
	now = now + 1;
    end

    out=out-1; % adjust for 1 sample offset problem.

    if debug > 0
       plot(ecg,'b');
       hold on;
       plot(out,ecg(out),'m*');
    end
elseif rs
    %% 2. Resample at 256 Hz
    % These time constants may need adjustment for pediatric or
    % small mammal ECGs.
    ecg_rs = resample(ecg,256,fs);

    time = 0;
    now = 10;

    freq = 256;
    ms160 = ceil(0.16*freq);
    ms200 = ceil(0.2*freq);
    s2 = ceil(2*freq);
    %scmin = 500;
    % ANV changed this to work with real units
    scmin = 500;
    % number of ADC units corresponding to scmin microvolts
    % scmin = muvadu(ecg_rs, scmin);
    scmax = 10 * scmin;
    slopecrit = 10 * scmin;
    maxslope = 0;
    nslope = 0;
    out = [];

    while (now < length(ecg_rs)) %   && (to == 0)
        filter = [1 4 6 4 1 -1 -4 -6 -4 -1] * ecg_rs((now-9):now);
        if (mod(time, s2) == 0)
            % Adjust slope
            if (nslope == 0)
                slopecrit = max(slopecrit - slopecrit/16, scmin);
            elseif (nslope >= 5)
                slopecrit = min(slopecrit + slopecrit/16, scmax);
            end
        end
        if (nslope == 0  && abs(filter) > slopecrit)
            nslope = nslope + 1;
            maxtime = ms160;
            if (filter > 0)
                sign = 1;
            else
                sign = -1;
            end
            qtime = time;
        end
        if (nslope ~= 0)
            if (filter * sign < -slopecrit)
                sign = -sign;
                nslope = nslope + 1;
                if (nslope > 4)
                    maxtime = ms200;
                else
                  maxtime = ms160;
                end
            elseif (filter * sign > slopecrit &&  abs(filter) > maxslope)
                maxslope = abs(filter);
            end
            if (maxtime < 0)
                if (2 <= nslope && nslope <= 4)
                    slopecrit = slopecrit + ((maxslope/4) - slopecrit)/8;
                    if (slopecrit < scmin)
                        slopecrit = scmin;
                    elseif (slopecrit > scmax)
                        slopecrit = scmax;
                    end
                    out = [out; now - (time - qtime) - 4];
                    %annot.anntyp = NORMAL;
                    time = 0;
                elseif (nslope >= 5)
                    out = [out; now - (time - qtime) - 4];
                    %annot.anntyp = ARFCT;
                end
                nslope = 0;
            end
            maxtime = maxtime - 1;
        end
	time = time + 1;
	now = now + 1;
    end

    out=out-1; % adjust for 1 sample offset problem.

    if debug > 0
       plot(ecg_rs,'b');
       hold on;
       plot(out,ecg_rs(out),'m*');
    end

end


%
% Replaces model parameters (from a vector) into an object.
% Used for optimizing a parse, with fixed type-level parameters,
% to a new image
%
% Replace variables:
%  image blur, pixel noise, and affine parameters
%  stroke position, token scale, and token shape
%
function vec_to_model_fit_token(theta,M,list_sid)

    if ~exist('list_sid','var')
       list_sid = 1:M.ns;
    end

    count = 1;

    % pixel noise
    M.epsilon = theta(count);
    count = count + 1;

    % image blur
    M.blur_sigma = theta(count);
    count = count + 1;

    % affine warp
    x = count:count+3;
    M.A = vec(theta(x));
    count = count + 4;

    for i=list_sid

        % stroke position
        x = count:count+1;
        M.S{i}.pos_token = vec(theta(x))';
        count = count + 2;

        % sub-stroke shapes (token)
        nn = numel(M.S{i}.shapes_token);
        x = count:count+nn-1;
        M.S{i}.shapes_token = reshape(theta(x),size(M.S{i}.shapes_token));
        count = count + nn;

        % sub-stroke scales (token)
        nn = numel(M.S{i}.invscales_token);
        x = count:count+nn-1;
        M.S{i}.invscales_token = reshape(theta(x),size(M.S{i}.invscales_token));
        count = count + nn;

        % eval_spot_token
        if ~isempty(M.S{i}.R) && strcmp(M.S{i}.R.type,'mid')
            M.S{i}.R.eval_spot_token = theta(count);
            count = count + 1;
        end
    end

end