function [mResult, fMls, fMc, fMu, fSigma, mDatPredBest, vPredBest] = plot_McCdfnormal(mCatalog, fBinning)
% function [mResult, fMls, fMc, fMu, fSigma, mDatPredBest, vPredBest] = plot_McCdfnormal(mCatalog, fBinning);
% -----------------------------------------------------------------------------------------------------
% Same as calc_McCdfnormal with plotting the fitting steps and the final result
%
% Incoming variables:
% mCatalog   : EQ catalog
% fBinning   : Binning interval, usually 0.1
%
% Outgoing variables:
% mResult     : Solution matrix including
%               vProbability: maximum likelihood score
%               vMc         : Mc values
%               vX_res      : mu (of normal CDF), sigma (of normal CDF), residuum, exitflag
%               vNmaxBest   : Number of events in lowest magnitude bin considered complete
%               vABValue    : a and b-value
% fMls       : minimum maximum likelihood score --> best Mc
% fMc        : Best estimated magnitude of completeness
% mDatPredBest   : Matrix of non-cumulative FMD [Prediction, magnitudes, original distribution]
% vPredBest      : Matrix of non-cumulative FMD below Mc [magnitude, prediction, uncertainty of prediction]
%
% J. Woessner: woessner@seismo.ifg.ethz.ch
% last update: 10.02.03

% Initialize
vProbability = [];
vMc = [];
vABValue =[];
mFitRes = [];
vX_res = [];
vNCumTmp = [];
mDataPred = [];
vPredBest = [];
vDeltaBest = [];
vX_res = [];
vNmaxBest = [];
mResult=[];
mDatPredBest = [];

% Determine exact time period
fPeriod1 = max(mCatalog(:,3)) - min(mCatalog(:,3));

% Determine max. and min. magnitude
fMaxMag = ceil(10 * max(mCatalog(:,6))) / 10;

% Set starting value for Mc loop and LSQ fitting procedure
fMcTry= calc_Mc(mCatalog,1);
fSmu = fMcTry/2;
fSSigma = fMcTry/4;
if (fSmu > 1)
    fSmu = fMcTry/10;
    fSSigma = fMcTry/20;
end
fMcBound = fMcTry;

% Calculate FMD for original catalog
[vFMDorg, vNonCFMDorg] = calc_FMD(mCatalog);
fMinMag = min(vNonCFMDorg(1,:));

%% Shift to positive values
if fMinMag ~= 0
    fMcBound = fMcTry-fMinMag;
end

% Loop over Mc-values
for fMc = fMcBound-0.4:0.1:fMcBound+0.4
    fMc = round(fMc*10)/10;
    vFMD = vFMDorg;
    vNonCFMD = vNonCFMDorg;
    vNonCFMD = fliplr(vNonCFMD);
    % Calculate a and b-value for GR-law and distribution vNCum
    [nIndexLo, fMagHi, vSel, vMagnitudes] = fMagToFitBValue(mCatalog, vFMD, fMc);
    if (length(mCatalog(vSel,1)) >= 20)
        [fMeanMag, fBValue, fStdDev, fAValue] =  calc_bmemag(mCatalog(vSel,:), fBinning);
        % Normalize to time period
        vFMD(2,:) = vFMD(2,:)./fPeriod1;
        vNonCFMD(2,:) = vNonCFMD(2,:)./fPeriod1;
        % Compute quantity of earthquakes by power law
        fMaxMagFMD = max(vNonCFMD(1,:));
        fMinMagFMD = min(vNonCFMD(1,:));
        vMstep = [fMinMagFMD:0.1:fMaxMagFMD];
        vNCum = 10.^(fAValue-fBValue.*vMstep); % Cumulative number

        % Compute non-cumulative numbers vN from GR-law
        fNCumTmp = 10^(fAValue-fBValue*(fMaxMag+0.1));
        vNCumTmp  = [vNCum fNCumTmp ];
        vN = abs(diff(vNCumTmp));

        % Normalize vN
        vN = vN./fPeriod1;
        % Data selection
        % mData = Non-cumulative FMD values from GR-law and original data
        mData = [vN' vNonCFMD'];
        vSel = (mData(:,2) >= fMc);
        mDataTest = mData(~vSel,:);
        mDataTmp = mData.subset(vSel);
        % Check for zeros in observed data
%         vSelCheck = (mDataTest(:,3) == 0);
%         mDataTest = mDataTest(~vSelCheck,:);
        % Choices of normalization
        fNmax = mDataTmp(1,3); % Frequency of events in Mc bin
        %fNmax = max(mDataTest(:,3));  % Use maximum frequency of events in bins below Mc
        %fNmax = mDataTest(length(mDataTest(:,1)),3); % Use frequency of events at bin Mc-0.1 -> best fit
        %fNmax = (mDataTest(length(mDataTest(:,1)),3)+mDataTmp(1,3))/2;
        if (~isempty(fNmax) & ~isnan(fNmax) & fNmax ~= 0 & length(mDataTest(:,1)) > 4)
            mDataTest(:,3) = mDataTest(:,3)/fNmax; % Normalize datavalues for fitting with CDF
            % Move to M=0 to fit with lsq-algorithm
            fMinMagTmp = min(mDataTest(:,2));
            mDataTest(:,2) = mDataTest(:,2)-fMinMagTmp;
            % Curve fitting: Non cumulative part below Mc
            options = optimset;
            %options = optimset('Display','off','Tolfun',1e-5,'TolX',0.0001,'MaxFunEvals', 100000,'MaxIter',10000);
            options = optimset('Display','off','Tolfun',1e-5,'TolX',0.001,'MaxFunEvals', 1000,'MaxIter',1000);
            [vX, resnorm, resid, exitflag, output, lambda, jacobian]=lsqcurvefit(@calc_normalCDF,[fSmu  fSSigma], mDataTest(:,2), mDataTest(:,3),[],[],options);
            mDataTest(:,1) = normcdf(mDataTest(:,2), vX(1), vX(2))*fNmax;
            if (length(mDataTest(:,2)) > length(vX(1,:)))
                %% Confidence interval determination
                % vPred : Predicted values of lognormal function
                % vPred+-delta : 95% confidence level of true values
                [vPred,delta] = nlpredci(@calc_normalCDF,mDataTest(:,2),vX, resid, jacobian);
            else
                vPred = NaN;
                delta = NaN;
            end % END: This section is due for errors produced with datasets less long than amount of parameters in vX
            % Results of fitting procedure
            mFitRes = [mFitRes; vX resnorm exitflag];
            % Move back to original magnitudes
            mDataTest(:,2) = mDataTest(:,2)+fMinMagTmp;
            %% Set data together
            mDataTest(:,3) = mDataTest(:,3)*fNmax;
            mDataPred = [mDataTest; mDataTmp];
            % Denormalize to calculate probabilities
            mDataPred(:,1) = round(mDataPred(:,1).*fPeriod1);
            mDataPred(:,3) = mDataPred(:,3).*fPeriod1;
            vProb_ = calc_log10poisspdf2(mDataPred(:,3), mDataPred(:,1)); % Non-cumulative
            %vPro_ = calc_log10poisspdf(mDataPred(:,3), mDataPred(:,1)); % Non-cumulative
            % Sum the probabilities
            fProbability = (-1) * sum(vProb_);
            vProbability = [vProbability; fProbability];
            % Move magnitude back
            mDataPred(:,2) = mDataPred(:,2)+fMinMag;
            vMc = [vMc; fMc+fMinMag];
            vABValue = [vABValue; fAValue fBValue];

             % Keep values
            vDeltaBest = [vDeltaBest; delta];
            vX_res = [vX_res; vX resnorm exitflag];
            vNmaxBest = [vNmaxBest; fNmax];

            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            % Plot routines
            if exist('cdfit_fig','var') &  ishandle(cdfit_fig)
                set(0,'Currentfigure',cdfit_fig);
            else
                cdfit_fig=figure_w_normalized_uicontrolunits('tag','cdfit','Name','Fitting CDF','Units','normalized','Nextplot','add',...
                    'Numbertitle','off','visible','on');
                cdfit_axs=axes('tag','ax_cdfit','Nextplot','add','box','off');
            end

            set(gcf,'tag','cdfit');
            subplot(3,1,1); % Fitting curve and original data => Mc
            plot(mDataTest(:,2)+fMinMag, mDataTest(:,1),'-r', mDataTest(:,2)+fMinMag, mDataTest(:,3), '*')
            hold on;
            plot(mDataTest(:,2)+fMinMag, mDataTest(:,1)+delta*fNmax,'--g',mDataTest(:,2)+fMinMag, mDataTest(:,1)-delta*fNmax,'--g');
            hold off;
            ylabel('CDF fit');
            sTitle = ['Test: Mc = ', num2str(fMc+fMinMag)];
            title(sTitle);
            subplot(3,1,2); % Non-cumulative data, Non-cumulative data from GR-law, Non-cumulative data predicted with normal CDF
            plot(vNonCFMD(1,:)'+fMinMag, vNonCFMD(2,:)'.*fPeriod1, '^b', vNonCFMD(1,:)'+fMinMag, vN.*fPeriod1, '*g', mDataPred(:,2),mDataPred(:,1),'or')
            ylabel('NonCumFMD fit')
            subplot(3,1,3); % Cumlative data, cumulative data from GR-law, cumulative data predicted with normal CDF
            mTmp = flipud(mDataPred);
            mTmp(:,1) = cumsum(mTmp(:,1));
            mTmp(:,3) = cumsum(mTmp(:,3));
            semilogy(mTmp(:,2), mTmp(:,1),'ro',mTmp(:,2), mTmp(:,3),'g*',vMstep+fMinMag, vNCum./fPeriod1)
            xlabel('Magnitude')
            ylabel('FMD fit')
            drawnow;
            %pause
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

             % Keep best fitting model for plotting
            if (fProbability == nan(vProbability))
                vDeltaBest = delta;
                vPredBest = [mDataTest(:,2)+fMinMag vPred*fNmax*fPeriod1 delta*fNmax*fPeriod1]; % Gives back uncertainty
                vNBest = vN;
                %fMc+fMinMag : Test procedure
                mDatPredBest = [mDataPred];
           end
        else
            %disp('Not enough data');
            % Setting values
            fProbability = NaN;
            fMc = NaN;
            vX(1) = NaN;
            vX(2) = NaN;
            resnorm = NaN;
            exitflag = NaN;
            delta = NaN;
            vPred = [NaN NaN NaN];
            fNmax = NaN;
            fAValue = NaN;
            fBValue = NaN;
            vProbability = [vProbability; fProbability];
            vMc = [vMc; fMc+fMinMag];
            vX_res = [vX_res; vX resnorm exitflag];
            vDeltaBest = [vDeltaBest; delta];
            vPredBest = [vPredBest; vPred*fNmax];
            vNmaxBest = [vNmaxBest; fNmax];
            vABValue = [vABValue; fAValue fBValue];
        end % END of IF fNmax
    end % END of IF length(mCatalog(vSel,1))

    % Clear variables
    vNCumTmp = [];
    mModelDat = [];
    vNCum = [];
    vSel = [];
    mDataTest = [];
    mDataPred = [];
end % END of FOR fMc

if isempty(vProbability)
    disp('Not enough data');
    return;
end

mResult = [mResult; vProbability vMc vX_res vNmaxBest vABValue];

% Find best estimate, excluding the case of mResult all NAN
if  ~isempty(nan(mResult))
    if ~isnan(nan(mResult(:,1)))
        vSel = find(nan(mResult(:,1)) == mResult(:,1));
        fMc = min(mResult(vSel,2));
        fMls = min(mResult(vSel,1));
        fMu = min(mResult(vSel,3));
        fSigma = min(mResult(vSel,4));
    else
        fMc = NaN;
        fMls = NaN;
        fMu = NaN;
        fSigma = NaN;

    end
else
    fMc = NaN;
    fMls = NaN;
    fMu = NaN;
    fSigma = NaN;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Plot result
% Plot MLS vs. Mc
figure_w_normalized_uicontrolunits('tag','mlsmc','Name','MLS vs. Mc','Units','normalized','Nextplot','add',...
                    'Numbertitle','off','visible','on');
plot(vMc, vProbability,'Marker','s','MarkerFaceColor',[0.5 0.5 0.5],'Markersize',8');
xlabel('Mc');
ylabel('MLS');
sTitlestr = ['Minimum MLS at Mc = ' num2str(fMc)];
title(sTitlestr);

% Plot Best fitting CDF vs. magnitude
figure_w_normalized_uicontrolunits('tag','best_cdfit','Name','CDF fit','Units','normalized','Nextplot','add',...
                    'Numbertitle','off','visible','on');
plot(vPredBest(:,1),vPredBest(:,2))
hold on;
%plot(mDat(:,2)+fMinMag, mDat(:,3)*fNmax*fPeriod1,'+r')
plot(mDatPredBest(:,2),mDatPredBest(:,1),'o',mDatPredBest(:,2), mDatPredBest(:,3),'<');
sTitlestr = ['mu = ' num2str(fMu) ', sigma = ' num2str(fSigma)];
title(sTitlestr)
plot(vPredBest(:,1),vPredBest(:,2)+vPredBest(:,3),'--g')
plot(vPredBest(:,1),vPredBest(:,2)-vPredBest(:,3),'--g')
xlabel('Magnitude');
ylabel('Non-cumulative FMD');
hold off;

% Plot Non-cumulative distribution, original and predicted
figure_w_normalized_uicontrolunits('tag','ncumdist','Name','Best model','Units','normalized','Nextplot','add',...
                    'Numbertitle','off','visible','on');
semilogy(vNonCFMDorg(1,:)', vNonCFMDorg(2,:)', '^', vNonCFMD(1,:)', vNBest.*fPeriod1, '*', mDatPredBest(:,2),mDatPredBest(:,1),'o')
xlim = ([min(mDatPredBest(:,2)) max(mDatPredBest(:,2))]);
sTitlestr = ['Mc = ' num2str(fMc) ' using Normal CDF fitting'];
title(sTitlestr)
xlabel('Magnitude');
ylabel('Non-cumulative FMD');
drawnow;


%{
Authors:
Jonatas Lopes de Paiva
Claudio Fabiano Motta Toledo
Helio Pedrini

%}

function f = crossover(p1, p2)

r = randi(3);
[linhas, colunas] = size(p1);
if (linhas == 0 || colunas == 0)
    fprinf('Error\n');
end

switch r

    case 1
        idx = randi(linhas);
        tmp = vertcat(p1(1:idx,:), p2(idx+1:linhas,:));
    case 2
        idx = randi(colunas);
        tmp = horzcat(p1(:,1:idx), p2(:,idx+1:colunas));
    case 3
        tmp = zeros(linhas, colunas);
        for i = 1: linhas
            for j = 1:colunas
                if(rand < 0.5)
                    tmp(i,j) = p1(i,j);
                else
                    tmp(i,j) = p2(i,j);
                end
            end
        end

end

f = tmp;
end


%% Copyright (C) 2014-2017, 2019 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy 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 software 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 software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defop  Method   @@sym {horzcat} {(@var{x}, @var{y}, @dots{})}
%% @defopx Operator @@sym {[@var{x}, @var{y}, @dots{}]} {}
%% @defopx Operator @@sym {[@var{x} @var{y} @dots{}]} {}
%% Horizontally concatentate symbolic arrays.
%%
%% Example:
%% @example
%% @group
%% A = sym([1 2; 3 4])
%%   @result{} A = (sym 2×2 matrix)
%%       ⎡1  2⎤
%%       ⎢    ⎥
%%       ⎣3  4⎦
%%
%% [A A A]
%%   @result{} (sym 2×6 matrix)
%%       ⎡1  2  1  2  1  2⎤
%%       ⎢                ⎥
%%       ⎣3  4  3  4  3  4⎦
%% @end group
%% @end example
%% @seealso{@@sym/vertcat, @@sym/cat}
%% @end defop

function h = horzcat(varargin)

  % special case for 0x0 but other empties should be checked for
  % compatibilty
  cmd = {
          '_proc = []'
          'for i in _ins:'
          '    if i is None or not i.is_Matrix:'
          '        _proc.append(sp.Matrix([[i]]))'
          '    else:'
          '        if i.shape == (0, 0):'
          '            pass'
          '        else:'
          '            _proc.append(i)'
          'return sp.MatrixBase.hstack(*_proc),'
          };

  for i = 1:nargin
    varargin{i} = sym(varargin{i});
  end
  h = pycall_sympy__ (cmd, varargin{:});

end

%!test
%! % basic
%! syms x
%! A = [x x];
%! B = horzcat(x, x);
%! C = horzcat(x, x, x);
%! assert (isa (A, 'sym'))
%! assert (isa (B, 'sym'))
%! assert (isa (C, 'sym'))
%! assert (isequal (size(A), [1 2]))
%! assert (isequal (size(B), [1 2]))
%! assert (isequal (size(C), [1 3]))

%!test
%! % basic, part 2
%! syms x
%! A = [x 1];
%! B = [1 x];
%! C = [1 2 x];
%! assert (isa (A, 'sym'))
%! assert (isa (B, 'sym'))
%! assert (isa (C, 'sym'))
%! assert (isequal (size(A), [1 2]))
%! assert (isequal (size(B), [1 2]))
%! assert (isequal (size(C), [1 3]))

%!test
%! % row vectors
%! a = [sym(1) 2];
%! b = [sym(3) 4];
%! assert (isequal ( [a b] , [1 2 3 4]  ))
%! assert (isequal ( [a 3 4] , [1 2 3 4]  ))
%! assert (isequal ( [3 4 a] , [3 4 1 2]  ))
%! assert (isequal ( [a [3 4]] , [1 2 3 4]  ))
%! assert (isequal ( [a sym(3) 4] , [1 2 3 4]  ))
%! assert (isequal ( [a [sym(3) 4]] , [1 2 3 4]  ))

%!test
%! % col vectors
%! a = [sym(1); 2];
%! b = [sym(3); 4];
%! assert (isequal ( [a b] , [1 3; 2 4]  ))
%! assert (isequal ( [a b a] , [1 3 1; 2 4 2]  ))

%!test
%! % empty vectors
%! v = sym(1);
%! a = [v []];
%! assert (isequal (a, v))
%! a = [[] v []];
%! assert (isequal (a, v))
%! a = [v [] []];
%! assert (isequal (a, v))

%!test
%! % more empty vectors
%! v = [sym(1) sym(2)];
%! q = sym(ones(1, 0));
%! assert (isequal ([v q], v))

%!error <ShapeError>
%! v = [sym(1) sym(2)];
%! q = sym(ones(3, 0));
%! w = horzcat(v, q);

%!test
%! % issue #700
%! A = sym ([1 2]);
%! B = simplify (A);
%! assert (isequal ([B A], [A B]))


classdef BatchNorm < dagnn.ElementWise
  properties
    numChannels
    epsilon = 1e-5
    opts = {'NoCuDNN'} % ours seems slightly faster
  end

  properties (Transient)
    moments
  end

  methods
    function outputs = forward(obj, inputs, params)
      if strcmp(obj.net.mode, 'test')
        outputs{1} = vl_nnbnorm(inputs{1}, params{1}, params{2}, ...
                                'moments', params{3}, ...
                                'epsilon', obj.epsilon, ...
                                obj.opts{:}) ;
      else
        [outputs{1},obj.moments] = ...
            vl_nnbnorm(inputs{1}, params{1}, params{2}, ...
                       'epsilon', obj.epsilon, ...
                       obj.opts{:}) ;
      end
    end

    function [derInputs, derParams] = backward(obj, inputs, params, derOutputs)
      [derInputs{1}, derParams{1}, derParams{2}, derParams{3}] = ...
        vl_nnbnorm(inputs{1}, params{1}, params{2}, derOutputs{1}, ...
                   'epsilon', obj.epsilon, ...
                   'moments', obj.moments, ...
                   obj.opts{:}) ;
      obj.moments = [] ;
      % multiply the moments update by the number of images in the batch
      % this is required to make the update additive for subbatches
      % and will eventually be normalized away
      derParams{3} = derParams{3} * size(inputs{1},4) ;
    end

    % ---------------------------------------------------------------------
    function obj = BatchNorm(varargin)
      obj.load(varargin{:}) ;
    end

    function params = initParams(obj)
      params{1} = ones(obj.numChannels,1,'single') ;
      params{2} = zeros(obj.numChannels,1,'single') ;
      params{3} = zeros(obj.numChannels,2,'single') ;
    end

    function attach(obj, net, index)
      attach@dagnn.ElementWise(obj, net, index) ;
      p = net.getParamIndex(net.layers(index).params{3}) ;
      net.params(p).trainMethod = 'average' ;
      net.params(p).learningRate = 0.1 ;
    end
  end
end


classdef TestGetPerspectiveTransform
    %TestGetPerspectiveTransform

    methods (Static)
        function test_1
            ref = [0, 1, 0; -1, 0, 1; 0, 0, 1];
            src = [0.0, 1.0; 1.0, 1.0; 1.0, 0.0; 0.25, 0.25];
            dst = [1.0, 1.0; 1.0, 0.0; 0.0, 0.0; 0.25, 0.75];
            t = cv.getPerspectiveTransform(src, dst);
            validateattributes(t, {'numeric'}, {'size',[3 3]});
            assert(all(abs(t(:)-ref(:)) < 1e-10));
        end

        function test_2
            ref = [0, 1, 0; -1, 0, 1; 0, 0, 1];
            src = num2cell([0.0, 1.0; 1.0, 1.0; 1.0, 0.0; 0.25, 0.25], 2);
            dst = num2cell([1.0, 1.0; 1.0, 0.0; 0.0, 0.0; 0.25, 0.75], 2);
            t = cv.getPerspectiveTransform(src, dst);
            validateattributes(t, {'numeric'}, {'size',[3 3]});
            assert(all(abs(t(:)-ref(:)) < 1e-10));
        end

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

end


function mogPrintPlot(model, lbls, capName, experimentNo)

% MOGPRINTPLOT Print projection of MOG into two dimensions.
% FORMAT
% DESC prints a projection of mixtures of Gaussians into two dimensions.
% ARG model : the model to use for plotting the latent space.
% ARG lbls : any lables that are available for plotting.
% ARG capName : the name of the saved plots.
% ARG experimentNo : the experiment number to assign to the files.
%
% SEEALSO : mogScatterPlot
%
% COPYRIGHT : Neil D. Lawrence, 2008

% MLTOOLS

if model.d>2
  model = mogProject(model, 2);
end

modelType = model.type;
modelType(1) = upper(modelType(1));

fileName = ['dem' capName modelType num2str(experimentNo)];

clf
ax = axes('position', [0.05 0.05 0.9 0.9]);
hold on
if ~isempty(lbls) && ~strcmp(lbls, 'connect')
  mogTwoDPlot(model, lbls, getSymbols(size(lbls, 2)));
else
  mogTwoDPlot(model, lbls);
end

piVals = linspace(-pi, pi, 200)';
for i=1:model.m
  a = line(model.mean(i, 1), model.mean(i, 2), 'marker', 'o');
  set(a, 'linewidth', 2, 'markersize', 10)
  x = [sin(piVals) cos(piVals)];
  el = x*model.U{i};
  line(model.mean(i, 1) + el(:, 1), model.mean(i, 2) + el(:, 2), ...
      'linewidth', 2);
end
xLim = [min(model.Y(:, 1)) max(model.Y(:, 1))]*1.1;
yLim = [min(model.Y(:, 2)) max(model.Y(:, 2))]*1.1;
set(ax, 'xLim', xLim);
set(ax, 'yLim', yLim);
set(gca, 'fontsize', 20);
printPlot(fileName, '../tex/diagrams/', '../html/')

figure
clf
ax = axes('position', [0.05 0.05 0.9 0.9]);
hold on
if ~isempty(lbls) && ~strcmp(lbls, 'connect')
  mogTwoDPlot(model, lbls, getSymbols(size(lbls, 2)));
else
  mogTwoDPlot(model, lbls);
end

%xLim = [min(model.Y(:, 1)) max(model.Y(:, 1))]*1.1;
%yLim = [min(model.Y(:, 2)) max(model.Y(:, 2))]*1.1;
set(ax, 'xLim', xLim);
set(ax, 'yLim', yLim);

%set(ax, 'fontname', 'arial');
set(ax, 'fontsize', 20);
printPlot([fileName 'NoOvals'], '../tex/diagrams/', '../html/')


function plot_tree_structure2(P,Bal,Segs,SChi,fig,ms,BO,segind)

% Plots the branch-segmented tree point cloud so that each branching order
% has its own color Blue = trunk, green = 1st-order branches,
% red = 2nd-order branches, etc.
%
% Inputs
% P         Point cloud
% Bal       Cover sets, Bal = cover.bal
% Segs      Segments, Segs = segment.segments
% SChi      Child segments, SChi = segment.ChildSegment
% fig       Figure number
% ms        Marker size
% BO        How many branching orders are plotted. 0 = all orders
% segind    Index of the segment where the plotting of tree structure
%                   starts. If segnum = 1 and BO = 0, then plots the whole
%                   tree. If segnum = 1 and B0 = 2, then plots the stem and
%                   the 1st-order branches. If segnum = 2 and BO = 0, then
%                   plots the branch whose index is 2 and all its sub-branches.

col = [
	0.00  0.00  1.00
	0.00  0.50  0.00
	1.00  0.00  0.00
	0.00  0.75  0.75
	0.75  0.00  0.75
	0.75  0.75  0.00
	0.25  0.25  0.25
	0.75  0.25  0.25
	0.95  0.95  0.00
	0.25  0.25  0.75
	0.75  0.75  0.75
	0.00  1.00  0.00
	0.76  0.57  0.17
	0.54  0.63  0.22
	0.34  0.57  0.92
	1.00  0.10  0.60
	0.88  0.75  0.73
	0.10  0.49  0.47
	0.66  0.34  0.65
	0.99  0.41  0.23];
col = repmat(col,[1000,1]);

if iscell(Segs{1})
    n = max(size(Segs));
    Seg = cell(n,1);
    for i = 1:n
        m = size(Segs{i},1);
        S = zeros(0);
        for j = 1:m
            s = Segs{i}(j);
            s = s{:};
            S = [S; s];
        end
        Seg{i} = S;
    end
else
    Seg = Segs;
end

if BO == 0
    BO = 1000;
end

S = vertcat(Bal{Seg{segind}});
figure(fig)
plot3(P(S,1),P(S,2),P(S,3),'.','Color',col(1,:),'Markersize',ms)
axis equal
forb = S;
if BO > 1
    %pause
    hold on
    c = SChi{segind};
    i = 2;
    while (i <= BO) && (~isempty(c))
        C = vertcat(Bal{unique(vertcat(Seg{c}))});
        C = setdiff(C,forb);
        figure(fig)
        plot3(P(C,1),P(C,2),P(C,3),'.','Color',col(i,:),'Markersize',ms)
        axis equal
        c = unique(vertcat(SChi{c}));
        i = i+1;
        forb = union(forb,C);
        if i <= BO
            %pause
        end
    end
    hold off
end


function f = squish(m,num)

% function f = squish(m,num)
%
% <m> is a matrix
% <num> is the positive number of initial dimensions to squish together
%
% return <m> squished.
%
% example:
% isequal(squish([1 2; 3 4],2),[1 3 2 4]')

% get the size of m
msize = [size(m) ones(1,num-ndims(m))];  % add ones to end if necessary

% calculate the new dimensions
newdim = [prod(msize(1:num)) msize(num+1:end)];

% do the reshape
f = reshape(m,[newdim 1]);  % tack on a 1 to handle the special case of squishing everything together


function sample = sampleFromCategorical(probabilities)
% sampleFromCategorical   Sample from a categorical distribution
%
%   sample = sampleFromCategorical(probabilities) returns an index sampled
%   from the categorical distribution represented by the input
%   probabilities.
%
%   Input:
%       probabilities   - A numClasses-by-1 vector of probabilities. The
%                         elements of this vector should sum to 1.
%
%   Output:
%       sample          - A number between 1 and numClasses that is sampled
%                         from the input probabilities.

cdf = cumsum(probabilities);
sample = find( cdf > rand );
sample = sample(1);

end


function det = dgbdi ( abd, lda, n, ml, mu, ipvt )

%*****************************************************************************80
%
%% DGBDI computes the determinant of a band matrix factored by DGBCO or DGBFA.
%
%  Discussion:
%
%    If the inverse is needed, use DGBSL N times.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 June 2005
%
%  Author:
%
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Dongarra, Moler, Bunch and Stewart,
%    LINPACK User's Guide,
%    SIAM, (Society for Industrial and Applied Mathematics),
%    3600 University City Science Center,
%    Philadelphia, PA, 19104-2688.
%    ISBN 0-89871-172-X
%
%  Parameters:
%
%    Input, real ABD(LDA,N), the output from DGBCO or DGBFA.
%
%    Input, integer LDA, the leading dimension of the array ABD.
%
%    Input, integer N, the order of the matrix.
%
%    Input, integer ML, MU, the number of diagonals below and above the
%    main diagonal.  0 <= ML < N, 0 <= MU < N.
%
%    Input, integer IPVT(N), the pivot vector from DGBCO or DGBFA.
%
%    Output, real DET(2), the determinant of the original matrix.
%      determinant = DET(1) * 10.0**DET(2)
%    with  1.0 <= abs ( DET(1) ) < 10.0 or DET(1) = 0.0.
%
  ten = 10.0;

  m = ml + mu + 1;
  det(1) = 1.0;
  det(2) = 0.0;

  for i = 1 : n

    if ( ipvt(i) ~= i )
      det(1) = -det(1);
    end

    det(1) = abd(m,i) * det(1);

    if ( det(1) == 0.0 )
      return
    end

    while ( abs ( det(1) ) < 1.0 )
      det(1) = ten * det(1);
      det(2) = det(2) - 1.0;
    end

    while ( ten <= abs ( det(1) ) )
      det(1) = det(1) / ten;
      det(2) = det(2) + 1.0;
    end

  end

  return
end


function varargout = createSoccerBall()
%CREATESOCCERBALL Create a 3D mesh representing a soccer ball.
%
%   It is basically a wrapper of the 'bucky' function in matlab.
%   [V, E, F] = createSoccerBall
%   return vertices, edges and faces that constitute a soccerball
%   V is a 60-by-3 array containing vertex coordinates
%   E is a 90-by-2 array containing indices of neighbor vertices
%   F is a 32-by-1 cell array containing vertex indices of each face
%   Example
%   [v, f] = createSoccerBall;
%   drawMesh(v, f);
%
%   See also
%   meshes, drawMesh, bucky

% ------
% Author: David Legland
% e-mail: david.legland@inra.fr
% Created: 2006-08-09
% Copyright 2006 INRA - CEPIA Nantes - MIAJ (Jouy-en-Josas).

%   HISTORY
%   2007-01-04 remove unused variables, enhance output processing
%   2010-12-07 clean up edges, uses formatMeshOutput

% get vertices and adjacency matrix of the buckyball
[b, n] = bucky;

% compute edges
[i, j] = find(b);
e = [i j];
e = unique(sort(e, 2), 'rows');

% compute polygons that correspond to each 3D face
f = minConvexHull(n)';

% format output
varargout = formatMeshOutput(nargout, n, e, f);


function [ result ] = get_subwindow( input_image, index, resx, resy, spacingx, spacingy )
% index is 0-N
%GET_SCRIPT Summary of this function goes here
%   Detailed explanation goes here

	maxPerRow = floor((size(input_image,2)-resx+spacingx) / spacingx);
    maxRows = floor((size(input_image,1) - resy+spacingy )/ spacingy);
    currentRow = floor(index / (maxPerRow));

    if (currentRow < maxRows)

        cutX = (mod(index,maxPerRow)*spacingx);
        cutY = (currentRow * spacingy);

        result = input_image(cutY+1:(cutY+resy),cutX+1:(cutX+resx),:);

    else
        result = 'error';
        %error('index too high, image overflow');
    end

end


% @KTENSOR
%
% Files
%   arrange      - Arranges the rank-1 components of a ktensor.
%   datadisp     - Special display of a ktensor.
%   disp         - Command window display for a ktensor.
%   display      - Command window display for a ktensor.
%   double       - Convert a ktensor to a double array.
%   end          - Last index of indexing expression for ktensor.
%   extract      - Creates a new ktensor with only the specified components.
%   fixsigns     - Fix sign ambiguity of a ktensor.
%   full         - Convert a ktensor to a (dense) tensor.
%   innerprod    - Efficient inner product with a ktensor.
%   isequal      - True if each component of two ktensor's is numerically equal.
%   ktensor      - Tensor stored as a Kruskal operator (decomposed).
%   minus        - Binary subtraction for ktensor.
%   mtimes       - Implement A*B (scalar multiply) for ktensor.
%   mttkrp       - Matricized tensor times Khatri-Rao product for ktensor.
%   ncomponents  - Number of components for a ktensor.
%   ndims        - Number of dimensions for a ktensor.
%   norm         - Frobenius norm of a ktensor.
%   normalize    - Normalizes the columns of the factor matrices.
%   nvecs        - Compute the leading mode-n vectors for a ktensor.
%   permute      - Permute dimensions of a ktensor.
%   plus         - Binary addition for ktensor.
%   redistribute - Distribute lambda values to a specified mode.
%   score        - Checks if two ktensors match except for permutation.
%   size         - Size of ktensor.
%   subsasgn     - Subscripted assignement for ktensor.
%   subsref      - Subscripted reference for a ktensor.
%   times        - Element-wise multiplication for ktensor.
%   tocell       - Convert X to a cell array.
%   ttm          - Tensor times matrix for ktensor.
%   ttv          - Tensor times vector for ktensor.
%   uminus       - Unary minus for ktensor.
%   uplus        - Unary plus for a ktensor.


%% Copyright (C) 2016-2017 Lagu
%% Copyright (C) 2017, 2022 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy 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 software 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 software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod @@sym [@var{K}, @var{E}] = ellipke (@var{m})
%% Complete elliptic integrals of the first and second kinds.
%%
%% Example:
%% @example
%% @group
%% syms m
%% [K, E] = ellipke (m)
%%   @result{} K = (sym) K(m)
%%   @result{} E = (sym) E(m)
%% @end group
%% @end example
%%
%% @seealso{ellipke, @@sym/ellipticK, @@sym/ellipticE}
%% @end defmethod

function varargout = ellipke(m)

  if (nargin ~= 1 || nargout > 2)
    print_usage ();
  end

  if (nargout == 0 || nargout == 1)
    varargout = {ellipticK(m)};
  else
    varargout = {ellipticK(m) ellipticE(m)};
  end

end

%!error ellipke (sym(1), 2)

%!test
%! for i = 2:10
%!   [K E] = ellipke (sym (1)/i);
%!   [k e] = ellipke (1/i);
%!   assert (double ([K E]), [k e], 2*eps)
%! end


function [res,ires]=dydt(t,y,yp,rpar)

global DEBUG;

res(1)=yp(1)+rpar(1)*y(1);
res(2)=yp(2)+rpar(2)*y(2);
res(3)=y(3)-y(1)-2.0;

ires = 0;

if ( DEBUG > 9 )
  buf1 = sprintf('%.4e ',y);
  buf2 = sprintf('%.4e ',yp);
  buf3 = sprintf('%.4e ',res);
  disp(sprintf('(Debug) dydt.m: t=%.2e y=%s yp=%s res=%s', ...
               t,buf1,buf2,buf3));
  if ( DEBUG > 99 )
    cbuf = input(sprintf('\tRETURN to continue : '));
  end
end


function d = dot_outer(S3G,q,varargin)
% return outer inner product of all nodes within a eps neighborhood
%
% Syntax
%   d = dot_outer(SO3G,nodes,'epsilon',radius)
%
% Input
%  SO3G   - @SO3Grid
%  nodes  - @quaternion
%  radius - double
%
% Output
%  d      - sparse matrix
%

if ~isa(S3G,'SO3Grid')
  d = dot_outer(q,S3G,varargin{:}).';
  return
end

epsilon = get_option(varargin,'epsilon',pi);

if check_option(varargin,{'full','all'})
  if check_option(varargin,'nospecimensymmetry')
    S3G.SS = specimenSymmetry;
  end
  d = dot_outer@orientation(S3G,q,varargin{:});

else

  d = sparse(length(S3G),length(q));

  % rotate q according to SO3Grid.center
  if ~isempty(S3G.center),q = inv(S3G.center) * q; end %#ok<MINV>

  % extract SO3Grid
  [ybeta,yalpha,ialphabeta,palpha] = getdata(S3G.alphabeta);

  ygamma = [S3G.gamma.points];
  sgamma = [S3G.gamma.min];
  pgamma = S3G.gamma(1).period;
  igamma = cumsum([0,GridLength(S3G.gamma)]);

  % correct for specimen symmetry
  if check_option(varargin,'nospecimensymmetry')
    qss = quaternion.id;
    palpha = 2*pi;
  else
    qss = quaternion(rotation_special(S3G.SS));
    palpha = max(palpha,pi);
  end

  % for finding the minimial beta angle
  qcs = quaternion(S3G.CS.rotation_special);

  [xalpha,xbeta,xgamma] = Euler( qss * quaternion(q) * qcs ,'ZYZ');

  ncs = length(qss)*length(qcs);
  cs = 0:length(q):ncs*length(q);

  for k=1:ncs

    ndx = cs(k)+1:cs(k+1);

    dist = SO3Grid_dist_region(yalpha,ybeta,ygamma, ...
      sgamma, int32(igamma), int32(ialphabeta), palpha, pgamma, ...
      xalpha(ndx), xbeta(ndx), xgamma(ndx), epsilon);

    if nnz(dist) > 0, d = max(d,dist); end

  end

end


function [fieldfeatures]=segfieldsfeat(imsegs,nsegments,smap,xspfield,spfind,spdata,features)
sinds=[1:nsegments];
xspfield(isnan(xspfield))=0;

if exist('spfind','var')
    spfind1{1}=spfind{1};%floor
    spfind1{2}=[spfind{2};spfind{3};spfind{4};spfind{5}];% walls+ceiling
    clear spfind;
    spfind=spfind1;
end

%get model for fields
if exist('spfind','var')
    bgmean=[];
    bgmedian=[];
    for f =1:numel(spfind)
        if numel(spfind1{f})==0
            bgmean(f,1:21)=0;
            bgmedian(f,1:21)=0;
            continue;
        end
        sparea = imsegs.npixels(spfind{f});
        npix = sum(sparea);
        spnorm = sparea / npix;

        bgmean(f,1:3) = sum( spdata(spfind{f}, 1:3).*repmat(spnorm, [1 3]), 1);
        bgmean(f,4:6) = rgb2hsv(bgmean(f, 1:3));
        bgmean(f,7:21)=sum(spdata(spfind{f}, 15:29) .* repmat(spnorm, [1 15]), 1);

        featinds = [1:3];
        for i=1:length(featinds)
            [vv,ii] = sort(spdata(spfind{f},featinds(i)));
            temp = cumsum(spnorm(ii));
            tempfeat1(i) = vv(min(find(temp>0.5)));
        end
        bgmedian(f,1:3) = tempfeat1(:)';
        bgmedian(f,4:6) = rgb2hsv(bgmedian(f, 1:3));

        featinds = [15:29];
        for i=1:length(featinds)
            [vv,ii] = sort(spdata(spfind{f},featinds(i)));
            temp = cumsum(spnorm(ii));
            tempfeat2(i) = vv(min(find(temp>0.5)));
        end
        bgmedian(f,7:21) = tempfeat2(:)';

    end
end

for k = 1:nsegments

    spind = find(smap==sinds(k));
    sparea = imsegs.npixels(spind);
    npix = sum(sparea);

    oarea=sum(xspfield(spind,:),1);
    tfeatures = oarea(:)';
    tfeatures=tfeatures/(npix+(npix==0));
    tempfieldfeatures=tfeatures;
    tempfieldfeatures(tfeatures==0)=eps;

    entfieldfeat=-1*sum(tfeatures.*log2(tempfieldfeatures));
    tfeatures=[tfeatures entfieldfeat ];
    fieldfeatures(k,:)=tfeatures;

    nf=numel(fieldfeatures);
    if exist('spfind','var')

        for tempf=1:size(bgmedian,1)
            fieldfeatures(k,nf+(1:5)) = [abs(bgmedian(tempf,1:4)-features(k,1:4)) ...
                norm((features(k,15:29)- bgmedian(tempf,7:21)),2)] ;%r g b h and mean tex res diff
            nf=nf+5;
        end
    end

end

end


function [Y,XYZ] = spm_read_vols(V,mask)
% Read in entire image volumes
% FORMAT [Y,XYZ] = spm_read_vols(V,mask)
% V    - vector of mapped image volumes to read in (from spm_vol)
% mask - implicit zero mask?
% Y    - 4D matrix of image data, fourth dimension indexes images
% XYZ  - 3xn matrix of XYZ locations returned
%_______________________________________________________________________
%
% For image data types without a representation of NaN (see spm_type),
% implicit zero masking can be used. If mask is set, then zeros are
% treated as masked, and returned as NaN.
%_______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Andrew Holmes
% $Id: spm_read_vols.m 1143 2008-02-07 19:33:33Z spm $

%-Argument checks
%-----------------------------------------------------------------------
if nargin<2, mask = 0; end
if nargin<1, error('insufficient arguments'), end

spm_check_orientations(V);

%-Read in image data
%-----------------------------------------------------------------------
n = numel(V);         %-#images
Y = zeros([V(1).dim(1:3),n]);       %-image data matrix

for i=1:n,
  for p=1:V(1).dim(3)
    Y(:,:,p,i) = spm_slice_vol(V(i),spm_matrix([0 0 p]),V(i).dim(1:2),0);
  end
end

%-Apply implicit zero mask for image datatypes without a NaNrep
%-----------------------------------------------------------------------
if mask
    %-Work out images without NaNrep
    im = logical(zeros(n,1));
    for i=1:n, im(i)=~spm_type(V(i).dt(1),'NaNrep'); end
    %-Mask
    Y(Y(:,:,:,im)==0)=NaN;
end

%-Return as 3D matrix if single image
%-----------------------------------------------------------------------
if n==1; Y=Y(:,:,:,1); end

%-Compute XYZ co-ordinates (if required)
%-----------------------------------------------------------------------
if nargout>1
    [R,C,P]=ndgrid(1:V(1).dim(1),1:V(1).dim(2),1:V(1).dim(3));
    RCP = [R(:)';C(:)';P(:)'];
    clear R C P
    RCP(4,:)=1;
    XYZ = V(1).mat(1:3,:)*RCP;
end


function [X, sigma2, W, model, modelInitVardist] = vargplvmEmbed2(Y, dims, varargin)
% VARGPLVMEMBED2 Embed given data Y into a lower dimensional manifold with Bayesian GP-LVM
%
% COPYRIGHT: Andreas C. Damianou, 2012
%
% VARGPLVM

% [X, sigma2, W, model, modelInitVardist] = vargplvmEmbed(Y, dims, varargin)
%
% varargin = {options, initIters, iters, display, optionsDyn}
% To do dynamical embedding, just call the function with all arguments in
% varargin (even if empty values are given, ie
% [..]=vargplvmEmbed2(Y, dims, [],[],[],[],[]);
%
% Like vargplvmEmbed but also has (optional) dynamics

vargplvm_init;

initVardistIters = 15;
iters = 50;
display = 1;

options = vargplvmOptions('dtcvar');
options.kern = 'rbfardjit';
options.numActive = min(50,size(Y,1));
options.optimiser = 'scg2';
options.initSNR = 100;
dynUsed = 0;
optionsDyn = [];

if nargin > 2
    if ~isempty(varargin{1})
        options = varargin{1};
    end
    if length(varargin)>1 && ~isempty(varargin{2}), initVardistIters = varargin{2}; end
    if length(varargin)>2 && ~isempty(varargin{3}), iters = varargin{3}; end
    if length(varargin)>3 && ~isempty(varargin{4}), display = varargin{4}; end
    if length(varargin)>4
        dynUsed=1;
        if ~isempty(varargin{5})
            optionsDyn = varargin{5};
        end
    end
end

globalOpt.initSNR = options.initSNR;

latentDim = dims;
d = size(Y, 2);

% demo using the variational inference method for the gplvm model
model = vargplvmCreate(latentDim, d, Y, options);
%
model = vargplvmParamInit(model, model.m, model.X);
model = vargplvmModelInit(model, globalOpt);

fprintf('#--- vargplvmEmbed from %d dims to %d dims (initSNR=%f)...\n',d,latentDim,vargplvmShowSNR(model, false));

if dynUsed
    %-------- Add dynamics to the model -----
    fprintf('  # Adding dynamics to the model...\n')
    if isempty(optionsDyn)
        optionsDyn.type = 'vargpTime';
        optionsDyn.t=[];
        optionsDyn.inverseWidth=30;
        optionsDyn.initX = model.X;%options.initX;
    end
    if ~isfield(optionsDyn, 'initX'), optionsDyn.initX = model.X; end
    % Fill in with default values whatever is not already set
    optionsDyn = vargplvmOptionsDyn(optionsDyn, model.X);
    optionsDyn.initX = options.initX;
    model = vargplvmAddDynamics(model, 'vargpTime', optionsDyn, optionsDyn.t, 0, 0,optionsDyn.seq);
    model = vargplvmInitDynamics(model,optionsDyn);
end

modelInit = model;%%%% Delete
%if dynUsed
%    model.dynamics.kern.comp{2}.variance = 1;
%end
% Optimise the model.
fprintf('  # vargplvmEmbed: Optimising var. distr. for %d iters...\n',initVardistIters);
if initVardistIters > 0
    model.initVardist = 1; model.learnSigmaf = false;
    model = vargplvmOptimise(model, display, initVardistIters);
end
modelInitVardist = model;
model.initVardist = false; model.learnSigmaf = true;
if ~isempty(iters)
    for i=1:length(iters)
        fprintf('\n  # vargplvmEmbed: Optimising for %d iters... (Session %d) \n',iters(i),i);
        model = vargplvmOptimise(model, display, iters(i));
    end
end
X = model.vardist.means;
sigma2 = model.vardist.covars;
W = vargplvmScales('get', model);

SNRfinal = vargplvmShowSNR(model, false);
fprintf('#--- Finished embedding. SNR: %f \n',SNRfinal);
fprintf('#--- Scales: %s\n\n', num2str(W));
if SNRfinal < 10
    warning(['During vargplvmEmbed SNR was too low (' num2str(SNRfinal) ')!'])
end


function [varargout]=sv3(varargin)

% function [hf]=sv3(M,v,optionStruct)
% ------------------------------------------------------------------------
% sv3 (slice view 3D) is a 3D slice viewer function. The 3D image data M is
% rendered using 3 mutally orthogonal slices. The option input v is the
% voxel size which scales the image appropriately in the 3 directions. The
% 3rd optional input vixOptStruct which can be used to make custom
% visualization settings. The default structure containts the following:
%
% optionStructDefault.colormap=gray(250); %colormap
% optionStructDefault.clim=[min(M(~isnan(M))) max(M(~isnan(M)))]; %color limits
% optionStructDefault.fontColor='w'; %font color
% optionStructDefault.fontSize=20; %font size
% optionStructDefault.edgeColor='none';
% optionStructDefault.figStruct=figStruct; %figure options (see cFigure)
% optionStructDefault.sliceIndices=round(size(M)/2); %Default mid-slices
% optionStructDefault.alphaLevel=1;
% optionStructDefault.origin=[0 0 0];
% optionStructDefault.updateFrequency=10;
%
% See also: sliceViewer, sv2, imx
%
% Change log:
% 2018/06/06 Added initial slice indices as option to input structure
% 2018/06/06 Added basic description at the top of this function
% 2019/08/09 Changed to use uicontrol slider rather than java slider due
% to future removal of javacomponent
% 2021/11/03 Fixed issue with specification of image origin and shifting
% slider
% ------------------------------------------------------------------------

%% Parse input

switch nargin
    case 1
        M=varargin{1};
        v=ones(1,3);
        optionStruct=[];
    case 2
        M=varargin{1};
        v=varargin{2};
        optionStruct=[];
    case 3
        M=varargin{1};
        v=varargin{2};
        optionStruct=varargin{3};
end

%Expand voxel size if it is scalar
if numel(v)==1
    v=v.*ones(1,3);
end

M=double(M); %Conver the image to a double

figStruct.Name='GIBBON: Slice viewer'; %Figure name
figStruct.Color='k'; %Figure background color
figStruct.ColorDef='black'; %Setting colordefinitions to black

optionStructDefault.colormap=gray(250); %colormap
optionStructDefault.clim=[min(M(~isnan(M))) max(M(~isnan(M)))]; %color limits
optionStructDefault.fontColor='w'; %font color
optionStructDefault.fontSize=20; %font size
optionStructDefault.edgeColor='none';
optionStructDefault.figStruct=figStruct; %figure options (see cFigure)
optionStructDefault.sliceIndices=round(size(M)/2); %Default mid-slices
optionStructDefault.alphaLevel=1;
optionStructDefault.origin=[0 0 0];
optionStructDefault.updateFrequency=10;

[optionStruct]=structComplete(optionStruct,optionStructDefault,1);

M=double(M);

%%
% Plot settings
scrollBarWidth=20; %Scrollbar width
fontColor=optionStruct.fontColor;
fontSize=optionStruct.fontSize;
cMap=optionStruct.colormap;
cLim=optionStruct.clim;
figStruct=optionStruct.figStruct;
alphaLevel=optionStruct.alphaLevel;
originLoc=optionStruct.origin;
updateFrequency=optionStruct.updateFrequency;

if all(isnan(cLim)) | all(isinf(cLim))
    cLim=[-1 1];
end

if diff(cLim)<eps
   cLim=cLim+[-1 1];
end

%%

%Defining row, column and slice indicices for slice patching
sliceIndexI=optionStruct.sliceIndices(1); %(close to) middle row
sliceIndexJ=optionStruct.sliceIndices(2); %(close to) middle column
sliceIndexK=optionStruct.sliceIndices(3); %(close to) middle slice

%%

[ax,ay,az]=im2cart([size(M,1)+1 0],[size(M,2)+1 0],[size(M,3)+1 0],v);

navString=['I: ',num2str(sliceIndexI),', J:  ',num2str(sliceIndexJ),', K: ',num2str(sliceIndexK)];

hf=cFigure(figStruct);
ht=gtitle(navString);
axis equal; axis tight; view(3);  axis vis3d; axis([ax(2) ax(1) ay(2) ay(1) az(2) az(1)]); grid on; box on; hold on;
colormap(cMap); colorbar;
caxis(cLim);
set(gca,'fontSize',fontSize);
drawnow;

%%

%Initialize sliders
hSlider_I= uicontrol(hf,'Style','slider','Position',[0,0,scrollBarWidth,round(hf.Position(4))]);
set(hSlider_I,'Value',sliceIndexI,'Min',1,'Max',size(M,1),'SliderStep',[1/(size(M,1)-1) 1/(size(M,1)-1)]);
hSlider_I.Callback={@plotSlice,{hf,hSlider_I,1}};
addlistener(hSlider_I,'ContinuousValueChange',@(hObject, event) plotSlice(hObject,event,{hf,hSlider_I,1}));
addlistener(hSlider_I,'Value','PostSet',@(hObject, event) plotSlice(hObject,event,{hf,hSlider_I,1}));

hSlider_J= uicontrol(hf,'Style','slider','Position',[1*scrollBarWidth,0,scrollBarWidth,round(hf.Position(4))]);
set(hSlider_J,'Value',sliceIndexJ,'Min',1,'Max',size(M,2),'SliderStep',[1/(size(M,2)-1) 1/(size(M,2)-1)]);
hSlider_J.Callback={@plotSlice,{hf,hSlider_J,2}};
addlistener(hSlider_J,'ContinuousValueChange',@(hObject, event) plotSlice(hObject,event,{hf,hSlider_J,2}));
addlistener(hSlider_J,'Value','PostSet',@(hObject, event) plotSlice(hObject,event,{hf,hSlider_J,2}));

hSlider_K= uicontrol(hf,'Style','slider','Position',[2*scrollBarWidth,0,scrollBarWidth,round(hf.Position(4))]);
set(hSlider_K,'Value',sliceIndexK,'Min',1,'Max',size(M,3),'SliderStep',[1/(size(M,3)-1) 1/(size(M,3)-1)]);
hSlider_K.Callback={@plotSlice,{hf,hSlider_K,3}};
addlistener(hSlider_K,'ContinuousValueChange',@(hObject, event) plotSlice(hObject,event,{hf,hSlider_K,3}));
addlistener(hSlider_K,'Value','PostSet',@(hObject, event) plotSlice(hObject,event,{hf,hSlider_K,3}));

%% Set resize function

set(hf,'ResizeFcn',{@setScrollSizeFunc,{hf,scrollBarWidth,hSlider_I,hSlider_J,hSlider_K}});

%%

t=clock;
hf.UserData.sv3.time=t;
hf.UserData.sv3.Name=figStruct.Name;
hf.UserData.sv3.M=M;
hf.UserData.sv3.v=v;
hf.UserData.sv3.patchTypes={'si','sj','sk'};
hf.UserData.sv3.sliceIndices=[sliceIndexI sliceIndexJ sliceIndexK];
hf.UserData.sv3.fontColor=fontColor;
hf.UserData.sv3.fontSize=fontSize;
hf.UserData.sv3.edgeColor=optionStruct.edgeColor;
hf.UserData.sv3.hp=nan(3,1);
hf.UserData.sv3.ht=ht;
hf.UserData.sv3.M_plot=M;
hf.UserData.sv3.alphaLevel=alphaLevel;
hf.UserData.sv3.origin=originLoc;
hf.UserData.sv3.sliderHandles=[hSlider_I,hSlider_J,hSlider_K];
hf.UserData.sv3.updateFrequency=updateFrequency;

%%
set(hSlider_I,'Value',sliceIndexI);
set(hSlider_J,'Value',sliceIndexJ);
set(hSlider_K,'Value',sliceIndexK);

%Initialize view
pause(1/updateFrequency); %Wait so plot will update
plotSlice([],[],{hf,hSlider_I,1});
hf.UserData.sv3.time=t; %Reset clock so this happens now
plotSlice([],[],{hf,hSlider_J,2});
hf.UserData.sv3.time=t; %Reset clock so this happens now
plotSlice([],[],{hf,hSlider_K,3});

drawnow;

%%
varargout{1}=hf;

end

function plotSlice(~,~,inputCell)

hf=inputCell{1};

jSlider=inputCell{2};
dirOpt=inputCell{3};
sliceIndex=round(get(jSlider,'Value'));
hf.UserData.sv3.sliceIndices(dirOpt)=sliceIndex;
sliceIndices=hf.UserData.sv3.sliceIndices;

dt=1/hf.UserData.sv3.updateFrequency;
t=hf.UserData.sv3.time;
t2=clock;
dtt=etime(t2,t); %Elapsed time

if dtt>dt %If ready to update
    hf.UserData.sv3.time=t2;

    M=hf.UserData.sv3.M_plot;
    v=hf.UserData.sv3.v;
    patchType=hf.UserData.sv3.patchTypes{dirOpt};

    logicPatch=false(size(M));
    switch dirOpt
        case 1
            logicPatch(sliceIndex,:,:)=1;
        case 2
            logicPatch(:,sliceIndex,:)=1;
        case 3
            logicPatch(:,:,sliceIndex)=1;
    end

    figure(hf); %TEMP FIX for bug in MATLAB 2018

    if isnan(hf.UserData.sv3.hp(dirOpt))
        [F,V,C]=im2patch(M,logicPatch,patchType);
        [V(:,1),V(:,2),V(:,3)]=im2cart(V(:,2),V(:,1),V(:,3),v);
        V=V+hf.UserData.sv3.origin(ones(size(V,1),1),:);
        hf.UserData.sv3.hp(dirOpt)= gpatch(F,V,C,hf.UserData.sv3.edgeColor,hf.UserData.sv3.alphaLevel);
    else
        V=get(hf.UserData.sv3.hp(dirOpt),'Vertices');
        switch dirOpt
            case 1
                V(:,2)=(sliceIndex-0.5).*v(1)+hf.UserData.sv3.origin(2);
            case 2
                V(:,1)=(sliceIndex-0.5).*v(2)+hf.UserData.sv3.origin(1);
            case 3
                V(:,3)=(sliceIndex-0.5).*v(3)+hf.UserData.sv3.origin(3);
        end
        set(hf.UserData.sv3.hp(dirOpt),'CData',M(logicPatch)); %Set color data
        set(hf.UserData.sv3.hp(dirOpt),'Vertices',V); %Set vertices
    end

    navString=['I: ',num2str(sliceIndices(1)),', J:  ',num2str(sliceIndices(2)),', K: ',num2str(sliceIndices(3))];

    set(hf.UserData.sv3.ht,'string',navString);

    hf.Name=[hf.UserData.sv3.Name,' ',navString];
end
end

function setScrollSizeFunc(~,~,inputCell)
hf=inputCell{1};
w=inputCell{2};

for q=3:numel(inputCell)
    hSlider=inputCell{q};
    posData=[w*(q-3),0,w,round(hf.Position(4))];
    set(hSlider,'Position',posData);
end

end

%%
% _*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 cmap = autumnCmap(numGrays,numColors)
%
% cmap = autumnCmap(numGrays,numColors)
%
% Makes colormap array with:
%   gray scale - 1:numGrays
%   autumn colors - numGrays+1:numGrays+numColors
%
% djh 1/98
if ~exist('numGrays','var')
  numGrays=128;
end
if ~exist('numColors','var')
  numColors=96;
end

cmap = zeros(numGrays+numColors,3);
cmap(1:numGrays+numColors,:) = [gray(numGrays); autumn(numColors)];

return


function [ a1, a2 ] = r8vec2_sort_a ( n, a1, a2 )

%*****************************************************************************80
%
%% R8VEC2_SORT_A ascending sorts an R8VEC2.
%
%  Discussion:
%
%    An R8VEC2 is two R8VEC's.
%
%    An R8VEC is a vector of R8 values.
%
%    Each item to be sorted is a pair (I,J), with the I
%    and J values stored in separate vectors A1 and A2.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 November 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of items of data.
%
%    Input, real A1(N), A2(N), the data to be sorted.
%
%    Output, real A1(N), A2(N), the sorted data.
%
  if ( n <= 1 )
    return
  end
%
%  Initialize.
%
  i = 0;
  indx = 0;
  isgn = 0;
  j = 0;
%
%  Call the external heap sorter.
%
  while ( 1 )

    [ indx, i, j ] = sort_heap_external ( n, indx, isgn );
%
%  Interchange the I and J objects.
%
    if ( 0 < indx )

      [ a1(i), a1(j) ] = r8_swap ( a1(i), a1(j) );
      [ a2(i), a2(j) ] = r8_swap ( a2(i), a2(j) );
%
%  Compare the I and J objects.
%
    elseif ( indx < 0 )

      isgn = r8vec2_compare ( n, a1, a2, i, j );

    elseif ( indx == 0 )

      break

    end

  end

  return
end


function [dt6, xformToAcpc, mmPerVoxel, fileName, desc, intentName] = dtiLoadTensorsFromNifti(ni)
%Load a dt6 (tensor) data file in mrDiffusion format from NIFTI format.
%
%  [dt6, xformToAcpc, mmPerVox, fileName, desc, intentName] = dtiLoadTensorsFromNifti(niFile)
%
% The six entries are the diffusion tensor values, derived from the raw
% data.  The raw data can be in many different directions.  The diffusion
% tensor is a 3x3 positive-definite matrix, D.  The entries in the matrix
% are stored in a vector:
%
%    Dxx Dyy Dzz Dxy Dxz Dyz
%
% or equivalently
%
%    D(1,1), D(2,2), D(3,3), D(1,2), D(1,3), D(2,3)
%
% HISTORY:
%  2007.10.04 AJS: Wrote it.
%
% (c) Stanford VISTA Team

if(~exist('ni','var')||isempty(ni))
    [f,p] = uigetfile({'*.nii.gz';'*.*'},'Select a NIFTI tensor file...');
    if(isnumeric(f)), disp('User canceled.'); return; end
    ni = fullfile(p,f);
end

if(ischar(ni))
    if exist(ni,'file'), ni = niftiRead(ni);
    else error('Can not find file %s\n',ni);
    end
end

fileName = ni.fname;

% We convert from the 5d, lower-tri row order NIFTI tensor format used by
% other groups, such as FSL, which stores (x,y,z,1,directions)
%    direction ordering:  (Dxx Dxy Dyy Dxz Dyz Dzz)
%
% to our 4d tensor format, (x,y,z,directions)
%    direction ordering: (Dxx Dyy Dzz Dxy Dxz Dyz).
%
dt6 = double(squeeze(ni.data(:,:,:,1,[1 3 6 2 4 5])));
xformToAcpc = ni.qto_xyz;
mmPerVoxel = ni.pixdim(1:3);
desc = ni.descrip;
intentName = ni.intent_name;

return


function [assignment, cost] = assignmentsuboptimal1(distMatrix)

%ASSIGNMENTSUBOPTIMAL1    Compute suboptimal assignment
%		ASSIGNMENTSUBOPTIMAL1(DISTMATRIX) computes a suboptimal assignment for the
%		given rectangular distance (or weight) matrix, for example the assignment
%		of tracks (in rows) to observations (in columns). The result is a column
%		vector containing the assigned column number in each row (or 0 if no
%		assignment could be done).
%
%		[ASSIGNMENT, COST] = ASSIGNMENTSUBOPTIMAL1(DISTMATRIX) returns the
%		assignment vector and the overall cost.
%
%		The algorithm is designed for distance matrices with many forbidden and
%		singly validated assignments, (rows or columns containing only one finite
%		element). The algorithm first searches the matrix for singly validated
%		columns and rejects all assignments with multiply validated row.
%		Afterwards, singly validated rows are searched and assignments to
%		multiply validated columns are rejected. Then, for each row that
%		validates only with singly validated columns (and the other way around),
%		the minimum elements is chosen and the assignment is made. If there are
%		still assignments open, the minimum element in the distMatrix is
%		searched and the corresponding assignment is made.
%
%		In scenarios without any forbidden assignments, the algorithm reduceds
%		to the last step is will give the same result as ASSIGNMENTOPTIMAL2. If
%		there are only some assignments forbidden, the algorithm will perform
%		poorly because singly validated assignments are preferred.
%
%		The last step can still be optimized, see the comments in
%		ASSIGNMENTOPTIMAL2.
%
%		Written by Markus Buehren, www.Lss.uni-stuttgart.de
%		Last modified 14.12.2004

% initialize
[nOfRows, nOfColumns] = size(distMatrix);
nOfValidObservations  = zeros(nOfRows,1);
nOfValidTracks        = zeros(1,nOfColumns);
assignment            = zeros(nOfRows,1);
cost                  = 0;

% compute number of validations for each track
for row=1:nOfRows
	nOfValidObservations(row) = length(find(isfinite(distMatrix(row,:))));
end

if any(nOfValidObservations < nOfColumns)

	if all(nOfValidObservations == 0)
		return
	end

	repeatSteps = 1;
	while repeatSteps

		repeatSteps = 0;

		% step 1: reject assignments of multiply validated tracks to singly validated observations
		for col=1:nOfColumns
			index = isfinite(distMatrix(:,col));
			nOfValidTracks(col) = length(find(index));
			if any(nOfValidObservations(index) == 1)
				index = index & (nOfValidObservations > 1);
				if any(index)
					distMatrix(index, col)      = inf;
					nOfValidObservations(index) = nOfValidObservations(index) - 1;
					nOfValidTracks(col)         = nOfValidTracks(col) - length(find(index));
					repeatSteps = 1;
				end
			end
		end

		% step 2: reject assignments of multiply validated observations to singly validated tracks
		if nOfColumns > 1
			for row=1:nOfRows
				index = isfinite(distMatrix(row,:));
				if any(nOfValidTracks(index) == 1)
					index = index & (nOfValidTracks > 1);
					if any(index)
						distMatrix(row, index)    = inf;
						nOfValidTracks(index)     = nOfValidTracks(index) - 1;
						nOfValidObservations(row) = nOfValidObservations(row) - length(find(index));
						repeatSteps = 1;
					end
				end
			end
		end

	end % while repeatSteps
	%disp(sprintf('xx = %d', xx));

	% for each multiply validated track that validates only with singly validated
	% observations, choose the observation with minimum distance
	for row=1:nOfRows
		if nOfValidObservations(row) > 1
			index = isfinite(distMatrix(row,:));
			if all(nOfValidTracks(index) == 1)
				[minDist, col] = min(distMatrix(row,:));
				assignment(row)    = col;
				cost               = cost + minDist;
				distMatrix(row,:)  = inf;
				distMatrix(:,col)  = inf;
			end
		end
	end

	% for each multiply validated observation that validates only with singly validated
	% track, choose the track with minimum distance
	for col=1:nOfColumns
		if nOfValidTracks(col) > 1
			index = isfinite(distMatrix(:,col));
			if all(nOfValidObservations(index) == 1)
				[minDist, row] = min(distMatrix(:,col));
				assignment(row)    = col;
				cost               = cost + minDist;
				distMatrix(row,:)  = inf;
				distMatrix(:,col)  = inf;
			end
		end
	end

end

% now, recursively search for the minimum element and do the assignment
while 1

	% find minimum distance observation-to-track pair
	[minDist, index1] = min(distMatrix, [], 1);
	[minDist, index2] = min(minDist);
	row = index1(index2);
	col = index2;

	if isfinite(minDist)

		% make the assignment
		assignment(row)    = col;
		cost               = cost + minDist;
		distMatrix(row, :) = inf;
		distMatrix(:, col) = inf;

	else
		break
	end

end


function lcd = getLowComplexityDistance(image,labels,graphDistances,colorHists,gradient,labelSet1,labelSet2,edgeImg , labelIndices)
Dmax = -Inf;
Dg = Inf;
De = 0;

lsum = 0;
for i = labelSet1
    for j = labelSet2
        Dmax = max(Dmax, getColorDistance(image,labels,colorHists,gradient,i,j));
        Dg = min(Dg, graphDistances(i,j));
        [de, l] = calculateGradientEdgeCost(edgeImg, labels, labelIndices, i,j);
        lsum = l + lsum;
        De = De + l * de;
    end
end

if(lsum == 0)
    De = 0;
else
    De = De/lsum;
end

lcd = Dg + Dmax + De;

end

github-repos/MATLAB/zhangqianqianQQ-MachineVisionAlgorithm/MachineVisionAlgorithm-683338f6c3b1aab9fa2b80026915fe936aebf0ee/识别算法/Object Recognition based on super pixel/getLowComplexityDistance.m


classdef TestAccumulateProduct
    %TestAccumulateProduct

    methods (Static)
        function test_1
            sz = [10 20];
            dst = zeros(sz);
            for i=1:5
                dst = cv.accumulateProduct(rand(sz), rand(sz), dst);
            end
            validateattributes(dst, {'double'}, {'size',sz});
        end

        function test_2
            sz = [10 20];
            dst = zeros(sz, 'single');
            for i=1:5
                dst = cv.accumulateProduct(randi([0 255],sz,'uint8'), ...
                    randi([0 255],sz,'uint8'), dst);
            end
            validateattributes(dst, {'single'}, {'size',sz});
        end

        function test_3
            sz = [10 20];
            dst = zeros(sz);
            for i=1:5
                src = rand(sz);
                mask = (rand(sz) > 0.5);
                dst = cv.accumulateProduct(src, src, dst, 'Mask',mask);
            end
        end

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

end


function IC = clusterMontage( I, IDX, nElem, pad )
% Used for visualization of clusters of images and videos.
%
% Organizes the matrix I, which is either MxNxR for images or MxNxTxR for
% videos, into a [M x N x T x nElem x nCluster] array IC, where each
% element IC(:,:,:,:,i) is the set of objects belonging to cluster i.
% If not all clusters have the same size, if pad==1 blank elements are
% added to pad the clusters so they do in fact have the same size, and if
% pad is 0 then IC is a cell vector where IC{i} is the set of objects
% belonging to cluster i.
%
% To display only a subset of clusters, given in a vector cs, use IDXb:
%  IDXb = zeros(size(IDX)); for i=1:length(cs) IDXb(IDX==cs(i))=i; end;
%
% USAGE
%  IC = clusterMontage( I, IDX, nElem, [pad] )
%
% INPUTS
%  I       - MxNxR array of images or MxNxTxR array of videos
%  IDX     - cluster membership (Rx1 integer vector) [see kmeans2.m]
%  nElem   - max number of instances to show of each cluster
%  pad     - [1] pads each cluster w blanks so it has exactly nElem
%
% OUTPUTS
%  IC      - if pad==1  [M x N x T x nElem x nCluster] array
%          - if pad==0  nCluster cell of [M x N x T x nElem_i] arrays
%
% EXAMPLE - images
%  load( 'images.mat' );
%  keep=randSample(144,80); IDXi=IDXi(keep); images=images(:,:,keep);
%  IC = clusterMontage( images, IDXi, 9, 0 );
%  figure(1); montage2( IC )
%
% EXAMPLE - videos
%  load( 'images.mat' );
%  IC = clusterMontage( videos, IDXv, 9, 0 );
%  figure(1); playMovie( IC )
%
% See also KMEANS2, MONTAGE2, PLAYMOVIE, CELL2ARRAY
%
% Piotr's Computer Vision Matlab Toolbox      Version 2.0
% Copyright 2014 Piotr Dollar.  [pdollar-at-gmail.com]
% Licensed under the Simplified BSD License [see external/bsd.txt]

if( nargin<4 || isempty(pad) ); pad=1; end

% error check
siz = size(I); nd = ndims(I);
if(nd~=3 && nd~=4); error('I must be 3 or 4 dimensional array'); end;
inds = {':'}; inds = inds(:,ones(1,nd-1));

% discard outliers
keepLocs = find( IDX>0 ); IDX = IDX(keepLocs); I=I(inds{:},keepLocs);

% sample both I and IDX so have nElem per cluster
uIDX=unique(IDX)';
for i=uIDX
  locs = find(IDX==i);  nLocs = length(locs);
  if( nLocs>nElem )
    keepLocs = [find(IDX~=i); locs(randSample(nLocs,nElem))];
    IDX = IDX(keepLocs); I=I(inds{:},keepLocs);
  elseif( nLocs<nElem && pad )
    nAdd = nElem-nLocs;
    IDX = [IDX; repmat(i,[nAdd,1])]; %#ok<AGROW>
    I = cat( nd, I, repmat(uint8(0),[siz(1:nd-1) nAdd]));
  end;
end;

% string out I
if( pad )
  IC = repmat( uint8(0), [siz(1:nd-1), nElem, length(uIDX)] );
  for i=uIDX; IC(inds{:},:,i) = I(inds{:},IDX==i); end
else
  IC = cell(1,max(IDX));
  for i=uIDX; IC{i} = I(inds{:},IDX==i); end
end


function [labv, labh] = testImageGraphCuts(spdata, edata, adjlist, vclassifierSP, hclassifierSP, eclassifier, ecal)

% probability of superpixel main labels
pvSP = test_boosted_dt_mc(vclassifierSP, spdata);
pvSP = 1 ./ (1+exp(-pvSP));
pvSP = pvSP ./ repmat(sum(pvSP, 2), 1, size(pvSP, 2));
[tmp, vmax] = max(pvSP, [], 2);

% probability of superpixel sub labels
phSP = test_boosted_dt_mc(hclassifierSP, spdata);
phSP = 1 ./ (1+exp(-phSP));
phSP = phSP ./ repmat(sum(phSP, 2), 1, size(phSP, 2));
[tmp, hmax] = max(phSP, [], 2);

% edge probability
pE = test_boosted_dt_mc(eclassifier, edata);
pE = 1 ./ (1+exp(ecal(1)*pE+ecal(2)));

%labv = alphaExpansion(pvSP, pE, adjlist);
labh = hmax;
labv = vmax;
% vind = find(labv==2);
% vaind = find((labv(adjlist(:, 1)) == 2) & (labv(adjlist(:, 2)) == 2));
% adjlisth = adjlist(vaind, :);
% for k = 1:size(adjlisth, 1)
%     s1 = find(adjlisth(k, 1)==vind);
%     s2 = find(adjlisth(k, 2)==vind);
%     adjlisth(k, :) = [s1 s2];
% end
% pEh = pE(vaind);
% phSP = phSP(vind, :);
%
% labh = hmax;
% tmplabh = alphaExpansion(phSP, pEh, adjlisth);
% labh(vind) = tmplabh;

%labh = alphaExpansion(phSP, pE, adjlist);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function lab = alphaExpansion(plab, pE, adjlist)

nsp = size(plab, 1);
nadj = size(adjlist, 1);

epenalty = max(log(pE)-log(1-pE), 0);% -log(1-pE); %

[tmp, lab] = max(plab, [], 2);
success = 1;
while success
    success = 0;
    for y = 1:3
        aux = find(lab(adjlist(:,1))~=lab(adjlist(:, 2)));
        naux = numel(aux);
        nnodes = nsp + naux;

        STE = zeros(2, nnodes);
        STE(1, 1:nsp) = -log(plab(:, y)');
        aind = find(lab==y);
        naind = find(lab~=y);
        STE(2, aind) = Inf;
        STE(2, naind) = -log(plab(nsp*(lab(naind)-1)+naind)); % -log P(current label)
        STE(2, nsp+1:end) = epenalty(aux);

        % nodes include main nodes and aux nodes for dealing with edges
        % between different-label nodes
        E_n = zeros(2, nadj+naux);
        E_n(1:2, 1:nadj) = adjlist';
        E_n(2, (nadj+1):(nadj+naux)) = E_n(2, aux);
        E_n(2, aux) = nsp+[1:naux];
        E_n(1, (nadj+1):(nadj+naux)) = E_n(2, aux);

        E_w = zeros(2, nadj+naux);
        for k = setdiff([1:nadj], aux')
            if lab(adjlist(k, 1)==y)
                E_w(:, k) = 0;
            else
                E_w(:, k) = epenalty(k);
            end
        end
        for k = 1:numel(aux)
            k1 = aux(k);
            k2 = k+nadj;
            if lab(adjlist(k1, 1)~=y)
                E_w(:, k) = epenalty(k1);
            end
            if lab(adjlist(k1, 2)~=y)
                E_w(:, k2) = epenalty(k1);
            end
        end

        [cut, flow] = vgg_graph_maxflow(uint32(nnodes), int16(100*STE), uint32(E_n), int16(100*E_w));

        lab2 = lab;
        lab2(logical(cut(1:nsp))) = y;

        energy1 = sum(-log(plab(nsp*(lab-1)+[1:nsp]'))) + sum(epenalty(aux));

        aux2 = find(lab2(adjlist(:,1))~=lab2(adjlist(:, 2)));
        energy2 = sum(-log(plab(nsp*(lab2-1)+[1:nsp]'))) + sum(epenalty(aux2));

        if energy2 < energy1
            %disp(['Energy 1 = ' num2str(energy1) '   Energy 2 = ' num2str(energy2)]);
            lab = lab2;
            success = 1;
        end
    end
end


% PERTURBK - Perturbs the current solution to the solution valid for the
%            given kernel parameter.
%
% Syntax: [a,b,g,ind,X_mer,y_mer,Rs,Q] = perturbk(scale)
%
%      a: alpha coefficients
%      b: bias
%      g: partial derivatives of cost function w.r.t. alpha coefficients
%    ind: cell array containing indices of margin, error and reserve vectors
%         ind{1}: indices of margin vectors
%         ind{2}: indices of error vectors
%         ind{3}: indices of reserve vectors
%  X_mer: matrix of margin, error and reserve vectors stored columnwise
%  y_mer: column vector of class labels (-1/+1) for margin, error and reserve vectors
%     Rs: inverse of extended kernel matrix for margin vectors
%      Q: extended kernel matrix for all vectors
%  scale: kernel scale
%
% Version 3.22e -- Comments to diehl@alumni.cmu.edu
%

function [a,b,g,ind,X,y,Rs,Q] = perturbk(new_scale)

% flags for example state
MARGIN    = 1;
ERROR     = 2;
RESERVE   = 3;
UNLEARNED = 4;

% define global variables
global a;             % alpha coefficients
global b;             % bias
global C;             % regularization parameters
global deps;          % jitter factor in kernel matrix
global g;             % partial derivatives of cost function w.r.t. alpha coefficients
global ind;           % cell array containing indices of margin, error, reserve and unlearned vectors
global num_unlearned; % number of unlearned vectors initially
global perturbations; % number of perturbations
global Q;             % extended kernel matrix for all vectors
global Rs;            % inverse of extended kernel matrix for margin vectors
global scale;			 % kernel scale
global type;          % kernel type
global X;             % matrix of margin, error, reserve and unlearned vectors stored columnwise
global y;             % column vector of class labels (-1/+1) for margin, error, reserve and unlearned vectors

kernel_evals_begin = kevals;
num_examples = size(X,2);

% sum{k in U} Qik lambda k and sum{k in U} yk lambda k
SQl = zeros(num_examples,1);
Syl = 0;

% adjust kernel scale
scale = new_scale;

% recompute g for the margin, error and reserve vectors
inda = [ind{MARGIN} ind{ERROR} ind{RESERVE}];
[f,K] = svmeval(X(:,inda));
g(inda) = y(inda).*f + a(inda)*deps - 1;

% identify the unlearned vectors and compute their coefficient sensitivities
lambda = zeros(num_examples,1);

% find all error vectors with g >= 0
flag = (g(ind{ERROR}) >= 0);
i = find(flag);

if (length(i) > 0)

   % relabel error vectors with g >= 0 as unlearned
   ind{UNLEARNED} = [ind{UNLEARNED} ind{ERROR}(i)];

   % coefficient sensitivities
   lambda(ind{ERROR}(i)) = -a(ind{ERROR}(i));

   % update sums
   SQl(inda) = SQl(inda) + ((y(ind{ERROR}(i))*y(inda)').*K(length(ind{MARGIN})+i,:))'*lambda(ind{ERROR}(i));
   Syl = Syl + y(ind{ERROR}(i))'*lambda(ind{ERROR}(i));

   % keep remaining error vectors labeled as such
   ind{ERROR}(i) = [];

end;

% find all reserve vectors with g <= 0
flag = (g(ind{RESERVE}) <= 0);
i = find(flag);

if (length(i) > 0)

   % relabel reserve vectors with g <= 0 as unlabeled
   ind{UNLEARNED} = [ind{UNLEARNED} ind{RESERVE}(i)];

   % coefficient sensitivities
   lambda(ind{RESERVE}(i)) = C(ind{RESERVE}(i));

   % update sums
   SQl(inda) = SQl(inda) + ((y(inda)*y(ind{RESERVE}(i))').*kernel(X(:,inda),X(:,ind{RESERVE}(i)),type,scale))*lambda(ind{RESERVE}(i));
   Syl = Syl + y(ind{RESERVE}(i))'*lambda(ind{RESERVE}(i));

   % keep remaining reserve vectors labeled as such
   ind{RESERVE}(i) = [];

end;

% find all margin vectors with g > 0
flag = (g(ind{MARGIN}) > 0);
i = find(flag);

if (length(i) > 0)

   % coefficient sensitivities
   lambda(ind{MARGIN}(i)) = -a(ind{MARGIN}(i));

   % update sums
   SQl(inda) = SQl(inda) + ((y(ind{MARGIN}(i))*y(inda)').*K(i,:))'*lambda(ind{MARGIN}(i));
   Syl = Syl + y(ind{MARGIN}(i))'*lambda(ind{MARGIN}(i));

end;

% find all margin vectors with g <= 0
flag = ~flag;
i = find(flag);

if (length(i) > 0)

   % coefficient sensitivities
   lambda(ind{MARGIN}(i)) = C(ind{MARGIN}(i))-a(ind{MARGIN}(i));

   % update sums
   SQl(inda) = SQl(inda) + ((y(ind{MARGIN}(i))*y(inda)').*K(i,:))'*lambda(ind{MARGIN}(i));
   Syl = Syl + y(ind{MARGIN}(i))'*lambda(ind{MARGIN}(i));

end;

% relabel margin vectors as unlearned
ind{UNLEARNED} = [ind{UNLEARNED} ind{MARGIN}];
ind{MARGIN} = [];

% add jitter factor
SQl(ind{UNLEARNED}) = SQl(ind{UNLEARNED}) + deps*lambda(ind{UNLEARNED});

% number of unlearned vectors initially
num_unlearned = length(ind{UNLEARNED});
s = sprintf('Number of unlearned vectors: %d',num_unlearned);
disp(s);

% reset Q and Rs
Q = Q(1,:);
Rs = Inf;

p_s = 0;
num_MVs = length(ind{MARGIN});
num_learned = 0;
perturbations = 0;
while ((length(ind{UNLEARNED}) > 0) | ((p_s < 1) & (length(ind{UNLEARNED}) == 0)))

   perturbations = perturbations + 1;

   % compute beta and gamma
   if (num_MVs > 0)

      v = zeros(num_MVs+1,1);
      if (p_s < 1-eps)
         v(1) = -Syl - sum(y.*a)/(1-p_s);
      else
         v(1) = -Syl;
      end;
      v(2:num_MVs+1) = -SQl(ind{MARGIN});
      beta = Rs*v;
      gamma = zeros(size(Q,2),1);
      ind_temp = [ind{ERROR} ind{RESERVE} ind{UNLEARNED}];
      gamma(ind_temp) = Q(:,ind_temp)'*beta + SQl(ind_temp);

   else

      beta = 0;
      gamma = SQl;

   end;

   % minimum acceptable parameter change
   [min_dps,indss,cstatus,nstatus] = min_delta_p_s(p_s,gamma,beta,lambda);

   % update a, b, g and p_s
   if (length(ind{UNLEARNED}) > 0)
      a(ind{UNLEARNED}) = a(ind{UNLEARNED}) + lambda(ind{UNLEARNED})*min_dps;
   end;
   if (num_MVs > 0)
      a(ind{MARGIN}) = a(ind{MARGIN}) + beta(2:num_MVs+1)*min_dps;
   end;
   b = b + beta(1)*min_dps;
   g = g + gamma*min_dps;
   p_s = p_s + min_dps;

   % perform bookkeeping
   indco = bookkeeping(indss,cstatus,nstatus);

   % set g(ind{MARGIN}) to zero
   g(ind{MARGIN}) = 0;

   % update Rs and Q if necessary
   if (nstatus == MARGIN)

      num_MVs = num_MVs + 1;
      if (num_MVs > 1)

         % compute beta and gamma for indss
         beta = -Rs*Q(:,indss);
         gamma = kernel(X(:,indss),X(:,indss),type,scale) + deps + Q(:,indss)'*beta;

      end;

      % expand Rs and Q
      updateRQ(beta,gamma,indss);

   elseif (cstatus == MARGIN)

      % compress Rs and Q
      num_MVs = num_MVs - 1;
      updateRQ(indco);

   end;

   % update SQl and Syl when the current status of indss is UNLEARNED
   if (cstatus == UNLEARNED)
      num_learned = num_learned + 1;
      if (nstatus == MARGIN)
         SQl = SQl - Q(num_MVs+1,:)'*lambda(indss);
      else
         SQl = SQl - ((y*y(indss)).*kernel(X,X(:,indss),type,scale))*lambda(indss);
         SQl(indss) = SQl(indss) - deps*lambda(indss);
      end;
      Syl = Syl - y(indss)*lambda(indss);

      if (mod(num_learned,50) == 0)
         s = sprintf('Learned %d examples.',num_learned);
         disp(s);
      end;
   end;

end;
disp('Perturbation complete!');

% summary statistics
s = sprintf('\nMargin vectors:\t\t%d',length(ind{MARGIN}));
disp(s);
s = sprintf('Error vectors:\t\t%d',length(ind{ERROR}));
disp(s);
s = sprintf('Reserve vectors:\t%d',length(ind{RESERVE}));
disp(s);
s = sprintf('Kernel evaluations:\t%d\n',-kernel_evals_begin+kevals);
disp(s);


function [anchors, im_scales] = proposal_locate_anchors(conf, im_size, target_scale, feature_map_size)
% [anchors, im_scales] = proposal_locate_anchors(conf, im_size, target_scale, feature_map_size)
% --------------------------------------------------------
% Faster R-CNN
% Copyright (c) 2015, Shaoqing Ren
% Licensed under The MIT License [see LICENSE for details]
% --------------------------------------------------------
% generate anchors for each scale

    % only for fcn
    if ~exist('feature_map_size', 'var')
        feature_map_size = [];
    end

    func = @proposal_locate_anchors_single_scale;

    if exist('target_scale', 'var')
        [anchors, im_scales] = func(im_size, conf, target_scale, feature_map_size);
    else
        [anchors, im_scales] = arrayfun(@(x) func(im_size, conf, x, feature_map_size), ...
            conf.scales, 'UniformOutput', false);
    end
end

function [anchors, im_scale] = proposal_locate_anchors_single_scale(im_size, conf, target_scale, feature_map_size)
    if isempty(feature_map_size)
        im_scale = prep_im_for_blob_size(im_size, target_scale, conf.max_size);
        img_size = round(im_size * im_scale);
        output_size = cell2mat([conf.output_height_map.values({img_size(1)}), conf.output_width_map.values({img_size(2)})]);
    else
        im_scale = prep_im_for_blob_size(im_size, target_scale, conf.max_size);
        output_size = feature_map_size;
    end

    shift_x = [0:(output_size(2)-1)] * conf.feat_stride;
    shift_y = [0:(output_size(1)-1)] * conf.feat_stride;
    [shift_x, shift_y] = meshgrid(shift_x, shift_y);

    % concat anchors as [channel, height, width], where channel is the fastest dimension.
    anchors = reshape(bsxfun(@plus, permute(conf.anchors, [1, 3, 2]), ...
        permute([shift_x(:), shift_y(:), shift_x(:), shift_y(:)], [3, 1, 2])), [], 4);
%   equals to
%     anchors = arrayfun(@(x, y) single(bsxfun(@plus, conf.anchors, [x, y, x, y])), shift_x, shift_y, 'UniformOutput', false);
%     anchors = reshape(anchors, [], 1);
%     anchors = cat(1, anchors{:});

end


% This is material illustrating the methods from the book
% Financial Modelling  - Theory, Implementation and Practice with Matlab
% source
% Wiley Finance Series
% ISBN 978-0-470-74489-5
%
% Date: 02.05.2012
%
% Authors:  Joerg Kienitz
%           Daniel Wetterau
%
% Please send comments, suggestions, bugs, code etc. to
% kienitzwetterau_FinModelling@gmx.de
%
% (C) Joerg Kienitz, Daniel Wetterau
%
% Since this piece of code is distributed via the mathworks file-exchange
% it is covered by the BSD license
%
% This code is being provided solely for information and general
% illustrative purposes. The authors will not be responsible for the
% consequences of reliance upon using the code or for numbers produced
% from using the code.

function y = psabr_complex(a,b,r,n,f,k,t)
% sabr risk neutral density using Benhamou et al. pricing formula

    eps = 1e-006;

    y1 = sabr_complex(f,k+eps,t,a,b,r,n);
    y2 = sabr_complex(f,k,t,a,b,r,n);
    y3 = sabr_complex(f,k-eps,t,a,b,r,n);
    y = (y1-2*y2+y3)/eps^2;
    y(isnan(y)) = 0;
end


function c = tapas_hgf_binary_config
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Contains the configuration for the Hierarchical Gaussian Filter (HGF)
% for binary inputs in the absence of perceptual uncertainty.
%
% The HGF is the model introduced in
%
% Mathys C, Daunizeau J, Friston, KJ, and Stephan KE. (2011). A Bayesian foundation
% for individual learning under uncertainty. Frontiers in Human Neuroscience, 5:39.
%
% The binary HGF model has since been augmented with a positive factor kappa1 which
% scales the second level with respect to the first, i.e., the relation between the
% first and second level is
%
% p(x1=1|x2) = s(kappa1*x2), where s(.) is the logistic sigmoid.
%
% By default, kappa1 is fixed to 1, leading exactly to the model introduced in
% Mathys et al. (2011).
%
% This file refers to BINARY inputs (Eqs 1-3 in Mathys et al., (2011));
% for continuous inputs, refer to tapas_hgf_config.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% The HGF configuration consists of the priors of parameters and initial values. All priors are
% Gaussian in the space where the quantity they refer to is estimated. They are specified by their
% sufficient statistics: mean and variance (NOT standard deviation).
%
% Quantities are estimated in their native space if they are unbounded (e.g., the omegas). They are
% estimated in log-space if they have a natural lower bound at zero (e.g., the sigmas).
%
% Parameters can be fixed (i.e., set to a fixed value) by setting the variance of their prior to
% zero. Aside from being useful for model comparison, the need for this arises whenever the scale
% and origin at the j-th level are arbitrary. This is the case if the observation model does not
% contain the representations mu_j and sigma_j. A choice of scale and origin is then implied by
% fixing the initial value mu_j_0 of mu_j and either kappa_j-1 or omega_j-1.
%
% Fitted trajectories can be plotted by using the command
%
% >> tapas_hgf_binary_plotTraj(est)
%
% where est is the stucture returned by tapas_fitModel. This structure contains the estimated
% perceptual parameters in est.p_prc and the estimated trajectories of the agent's
% representations (cf. Mathys et al., 2011). Their meanings are:
%
%         est.p_prc.mu_0       row vector of initial values of mu (in ascending order of levels)
%         est.p_prc.sa_0       row vector of initial values of sigma (in ascending order of levels)
%         est.p_prc.rho        row vector of rhos (representing drift; in ascending order of levels)
%         est.p_prc.ka         row vector of kappas (in ascending order of levels)
%         est.p_prc.om         row vector of omegas (in ascending order of levels)
%
% Note that the first entry in all of the row vectors will be NaN because, at the first level,
% these parameters are either determined by the second level (mu_0 and sa_0) or undefined (rho,
% kappa, and omega).
%
%         est.traj.mu          mu (rows: trials, columns: levels)
%         est.traj.sa          sigma (rows: trials, columns: levels)
%         est.traj.muhat       prediction of mu (rows: trials, columns: levels)
%         est.traj.sahat       precisions of predictions (rows: trials, columns: levels)
%         est.traj.v           inferred variance of random walk (rows: trials, columns: levels)
%         est.traj.w           weighting factors (rows: trials, columns: levels)
%         est.traj.da          volatility prediction errors  (rows: trials, columns: levels)
%         est.traj.ud          updates with respect to prediction  (rows: trials, columns: levels)
%         est.traj.psi         precision weights on prediction errors  (rows: trials, columns: levels)
%         est.traj.epsi        precision-weighted prediction errors  (rows: trials, columns: levels)
%         est.traj.wt          full weights on prediction errors (at the first level,
%                                  this is the learning rate) (rows: trials, columns: levels)
%
% Note that in the absence of sensory uncertainty (which is the assumption here), the first
% column of mu, corresponding to the first level, will be equal to the inputs. Likewise, the
% first column of sa will be 0 always.
%
% Tips:
% - When analyzing a new dataset, take your inputs u and use
%
%   >> est = tapas_fitModel([], u, 'tapas_hgf_binary_config', 'tapas_bayes_optimal_binary_config');
%
%   to determine the Bayes optimal perceptual parameters (given your current priors as defined in
%   this file here, so choose them wide and loose to let the inputs influence the result). You can
%   then use the optimal parameters as your new prior means for the perceptual parameters.
%
% - If you get an error saying that the prior means are in a region where model assumptions are
%   violated, lower the prior means of the omegas, starting with the highest level and proceeding
%   downwards.
%
% - Alternatives are lowering the prior means of the kappas, if they are not fixed, or adjusting
%   the values of the kappas or omegas, if any of them are fixed.
%
% - If the log-model evidence cannot be calculated because the Hessian poses problems, look at
%   est.optim.H and fix the parameters that lead to NaNs.
%
% - Your guide to all these adjustments is the log-model evidence (LME). Whenever the LME increases
%   by at least 3 across datasets, the adjustment was a good idea and can be justified by just this:
%   the LME increased, so you had a better model.
%
% --------------------------------------------------------------------------------------------------
% Copyright (C) 2012-2017 Christoph Mathys, TNU, UZH & ETHZ
%
% This file is part of the HGF toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

% Config structure
c = struct;

% Model name
c.model = 'hgf_binary';

% Number of levels (minimum: 3)
c.n_levels = 3;

% Input intervals
% If input intervals are irregular, the last column of the input
% matrix u has to contain the interval between inputs k-1 and k
% in the k-th row, and this flag has to be set to true
c.irregular_intervals = false;

% Sufficient statistics of Gaussian parameter priors

% Initial mus and sigmas
% Format: row vectors of length n_levels
% For all but the first two levels, this is usually best
% kept fixed to 1 (determines origin on x_i-scale). The
% first level is NaN because it is determined by the second,
% and the second implies neutrality between outcomes when it
% is centered at 0.
c.mu_0mu = [NaN, 0, 1];
c.mu_0sa = [NaN, 0, 0];

c.logsa_0mu = [NaN,   log(0.1), log(1)];
c.logsa_0sa = [NaN,          0,      0];

% Rhos
% Format: row vector of length n_levels.
% Undefined (therefore NaN) at the first level.
% Fix this to zero to turn off drift.
c.rhomu = [NaN, 0, 0];
c.rhosa = [NaN, 0, 0];

% Kappas
% Format: row vector of length n_levels-1.
% Fixing log(kappa1) to log(1) leads to the original HGF model.
% Higher log(kappas) should be fixed (preferably to log(1)) if the
% observation model does not use mu_i+1 (kappa then determines the
% scaling of x_i+1).
c.logkamu = [log(1), log(1)];
c.logkasa = [     0,      0];

% Omegas
% Format: row vector of length n_levels.
% Undefined (therefore NaN) at the first level.
c.ommu = [NaN,  -3,  -6];
c.omsa = [NaN, 4^2, 4^2];

% Gather prior settings in vectors
c.priormus = [
    c.mu_0mu,...
    c.logsa_0mu,...
    c.rhomu,...
    c.logkamu,...
    c.ommu,...
         ];

c.priorsas = [
    c.mu_0sa,...
    c.logsa_0sa,...
    c.rhosa,...
    c.logkasa,...
    c.omsa,...
         ];

% Check whether we have the right number of priors
expectedLength = 3*c.n_levels+2*(c.n_levels-1)+1;
if length([c.priormus, c.priorsas]) ~= 2*expectedLength;
    error('tapas:hgf:PriorDefNotMatchingLevels', 'Prior definition does not match number of levels.')
end

% Model function handle
c.prc_fun = @tapas_hgf_binary;

% Handle to function that transforms perceptual parameters to their native space
% from the space they are estimated in
c.transp_prc_fun = @tapas_hgf_binary_transp;

return;


function res = GALA_clustering(lJcov,J1, S, distance, A)

    Nl = S.Nl;
    Nd = length(lJcov)/Nl;

    CJcov = GALA_find_localmin(lJcov,Nl,Nd,A,S.threshold);

    for p=1:Nl
        tCJcov=[];
        tCJcov.clvi=CJcov.clvi(p,:);
        tCJcov.maxs=CJcov.maxs{p};
        mxymcor = 0;
        while mxymcor<S.mincorr
            oldsize = length(tCJcov.maxs);
            cursize = length(tCJcov.maxs);
            for i=1:oldsize
                sxycor = corrcoef(J1(tCJcov.clvi{i}+(p-1)*Nd,:)');
                sxycor(sxycor==1)=NaN;
                sxymcor = nanmean(nanmean(sxycor));
                if length(tCJcov.clvi{i})>S.maxsize || sxymcor<S.mincorr
                    cltd = tCJcov.clvi{i};
    %                 ntd = ceil(length(cltd)/20);
                    ntd = 2;
                    Jcovpi = J1(cltd+(p-1)*Nd,:);
                    d = distance(cltd,cltd);
                    Jcd = ones(length(cltd),length(cltd))-corrcoef(Jcovpi');
                    dd = d+S.distratio1*Jcd;
                    Y = squareform(dd);
                    Z = linkage(Y,'complete');
                    CL = cluster(Z,'maxclust',ntd);
                    clm = CL(cltd==tCJcov.maxs(i));
                    tCJcov.clvi{i} = cltd(CL==clm);
                    cld = setdiff(1:max(CL),clm);
                    for j=cld
                        ind = find(CL==j);
                        tCJcov.clvi{cursize+1} = cltd(ind);
                        dd = distance(cltd(ind),cltd(ind));
                        [nu md] = min(sum(dd));
                        tCJcov.maxs(cursize+1) = cltd(ind(md));
                        cursize = cursize+1;
                    end
                end
            end
            i=1;
            while i<=cursize
                if length(tCJcov.clvi{i})<5
                    tCJcov.clvi(i) = [];
                    tCJcov.maxs(i) = [];
                    cursize = length(tCJcov.maxs);
                else
                    i=i+1;
                end
            end
            xymcor=[];
            for i=1:cursize
                xycor = corrcoef(J1(tCJcov.clvi{i}+(p-1)*Nd,:)');
                xycor(xycor==1)=NaN;
                xymcor(i) = nanmean(nanmean(xycor));
            end
            mxymcor = min(xymcor);
        end
        for i=1:max(length(CJcov.maxs{p}),cursize)
            if i<=cursize
                CJcov.clvi{p,i}=tCJcov.clvi{i};
                CJcov.maxs{p}(i)=tCJcov.maxs(i);
            else
                CJcov.clvi{p,i}=[];
                CJcov.maxs{p}(i)=[];
            end
        end
    end

    maxsa = spm_cat(CJcov.maxs);

    ldist = distance(maxsa,maxsa);
    lmaxs = [];
    smaxs = [];
    clind = [];
    for p=1:Nl
        lmaxs = horzcat(lmaxs,CJcov.maxs{p}+Nd*(p-1));
        smaxs(end+1:end+length(CJcov.maxs{p}),:) =...
            horzcat(repmat(p,[length(CJcov.maxs{p}) 1]),CJcov.maxs{p}');
        clind(end+1:end+length(CJcov.maxs{p}),:) =...
            horzcat(repmat(p,[length(CJcov.maxs{p}) 1]),(1:length(CJcov.maxs{p}))');

    end
    lmaxs = lmaxs';

    Jcor = ones(length(lmaxs),length(lmaxs))-corrcoef(J1(lmaxs,:)');
    dd = ldist+S.distratio2*Jcor;

    Y = squareform(dd);
    Z = linkage(Y,S.linkmeth);
    if isfield(S.cluster,'maxclust')
        CL = cluster(Z,'maxclust',S.cluster.maxclust.maxclustsize);
    elseif isfield(S.cluster,'cutoff')
        CL = cluster(Z,'cutoff',S.cluster.cutoff.cutoffthresh,'criterion','distance');
    end

    % remove multiple maxs for one subject in one cluster
    % and merge appropriate basins
    rs=[];
    for cl=1:max(CL)
       list = smaxs(CL==cl,:);
       ind = find(CL==cl);
       lm = lJcov(lmaxs(ind(1)));
       ind_lm = 1;
       for i=2:size(list,1)
           if list(i,1)==list(i-1,1)
               if lJcov(lmaxs(ind(i)))>lm
                   rs = [rs;ind(ind_lm)];
                   CJcov.clvi{clind(ind(i),1),clind(ind(i),2)}=...
                       horzcat(CJcov.clvi{clind(ind(i),1),clind(ind(i),2)},...
                       CJcov.clvi{clind(ind(ind_lm),1),clind(ind(ind_lm),2)});
                   CJcov.clvi{clind(ind(ind_lm),1),clind(ind(ind_lm),2)}=[];
                   lm = lJcov(lmaxs(ind(i)));
                   ind_lm = i;
               else
                   rs = [rs;ind(i)];
                   CJcov.clvi{clind(ind(ind_lm),1),clind(ind(ind_lm),2)}=...
                       horzcat(CJcov.clvi{clind(ind(i),1),clind(ind(i),2)},...
                       CJcov.clvi{clind(ind(ind_lm),1),clind(ind(ind_lm),2)});
                   CJcov.clvi{clind(ind(i),1),clind(ind(i),2)}=[];
               end
           else
               lm = lJcov(lmaxs(ind(i)));
               ind_lm = i;
           end
       end
    end

    CL(rs)=[];
    lmaxs(rs)=[];
    smaxs(rs,:)=[];
    clind(rs,:)=[];
    ldist(rs,:) = [];
    ldist(:,rs) = [];

    CLi = unique(CL);

thr = S.Nl-S.similarity;

dd=[];list=[];ncl=0;pclvi=[];pmaxs=[];tc=0;
for cl=1:length(CLi)
    if length(lmaxs(CL==CLi(cl)))>=thr
        ncl=ncl+1;
        ind = find(CL==CLi(cl));
        dd = ldist(ind,ind);
        [nu, md] = min(sum(dd));
        list{CLi(cl)} = smaxs(ind,:);
        mvd = list{CLi(cl)}(md,2);
        no = find(~ismember(1:Nl,list{CLi(cl)}(:,1)));
        iclvi = CJcov.clvi{clind(ind(1),1),clind(ind(1),2)};
        uclvi = CJcov.clvi{clind(ind(1),1),clind(ind(1),2)};
        wi = 1;
        while isempty(iclvi)
            wi=wi+1;
            iclvi = CJcov.clvi{clind(ind(wi),1),clind(ind(wi),2)};
            no = sort([no clind(ind(wi-1))]);
            ind(wi-1)=[];
        end
        pclvi{clind(ind(1),1),ncl} = iclvi;
        pmaxs{clind(ind(1),1)}(ncl) = smaxs(ind(1),2);
        for i=2:length(ind)
            pclvi{clind(ind(i),1),ncl} = CJcov.clvi{clind(ind(i),1),clind(ind(i),2)};
            pmaxs{clind(ind(i),1)}(ncl) = smaxs(ind(i),2);
            if isempty(pclvi{clind(ind(i),1),ncl})
                pclvi{clind(ind(i),1),ncl} = iclvi;
                pmaxs{clind(ind(i),1)}(ncl) = smaxs(ind(1),2);
            end
            iclvin = intersect(iclvi,pclvi{clind(ind(i),1),ncl});
            uclvin = union(uclvi,pclvi{clind(ind(i),1),ncl});
        end
        oth = setdiff(1:Nl,list{CLi(cl)}(:,1));
        for i=1:length(oth)
            if length(iclvi)>15
                pclvi{oth(i),ncl} = iclvi;
                pmaxs{oth(i)}(ncl) = smaxs(ind(1),2);
            else
                dd = distance(uclvin,uclvin);
                [nu, md] = min(sum(dd));
                pmaxs{oth(i)}(ncl) = uclvin(md);
                pclvi{oth(i),ncl} = find(distance(uclvin(md),:)<=2);
            end
        end

    end

end

res.pclvi = pclvi;
res.pmaxs = pmaxs;

%     figure;
%     ahp = [];
%     for p=1:Nl
%
%         srcs_disp1 = zeros(Nd,1);
%         for cl=1:size(pclvi,2)
%             srcs_disp1(pclvi{p,cl})=1;
%         end
%
%         ahp(p)=subplot(1,2,p);
%
%         cla; axis off
%
%         fig1 = patch('vertices',vert,'faces',face,'FaceVertexCData',srcs_disp1);
%
%         set(fig1,'FaceColor',[.5 .5 .5],'EdgeColor','none');
%         shading interp
%         lighting gouraud
%         %camlight
%         zoom off
%         lightangle(0,270);lightangle(270,0),lightangle(90,0),lightangle(0,45),lightangle(0,135);
%         material([.1 .1 .4 .5 .4]);
%         %view(140,15);
%         caxis([0 1])
%         colormap(jet);
%         hold on;
%         scatter3(vert(pmaxs{p},1),vert(pmaxs{p},2),vert(pmaxs{p},3),15,'r','fill');hold on;
%
%     end
%     hlink = linkprop(ahp, {'CameraPosition','CameraUpVector'});
%     key = 'graphics_linkprop';
%     setappdata(ahp(1),key,hlink);

end


function [m,v] = spm_csd_chf(P,M,U)
% Characteristic (expected) frequency of a NMM
% FORMAT [G,w] = spm_csd_chf(P,M,U)
%
% P - parameters
% M - neural mass model structure
% U - trial-specific effects
%
% m - expected frequency
% v - dispersion
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_csd_chf.m 4718 2012-04-19 15:34:45Z karl $

% compute log-spectral density (without noise)
%==========================================================================
P.a(1) = -0;
P.a(2) = -32;
P.b    = P.b - 32;
P.c    = P.c - 32;

[G,w]  = spm_csd_mtf(P,M,U);

% compute moments (treating abs(G{i}) as a density)
%--------------------------------------------------------------------------
for i = 1:length(G)
    p     = abs(G{i});
    p     = p/sum(p);
    m(i)  = w'*p;
    v(i)  = ((w - m(i)).^2)'*p;
end

% average over trials
%--------------------------------------------------------------------------
m    = mean(m);
v    = mean(v);