function [ newPositions, zerosInARow ] = CalcSimpleOpticalFlowHists( centroids, img1, train, neighborSize, windowSize, w, thresh, zerosInARow)
%  calcSimpleOpticalFlowHists - Used to track object of interest
%--------------------------------------------------------------------------
%   Params: centroids: n x 3 matrix where n is the number of centroids showing
%           img1: image to be looked at for new centroid position
%           train: training histograms
%           neighborSize: size of neighborhood to look at.  Should be odd
%           windowSize: size of windows in centroid neighborhood
%           w - the width of the bins for the RGB color
%               histograms
%           thresh: distance threshold
%           zerosInARow: zeros in a row
%
%   Returns: newPositions - new positions of centroid.  0 for x and y of
%               centroid if its out of view bounds or doesn't
%               have a good enough match in the view
%            zerosInARow - number of frames straight where zeros
%               detected
%
%   Assumes: brightness constant, small motion changes betw frames
%--------------------------------------------------------------------------

newPositions = zeros(size(centroids,1), size(centroids,2));
imgWidth = size(img1,2);
imgHeight = size(img1,1);
for i = 1:size(centroids,1)
    currCentr = centroids(i,:);
    row = currCentr(1);
    col = currCentr(2);
%     if useOrigColor == 1
%         pixRef = [currCentr(4) currCentr(5) currCentr(6)]';
%     else
%         pixRef = double(refImg(row,col,:));
%         pixRef = pixRef(:);
%     end
    indent = floor(neighborSize / 2);
    bestDist = 0;
    for kRow = -indent:indent
        for kCol = -indent:indent
            testRow = max(1, row + kRow);
            testRow = min(imgHeight, testRow);
            testCol = max(1, col + kCol);
            testCol = min(imgWidth, testCol);
            hist = SimpleHist1D(img1(max(1,testRow - windowSize):min(imgHeight, testRow + windowSize),...
                max(1,testCol- windowSize):min(imgWidth, testCol + windowSize)...
                ,:), w);
            dist = Score1D(hist, train);
            %prefer points closer to old centroid so put penalty
            manhDist2center = (abs(testRow - centroids(i,1)) + ...
              abs(testCol - centroids(i,2))) / 2;
            %good vals is - 15, - 20,
            if (dist > exp(thresh - 25 + manhDist2center))
                if (dist > bestDist)
                    newPositions(i,1) = testRow;
                    newPositions(i,2) = testCol;
                    bestDist = dist;
                end
            end
        end
    end
    if (newPositions(i,1) == 0)
        zerosInARow = zerosInARow + 1;
        if (zerosInARow <= 15)
            newPositions(i,1) = centroids(i,1);
            newPositions(i,2) = centroids(i,2);
        end
    else
        zerosInARow = 0;
    end
    %newPositions
end

end


function desired_velocity = variable_v(position,velocity)
%{
This function  receives the following inputs:
    1. Position of the aircraft- [x, y, z]
    2. Velocity of the aircraft - [x,y,z]
Using the inputs, the function returns the value of the desired velocity,
cartasian coordinates.
Created by Roni Peer, 11.7.2010
%}
%#eml
height = position(3);                                           % Get the Height.
if height > 500                                                         % Maintain velocity.
    desired_descent_rate = velocity(3);
elseif height > 200                                                % Slow down.
    desired_descent_rate = -10;
elseif height > 100
    desired_descent_rate = -2;
elseif height > 10
    desired_descent_rate = -1;
else
    desired_descent_rate = -0.5;                        % Break.
end
desired_velocity = [0; 0; desired_descent_rate];


function res = hlp_aggregatestructs(structs,defaultop,varargin)
% Aggregate structs (recursively), using the given combiner operations.
% Result = hlp_aggregatestructs(Structs,Default-Op,Field-Ops...)
%
% This results in a single 1x1 struct which has aggregated values in its fields (e.g., arrays,
% averages, etc.). For a different use case, see hlp_superimposedata.
%
% In:
%   Structs    : cell array of structs to be aggregated (recursively) into a single struct
%
%   Default-Op : optional default combiner operation to execute for every field that is not itself a
%                struct; see notes for the format.
%
%   Field-Ops  : name-value pairs of field-specific ops; names can have dots to denote operations
%                that apply to subfields. field-specific ops that apply to fields that are
%                themselves structures become the default op for that sub-structure
%
% Out:
%   recursively merged structure.
%
% Notes:
%   If an operation cannot be applied, a sequence of fall-backs is silently applied. First,
%   concatenation is tried, then, replacement is tried (which never fails). Therefore,
%   function_handles are being concatenated up to 2008a, and replaced starting with 2008b.
%   Operations are specified in one of the following formats:
%   * 'cat': concatenate values horizontally using []
%   * 'replace': replace values by those of later structs (noncommutative)
%   * 'sum': sum up values
%   * 'mean': compute the mean value
%   * 'std': compute the standard deviation
%   * 'median': compute the median value
%   * 'random': pick a random value
%   * 'fillblanks': replace [] by values of later structs
%   * binary function: apply the function to aggregate pairs of values; applied in this order
%     f(f(f(first,second),third),fourth)...
%   * cell array of binary and unary function: apply the binary function to aggregate pairs of
%     values, then apply the unary function to finalize the result: functions {b,u} are applied in
%     the following order: u(b(b(b(first,second),third),fourth))
%
% Examples:
%   % calc the average of the respective field values, across structs
%   hlp_aggregatestructs({result1,result2,result3},'mean')
%
%   % calc the std deviation of the respective field values, across structs
%   hlp_aggregatestructs({result1,result2,result3},'std')
%
%   % concatenate the field values across structs
%   hlp_aggregatestructs({result1,result2,result3},'cat')
%
%   % as before, but use different operations for a few fields
%   hlp_aggregatestructs({result1,result2,result3},'cat','myfield1','mean','myfield2.subfield','median')
%
%   % use a custom combiner operation (here: product)
%   hlp_aggregatestructs({result1,result2,result3},@times)
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2010-05-04

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

warning off MATLAB:warn_r14_function_handle_transition

if nargin < 2
    defaultop = 'cat'; end
if ~iscell(structs)
    structs = {structs}; end
fieldops = hlp_varargin2struct(varargin);

% translate all ops (if they are specified as strings)
defaultop = translateop(defaultop);
fieldops = translateop(fieldops);

% aggregate, then finalize
res = finalize(aggregate(structs,defaultop,fieldops),defaultop,fieldops);

function res = aggregate(structs,defaultop,fieldops)
% we skip empty records
structs = structs(~cellfun('isempty',structs));

% for any struct array in the input, we first merge it recursively as if it were a cell array
for k=find(cellfun('length',structs)>1)
    structs{k} = hlp_aggregatestructs(structarray2cellarray(structs{k}),defaultop,fieldops); end

% at this point, we should have a cell array of structs
if ~isempty(structs)
    % we begin with the first struct
    res = structs{1};
    % and aggregate the remaining ones onto it
    for i=2:length(structs)
        si = structs{i};
        % proceeding field by field...
        for fn=fieldnames(si)'
            f = fn{1};
            % figure out which operation applies
            if isfield(fieldops,f)
                % a field-specific op applies
                if isstruct(fieldops.(f))
                    % ... which is itself a struct
                    fop = fieldops.(f);
                else
                    op = fieldops.(f);
                end
            else
                % the default op applies
                op = defaultop;
                fop = fieldops;
            end

            % now process the field
            if ~isfield(res,f)
                % field is not yet in the aggregate: just assign
                res.(f) = si.(f);
            else
                % need to aggregate it
                if isstruct(res.(f)) && isstruct(si.(f))
                    % both are a struct: recursively aggregate
                    res.(f) = aggregate({res.(f),si.(f)},op,fop);
                else
                    % they are not both structus
                    try
                        % try to apply the combiner op
                        res.(f) = op{1}(res.(f),si.(f));
                    catch
                        % didn't work: try to concatenate as fallback
                        try
                            res.(f) = [res.(f),si.(f)];
                        catch
                            % didn't work: try to assign as fallback (dropping previous field)
                            res.(f) = si.(f);
                        end
                    end
                end
            end
        end
    end
else
    % nothing to aggregate
    res = [];
end

function x = finalize(x,defaultop,fieldops)
% proceed field by field...
for fn=fieldnames(x)'
    f = fn{1};
    % figure out which operation applies
    if ~isempty(fieldops) && isfield(fieldops,f)
        % a field-specific op applies
        if isstruct(fieldops.(f))
            % ... which is itself a struct
            fop = fieldops.(f);
        else
            op = fieldops.(f);
        end
    else
        % the default op applies
        op = defaultop;
        fop = fieldops;
    end
    try
        % now apply the finalizer
        if isstruct(x.(f))
            % we have a sub-struct: recurse
            x.(f) = finalize(x.(f),op,fop);
        else
            % we have a regular element: apply finalizer
            x.(f) = op{2}(x.(f));
        end
    catch
        % for empty structs, x.(f) produces no output
    end
end

% translate string ops into actual ops, add the default finalizer if missing
function op = translateop(op)
if isstruct(op)
    % recurse
    op = structfun(@translateop,op,'UniformOutput',false);
else
    % remap strings
    if ischar(op)
        switch op
            case 'cat'
                op = @(a,b)[a b];
            case 'replace'
                op = @(a,b)b;
            case 'sum'
                op = @(a,b)a+b;
            case 'mean'
                op = {@(a,b)[a b], @(x)mean(x)};
            case 'median'
                op = {@(a,b)[a b], @(x)median(x)};
            case 'std'
                op = {@(a,b)[a b], @(x)std(x)};
            case 'random'
                op = {@(a,b)[a b], @(x) x(min(length(x),ceil(eps+rand(1)*length(x))))};
            case 'fillblanks'
                op = @(a,b)quickif(isempty(a),b,a);
            otherwise
                error('Unsupported combiner operation specified: %s',op);
        end
    elseif ~isa(op,'function_handle')
        error('The given combiner operation must be either a string or a function handle, but was: %s',hlp_tostring(op,1000));
    end
    % add finalizer if missing
    if ~iscell(op)
        op = {op,@(x)x}; end
end

% inefficiently turn a struct array into a cell array of structs
function res = structarray2cellarray(arg)
res = {};
for k=1:numel(arg)
    res = [res {arg(k)}]; end

% for the 'fillblanks' translate op
function val = quickif(cond,trueval,falseval)
if cond
    val = trueval;
else
    val = falseval;
end


function handles = plotData3D(hObject, handles)

plotDimensions = get(handles.lstPlotDimensions, 'Value');

FigureTitle = 'Data';
[handles, handles.figData] = openPlotFigure(hObject, handles, ...
    'Data Plot (3D)', FigureTitle);

view(3);

scatter3(handles.Data(plotDimensions(1), :), ...
         handles.Data(plotDimensions(2), :), ...
         handles.Data(plotDimensions(3), :), ...
         getPlotMarkerSize(), ...
         ['k' getPlotMarkerStyle()]);

hold off;

guidata(hObject, handles);


function [] = plotHammDist( jobIDs, taskIDs, jobNames, objIDs, doHourly )
% View trace plots of hamming distance for sampler state at each
%    recorded iteration of the sampler chain.  Useful for diagnosing
%    convergence and mixing rates.
% ________________________________________________________________________

if ~exist( 'objIDs','var')
    objIDs = 1:6;
end

figure;
set( gcf, 'Units', 'normalized', 'Position', [0.5 0.5 0.5 0.5] );
if exist( 'jobNames', 'var' ) && ~isempty( jobNames )
    plotColors  = get(0,'defaultAxesColorOrder');
    hold on;
else
    plotColors = get(0,'defaultAxesColorOrder');
    hold all;
end

for jobID = jobIDs
    taskNames = {};

    doFirstTask = 1;
    for taskID = taskIDs
        DATA = loadSamplerOutput( jobID, taskID , {'times', 'A'} );
        if isnumeric(DATA) && DATA == -1
            continue;
        end

        times = DATA.times.Psi;

        Ts = DATA.A(end).HDist.Ts( objIDs );
        Hdist = zeros( 1, length(DATA.A ) );
        for ss = 1:length( DATA.A )
            objDists = DATA.A(ss).HDist.obj( objIDs );
            Hdist(ss) = sum( objDists .* Ts )/sum(Ts);
        end

        if exist( 'jobNames', 'var' )  && ~isempty( jobNames )
            jj = 1 + mod( find( jobID == jobIDs )-1, size(plotColors,1) );
            curColor = plotColors(jj,:);
            if doFirstTask;
                taskVis = 'on';
                doFirstTask = 0;
            else
                taskVis = 'off';
            end
        else
            taskNames{end+1} = num2str( taskID );
            jj = 1 + mod( find( taskID == taskIDs )-1, size(plotColors,1) );
            curColor = plotColors(jj,:);
            taskVis = 'on';
        end

        styleStr = '.-';

        while length( times ) > 200
           times = times(1:2:end);
           Hdist = Hdist(1:2:end);
        end

        if doHourly
            times = times/3600;
        end

        plot( times, Hdist, styleStr, 'MarkerSize', 15, 'LineWidth', 2, 'HandleVisibility', taskVis, 'Color', curColor );

    end
end

if exist( 'jobNames', 'var' ) && ~isempty( jobNames )
    legend( jobNames , 'Location', 'SouthEast' );
else
    legend( taskNames, 'Location', 'SouthEast' );
end

ylabel( 'Hamming Dist', 'FontSize', 18 );

if doHourly
xlabel ('CPU time (hours)', 'FontSize', 18);
else
xlabel ('CPU time (sec)', 'FontSize', 18);
end
grid on;
set( gca, 'FontSize', 16 );
end % main function


function value = halton_base_check ( dim_num, base )

%*****************************************************************************80
%
%% HALTON_BASE_CHECK is TRUE if BASE is legal.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 July 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer BASE(1:DIM_NUM), the Halton bases.
%    Each base should be greater than 1.  Only the integer
%    part of a base is used.
%
%    Output, logical VALUE.
%
  if ( any ( base(1:dim_num) <= 1 ) )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'HALTON_BASE_CHECK - Fatal error!\n' );
    fprintf ( 1, '  At least one of the input bases is <= 1!\n' );
    value = 0;
  else
    value = 1;
  end

  return
end


classdef AGEMOEA < ALGORITHM
% <multi/many> <real/integer/label/binary/permutation> <constrained/none>
% Adaptive geometry estimation-based many-objective evolutionary algorithm

%------------------------------- Reference --------------------------------
% A. Panichella, An adaptive evolutionary algorithm based on non-euclidean
% geometry for many-objective optimization, Proceedings of the Genetic and
% Evolutionary Computation Conference, 2019, 595-603.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

% This function is written by Annibale Panichella

    methods
        function main(Algorithm,Problem)
            %% Generate random population
            Population = Problem.Initialization();
            [~,FrontNo,CrowdDis] = EnvironmentalSelection(Population,Problem.N);

            %% Optimization
            while Algorithm.NotTerminated(Population)
              MatingPool = TournamentSelection(2,Problem.N,FrontNo,-CrowdDis);
              Offspring  = OperatorGA(Problem,Population(MatingPool));
              [Population,FrontNo,CrowdDis] = EnvironmentalSelection([Population,Offspring],Problem.N);
            end
        end
    end
end


function s=v_lpcconv(from,to,x,y,np)
%V_LPCCONV(from,to,x,y)->s convert between LPC parameter sets
%
% The output is a string that may be passed to eval(s)
% x and y are optionally the input and output matrices
% and np the new value of the order p.
% with one frame stored per row. from and to are taken
% from the following list which also gives the column dimension:
%
%  1 ar p+1  Autoregressive coevfficients: ar(1)=1 always.
%  2 cc  p   Complex cepstral coefficients
%  3 ls  p   Line spectrum pair frequencies (normalized Hz)
%  4 zz  p   Z-plane roots
%  5 ss  p   S-plane roots (normalized Hz)
%  6 rf  p   Reflection coefficients (= -PARCOR coefs)
%  7 ao  p   Area ratios
%  8 aa p+2  Vocal tract areas: aa(p+2)=1 always
%  9 rr p+1  Autocorrelation coefficients
% 10 dl  p   DCT of log area function
% 11 lo  p   Log area ratios
% 12 la p+1  Log areas: la(1)=0 always
% 13 ra p+1  Autocorrelation coefs of inverse filter
% 14 ff p+2  Fourier transform of forward filter (all-pole)
% 15 pf p+2  Power spectrum of forward filter (all-pole)
% 16 gc  p   Gain and cos(w) of each formant
% 17 im p+1  Impulse response of forward filter

%	   Copyright (C) Mike Brookes 1998
%      Version: $Id: v_lpcconv.m 10865 2018-09-21 17:22:45Z dmb $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

nm=['aa';'am';'ao';'ar';'cc';'db';'dl';'ff';'fq';'im';'is';'la';'lo';'ls';'pf';'ra';'rf';'rr';'ss';'zz';];
nx=[...
      0 17  3 17 17 17  7 17  0 17 17 17 17 17 17 17 17 17 17 17;...
      0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0;...
     17 17  0 17 17 17 17 17  0 17 17 17 17 17 17 17 17 17 17 17;...
     17 18 17  0  5  6 17  8  0 10 17 17 17 14 15 16 17 18 20 20;...
      4  4  4  4  5  6  4  4  0  4  4  4  4  4 15  4  4  4  4  4;...
     15 15 15 15 15  0 15 15  0 15 15 15 15 15 15 15 15 15 15 15;...
      1  1  1  1  1  1  0  1  0  1  1  1  1  1  1  1  1  1  1  1;...
     15 15 15 15 15 15 15  0  0 15 15 15 15 15 15 15 15 15 15 15;...
     20 20 20 20 20 20 20 20  0 20 20 20 20 20 20 20 20 20 20 20;...
      4  4  4  4  4  4  4  4  0  0  4  4  4  4  4  4  4  4  4  4;...
     17 17 17 17 17 17 17 17  0 17  0 17 17 17 17 17 17 17 17 17;...
     17 17 17 17 17 17 17 17  0 17 17  0 17 17 17 17 17 17 17 17;...
     17 17 17 17 17 17 17 17  0 17 17 17  0 17 17 17 17 17 17 17;...
      4  4  4  4  4  4  4  4  0  4  4  4  4  0  4  4  4  4  4  4;...
      5 18  5  5  5  5  5  5  0  5  5  5  5  5  0  5  5 18  5  5;...
     15 15 15 15 15 15 15 15  0 15 15 15 15 15 15  0 15 15 15 15;...
      1 18  3  4  4  4  1  4  0  4 11 12 13  4  4  4  0 18  4  4;...
      4  2  4  4  4  4  4  4  0  4  4  4  4  4  4  4  4  0  4  4;...
     20 20 20 20 20 20 20 20  0 20 20 20 20 20 20 20 20 20  0 20;...
      4  4  4  4  5  4  4  4  0  4  4  4  4  4  4  4  4  4 19  0;...
];
na=size(nm,1);
b=256*nm(:,1)+nm(:,2);
jf=find(b==256*from(1)+from(2));
jt=find(b==256*to(1)+to(2));
if length([jf jt])~=2
   [x,idx]=sort(b);
  error(sprintf('lpcxx2yy types are: %s',[nm(idx,:)';' '*ones(1,na)]));
end
if nargin<3 s=nm(jf,:); else s=x; end
while jf ~= jt
  jn=nx(jf,jt);
  if jn==0
     error(sprintf('cannot convert between %s and %s',nm(jf,:),nm(jt,:)));
 end
  s=sprintf('lpc%s2%s(%s)',nm(jf,:),nm(jn,:),s);
  jf=jn;
  end
if nargin<4 sn=nm(jt,:); else sn=y; end
s=sprintf('%s=%s;',sn,s);


function net = make_net(opts)
% MAKE_NET constructs the network up to the output.
% Loss functions are not added.
%
% Options include:
% Architecture to use for initial branches of network.
% Whether to use scores or bounding box regression.
% Whether to use xcorr or concat layer to join.
% Architecture to put after concat (1x1 convs).

switch opts.branch.type
    case 'alexnet'
        [branch1, branch2] = make_branches_alexnet(opts);
    otherwise
        error('Unknown branch type')
end
[repr_sz, repr_stride] = output_size(branch1, [opts.exemplarSize*[1 1], 3, 1]);
switch opts.join.method
    case 'xcorr'
        [join, final] = make_join_xcorr(opts);
    case 'corrfilt'
        [join, final] = make_join_corr_filt(opts, repr_sz, repr_stride);
    otherwise
        error('Unknown join method')
end

net = make_siamese(branch1, branch2, join, final, ...
                   {'exemplar', 'instance'}, 'score', ...
                   'share_all', opts.share_params);

end

function [branch1, branch2] = make_branches_alexnet(opts)
    branch_opts.last_layer = 'conv5';
    branch_opts.num_out     = [96, 256, 384, 384, 256];
    branch_opts.num_in      = [ 3,  48, 256, 192, 192];
    branch_opts.conv_stride = [ 2,   1,   1,   1,   1];
    branch_opts.pool_stride = [ 2,   2];
    branch_opts.batchNormalization = true;
    branch_opts = vl_argparse(branch_opts, {opts.branch.conf});

    branch_opts.exemplarSize = opts.exemplarSize * [1 1];
    branch_opts.instanceSize = opts.instanceSize * [1 1];
    branch_opts.weightInitMethod = opts.init.weightInitMethod;
    branch_opts.scale            = opts.init.scale;
    branch_opts.initBias         = opts.init.initBias;

    f = @() make_branch_alexnet(branch_opts);
    branch1 = f();
    branch2 = f();
end

function [join, final] = make_join_xcorr(opts)
    join_opts.finalBatchNorm = true;
    join_opts.adjustGainInit = 1;
    join_opts.adjustBiasInit = 0;
    % Learning rates ignored if batch-norm is enabled.
    join_opts.adjustGainLR = 0;
    join_opts.adjustBiasLR = 1;
    join_opts = vl_argparse(join_opts, {opts.join.conf});

    join = dagnn.DagNN();
    join.addLayer('xcorr', XCorr(), {'in1', 'in2'}, {'out'});

    % Create adjust layer.
    final.layers = {};
    convOpts = {'CudnnWorkspaceLimit', 1024*1024*1024};
    if join_opts.finalBatchNorm
        % Batch-norm layer only.
        final.layers{end+1} = struct(...
            'type', 'bnorm', 'name', 'adjust_bn', ...
            'weights', {{single(join_opts.adjustGainInit), ...
                         single(join_opts.adjustBiasInit), ...
                         zeros(1, 2, 'single')}}, ...
            'learningRate', [2 1 0.3], ...
            'weightDecay', [0 0]);
    else
        % Linear layer only.
        final.layers{end+1} = struct(...
            'type', 'conv', 'name', 'adjust', ...
            'weights', {{single(join_opts.adjustGainInit), ...
                         single(join_opts.adjustBiasInit)}}, ...
            'learningRate', [join_opts.adjustGainLR, join_opts.adjustBiasLR], ...
            'weightDecay', [1 0], ...
            'opts', {convOpts});
    end
end

function [join, final] = make_join_corr_filt(opts, in_sz, in_stride)
    join_opts.finalBatchNorm = false;
    join_opts.const_cf = false;
    join_opts.lambda = nan;
    join_opts.window = 'not-set';
    join_opts.window_lr = 0;
    join_opts.bias = false;
    join_opts.adjust = true;
    join_opts.sigma = 0;
    join_opts.target_lr = 0;

    join_opts.adjustGainInit = 1;
    join_opts.adjustBiasInit = 0;
    % Learning rates ignored if batch-norm is enabled.
    join_opts.adjustGainLR = 0;
    join_opts.adjustBiasLR = 1;

    join_opts = vl_argparse(join_opts, {opts.join.conf});
    convOpts = {'CudnnWorkspaceLimit', 1024*1024*1024};

    join = dagnn.DagNN();
    % Apply window before correlation filter.
    join.addLayer('cf_window', MulConst(), ...
                  {'in1'}, {'cf_example'}, {'window'});
    p = join.getParamIndex('window');
    join.params(p).value = single(make_window(in_sz, join_opts.window));
    join.params(p).learningRate = join_opts.window_lr;

    % Establish whether there is a bias parameter to the XCorr.
    cf_outputs = {'tmpl'};
    xcorr_inputs = {'tmpl_cropped', 'in2'};

    % learnt alphas instead of CF for Adaptation Experiment
    if join_opts.const_cf
        join.addLayer('circ', ConvCircScalar(), ...
                      {'cf_example'}, cf_outputs, {'circf'});
        p = join.getParamIndex('circf');
        join.params(p).value = init_weight(opts.init, in_sz(1), in_sz(2), 1, 1, 'single');
    else
    % Add a correlation filter before the XCorr in branch 1.
        if join_opts.bias
            % Connect correlation filter bias to xcorr bias.
            cf_outputs = [cf_outputs, {'bias'}];
            xcorr_inputs = [xcorr_inputs, {'bias'}];
        end
        join.addLayer('cf', ...
                      CorrFilter('lambda', join_opts.lambda, ...
                                 'bias', join_opts.bias), ...
                      {'cf_example'}, cf_outputs, {'cf_target'});
        % Set correlation filter target.
        p = join.getParamIndex('cf_target');
    end

    join.addLayer('crop_z', ...
                    CropMargin('margin', 16), ...
                    cf_outputs, xcorr_inputs{1});

    % Cross-correlate template with features of other image.
    join.addLayer('xcorr', XCorr('bias', join_opts.bias), ...
                  xcorr_inputs, {'out'});

    assert(join_opts.sigma > 0);
    join.params(p).value = single(gaussian_response(in_sz, join_opts.sigma/in_stride));
    join.params(p).learningRate = join_opts.target_lr;

    % Add scalar layer to calibrate corr-filt scores for loss function.
    final.layers = {};
    if join_opts.adjust
        if  join_opts.finalBatchNorm
            % Batch-norm layer only.
            final.layers{end+1} = struct(...
                'type', 'bnorm', 'name', 'adjust_bn', ...
                'weights', {{single(join_opts.adjustGainInit), ...
                             single(join_opts.adjustBiasInit), ...
                             zeros(1, 2, 'single')}}, ...
                'learningRate', [2 1 0.3], ...
                'weightDecay', [0 0]);
        else
            final.layers{end+1} = struct(...
                'type', 'conv', 'name', 'adjust', ...
                'weights', {{single(1), single(-0.5)}}, ...
                'learningRate', [1, 2], ...
                'weightDecay', [0 0], ...
                'opts', {convOpts});
        end
    end
end

function num_out = output_dim(opts)
    % TODO: Restructure options so that this code does not need to know about
    % different types of loss function?
    switch opts.loss.type
        case {'simple', 'structured'}
            num_out = 1;
        case 'regression'
            assert(opts.instanceSize==opts.exemplarSize, 'Exemplar and Instance should have the same size.');
            assert(opts.negatives==0 && opts.hardNegatives==0, 'No negative pairs for the moment.');
            num_out = 4;
        otherwise
            error('unknown loss');
    end
end

function [out_sz, out_stride] = output_size(net, in_sz)
    % Assume that net has 1 input and 1 output.
    if isa(net, 'dagnn.DagNN')
        input = only(net.getInputs());
        output = only(net.getOutputs());
        sizes = net.getVarSizes({input, in_sz});
        out_sz = sizes{net.getVarIndex(output)}(1:3);
        rfs = net.getVarReceptiveFields(input);
        out_stride = rfs(net.getVarIndex(output)).stride;
    else
        info = vl_simplenn_display(net, 'inputSize', in_sz);
        out_sz = info.dataSize(1:3, end);
        out_stride = info.receptiveFieldStride(:, end);
    end
    out_sz = reshape(out_sz, 1, []);
    assert(all(out_stride == out_stride(1)));
    out_stride = out_stride(1);
end


function varargout = efficency(X,P)
% function [con_eff,hrf_eff,X,hrfX,P] = efficency(X,PARAMS)
% a useful summary function for a design, incorporating tests of contrasts and of HRF shape estimation
%
% X
%   either a design vector (condition function) with integers indicating onsets of conditions
%   or an already-constructed design matrix
%
% PARAMS structure contains inputs
% Optional fields:
%   contrasts   required for testing contrast efficiency; see calcEfficiency.m
%   Vi          intrinsic autocorrelation matrix; empty assumes identity matrix (independence)
%   S           smoothing matrix; empty for no smoothing
%   HRF         canonical hemodynamic response function; empty assumes SPM's canonical HRF
%               should be in resolution of .1 s per element
%   nonlint     saturation threshold (ceiling) for predictors; simple nonlinearity model
%   HRFtime     number of s to estimate HRF shape for, in FIR model.
%   delta       You must enter this if you want HRF shape estimate eff and you enter a model matrix X
%               Delta is n x m, with columns for conditions, made of ones and zeros, in TR-length time bins
%
% Required fields for condition function (vector) input:
%   ISI         sampling resolution of design vector, as time between elements in s
%   TR          sampling resolution of final design matrix (volumes acquired), in s
%
% Functions Called: (from OptimizeDesign GA toolbox)
% designvector2model.m
% tor_make_deconv_mtx2.m
% calcEfficiency.m

if ~isfield(P,'contrasts'), P.contrasts = eye(size(X,2));, end
if ~isfield(P,'HRFtime'), P.HRFtime = 30;, end
if isfield(P,'delta'), delta = P.delta;, end
if isfield(P,'TR'), TR = P.TR;, end
if isfield(P,'ISI'), ISI = P.ISI;, end

% -------------------------------------------------------------------------------------------------
% * Set up design matrix
% -------------------------------------------------------------------------------------------------

% For condition function
if any(size(X) == 1)

    if ~isfield(P,'ISI'), error('ISI is required field in PARAMS input'), end
    if ~isfield(P,'TR'), error('TR is required field in PARAMS input'), end
    if ~isfield(P,'S'), P.S = [];, end
    if ~isfield(P,'HRF'), P.HRF = spm_hrf(.1);, HRF = HRF ./ max(HRF);, end
    if ~isfield(P,'nonlint'), P.nonlint = [];, end

    numsamps = ceil(length(X)*P.ISI/P.TR);

    if nargout > 1
        delta = [];
        for i = 1:max(double(X))
            delta(:,i) = (X == i);
        end
    end

    X = designvector2model(X,P.ISI,P.HRF,P.TR,numsamps,P.nonlint,P.S);

    if ~isfield(P,'Vi'), P.Vi = eye(size(X,1));, end

% For a design matrix
else
    if ~isfield(P,'S'), P.S = [];, end
    if ~isfield(P,'Vi'), P.Vi = eye(size(X,1));, end

end

if ~isempty(P.S), svi = P.S * P.Vi;, else, svi = P.Vi;, end

if ~isempty(P.contrasts)
        % -------------------------------------------------------------------------------------------------
		% * efficiency
		% -------------------------------------------------------------------------------------------------

        	xtxitx = pinv(X);                                       		% inv(X'S'SX)*(SX)'; pseudoinv of (S*X)
            contrastweights = ones(1,size(P.contrasts,1));
			[dummy,varargout{1}] = calcEfficiency(contrastweights,P.contrasts,xtxitx,svi);

else
        varargout{1} = [];
end

if isfield(P,'ISI') & isfield(P,'TR') & nargout > 1 & exist('delta') == 1

        % -------------------------------------------------------------------------------------------------
		% * HRF shape estimation efficiency
		% -------------------------------------------------------------------------------------------------

			[X2] = tor_make_deconv_mtx3(delta,round(P.HRFtime / P.TR),P.TR / P.ISI);
            if ~isempty(P.S), X2 = P.S * X2;,end

        	xtxitx = pinv(X2);                                       		% inv(X'S'SX)*(SX)'; pseudoinv of (S*X)
			[dummy,varargout{2}] = calcEfficiency([],[],xtxitx,svi);

elseif nargout > 1
            disp(['Missing ISI or TR field, or already-constructed model entered: HRF efficiency not calculated.'])
            varargout{2} = [];
end

if nargout > 2
    varargout{3} = X; varargout{4} = X2;
    P.hrfsamples = round(P.HRFtime / P.TR);
    P.hrftimeres = P.TR / P.ISI;
    varargout{5} = P;
end

return


function [s, cfg] = ft_statfun_roc(cfg, dat, design)

% FT_STATFUN_ROC computes the area under the curve (AUC) of the Receiver Operator
% Characteristic (ROC). This is a measure of the separability of the data observed in
% two conditions. The AUC can be used for statistical testing whether the two
% conditions can be distinguished on the basis of the data.
%
% Use this function by calling one of the high-level statistics functions as
%   [stat] = ft_timelockstatistics(cfg, timelock1, timelock2, ...)
%   [stat] = ft_freqstatistics(cfg, freq1, freq2, ...)
%   [stat] = ft_sourcestatistics(cfg, source1, source2, ...)
% with the following configuration option
%   cfg.statistic = 'ft_statfun_roc'
%
% The experimental design is specified as:
%   cfg.ivar  = independent variable, row number of the design that contains the labels of the conditions to be compared (default=1)
%
% The labels for the independent variable should be specified as the number 1 and 2.
%
% Note that this statfun performs a one sided test in which condition "1" is assumed
% to be larger than condition "2". This function does not compute an analytic
% probability of condition "1" being larger than condition "2", but can be used in a
% randomization test, including clustering.
%
% A low-level example with 10 channel-time-frequency points and 1000 observations per
% condition goes like this:
%   dat1 = randn(10,1000) + 1;
%   dat2 = randn(10,1000);
%   design = [1*ones(1,1000) 2*ones(1,1000)];
%   stat = ft_statfun_roc([], [dat1 dat2], design);
%
% See also FT_TIMELOCKSTATISTICS, FT_FREQSTATISTICS or FT_SOURCESTATISTICS

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

% set the defaults
cfg.ivar = ft_getopt(cfg, 'ivar', 1);

% on-the-fly log transformation is not supported any more, please use FT_MATH instead
cfg = ft_checkconfig(cfg, 'forbidden', 'logtransform');
cfg = ft_checkconfig(cfg, 'forbidden', 'numbins');

% start with a quick test to see whether there appear to be NaNs
if any(isnan(dat(1,:)))
  % exclude trials that contain NaNs for all observed data points
  sel    = all(isnan(dat),1);
  dat    = dat(:,~sel);
  design = design(:,~sel);
end

% logical indexing is faster than using find(...)
selA = (design(cfg.ivar,:)==1);
selB = (design(cfg.ivar,:)==2);
% select the data in the two classes
datA = dat(:, selA);
datB = dat(:, selB);

nobs = size(dat,1);
na   = size(datA,2);
nb   = size(datB,2);
auc  = zeros(nobs, 1);

for k = 1:nobs
  % compute the area under the curve for each channel/time/frequency
  a = datA(k,:);
  b = datB(k,:);

  % to speed up the AUC, the critical value is determined by the actual
  % values in class B, which also ensures a regular sampling of the False Alarms
  b = sort(b);

  ca = zeros(nb+1,1);
  ib = zeros(nb+1,1);
  % cb = zeros(nb+1,1);
  % ia = zeros(nb+1,1);

  for i=1:nb
    % for the first approach below, the critval could also be choosen based on e.g. linspace(min,max,n)
    critval = b(i);

    % for each of the two distributions, determine the number of correct and incorrect assignments given the critical value
    % ca(i) = sum(a>=critval);
    % ib(i) = sum(b>=critval);
    % cb(i) = sum(b<critval);
    % ia(i) = sum(a<critval);

    % this is a much faster approach, which works due to using the sorted values in b as the critical values
    ca(i) = sum(a>=critval);   % correct assignments to class A
    ib(i) = nb-i+1;            % incorrect assignments to class B
  end

  % add the end point
  ca(end) = 0;
  ib(end) = 0;
  % cb(end) = nb;
  % ia(end) = na;

  hits = ca/na;
  fa   = ib/nb;

  % the numerical integration is faster if the points are sorted
  hits = fliplr(hits);
  fa   = fliplr(fa);

  if false
    % this part is optional and should only be used when exploring the data
    figure
    plot(fa, hits, '.-')
    xlabel('false positive');
    ylabel('true positive');
    title('ROC-curve');
  end

  % compute the area under the curve using numerical integration
  auc(k) = numint(fa, hits);

end

% return the area under the curve as the statistic of interest
s.stat = auc;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% NUMINT computes a numerical integral of a set of sampled points using
% linear interpolation. Alugh the algorithm works for irregularly sampled points
% along the x-axis, it will perform best for regularly sampled points
%
% Use as
%   z = numint(x, y)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function z = numint(x, y)
if ~all(diff(x)>=0)
  % ensure that the points are sorted along the x-axis
  [x, i] = sort(x);
  y = y(i);
end
n = length(x);
z = 0;
for i=1:(n-1)
  x0 = x(i);
  y0 = y(i);
  dx = x(i+1)-x(i);
  dy = y(i+1)-y(i);
  z = z + (y0 * dx) + (dy*dx/2);
end


% FAST_NONMAX perform non-maximal suppression on FAST features.
%
%     nonmax = FAST_NONMAX(image, threshold, FAST_CORNER_DETECT_9(image, threshold));
%     returns a list of nonmaximally suppressed corners with the X coordinate
%     in nonmax(:,1) and Y in nonmax(:,2).
%
%     If you use this in published work, please cite:
%       Fusing Points and Lines for High Performance Tracking, E. Rosten and T. Drummond, ICCV 2005
%       Machine learning for high-speed corner detection, E. Rosten and T. Drummond, ECCV 2006
%     The Bibtex entries are:
%
%     @inproceedings{rosten_2005_tracking,
%         title       =    "Fusing points and lines for high performance tracking.",
%         author      =    "Edward Rosten and Tom Drummond",
%         year        =    "2005",
%         month       =    "October",
%         pages       =    "1508--1511",
%         volume      =    "2",
%         booktitle   =    "IEEE International Conference on Computer Vision",
%         notes       =    "Oral presentation",
%         url         =    "http://mi.eng.cam.ac.uk/~er258/work/rosten_2005_tracking.pdf"
%     }
%
%     @inproceedings{rosten_2006_machine,
%         title       =    "Machine learning for high-speed corner detection",
%         author      =    "Edward Rosten and Tom Drummond",
%         year        =    "2006",
%         month       =    "May",
%         booktitle   =    "European Conference on Computer Vision (to appear)",
%         notes       =    "Poster presentation",
%         url         =    "http://mi.eng.cam.ac.uk/~er258/work/rosten_2006_machine.pdf"
%     }
%
%
%
%     See also FAST_CORNER_DETECT_9, FAST_CORNER_DETECT_10
%              FAST_CORNER_DETECT_11, FAST_CORNER_DETECT_12
function ret = fast_nonmax(im, barrier, c)
	sz = size(im);
	ysize = sz(1);

	% x, y
	dir=[	0,3
			1,3
			2,2
			3,1
			3,0
			3,-1
			2,-2
			1,-3
			0,-3
			-1,-3
			-2,-2
			-3,-1
			-3,0
			-3,1
			-2,2
			-1,3];

	dir = dir(:,2) + dir(:,1) * ysize;
	centres = c(:,2) + (c(:,1)-1) * ysize;

	%First pass: compute scores for all of the pixels:
	scores = zeros(sz(1) * sz(2), 1);

	for i=1:length(centres)

		p1 = im(centres(i)+dir) -( im(centres(i)) + barrier);
		pos = sum(p1 .* (p1 > 0));
		n1 = im(centres(i)) - barrier - im(centres(i)+dir);
		neg = sum(n1 .* (n1 > 0));

		scores(centres(i)) = max([pos neg]);
	end

	cs = zeros(length(centres),1);

	up = -1;
	down = 1;
	left =-ysize;
	right = ysize;

	%second pass: get local maxima
	for i=1:length(centres)
		p = centres(i);
		square=p +  [ up down left right up+left up+right down+left down+right];

		cs(i) = (sum(scores(p) >= scores(square)) == 8);
	end

	%Get the maxima positions
	maximas = centres(find(cs));

	ret = zeros(length(maximas), 2);

	ret(:,1) = 1 + floor(maximas / ysize);
	ret(:,2) = mod(maximas, ysize);


function [pos, tri] = remove_double_vertices(pos, tri)

% REMOVE_DOUBLE_VERTICES removes double vertices from a triangular, tetrahedral or
% hexahedral mesh, renumbering the vertex-indices for the elements.
%
% Use as
%   [pos, tri] = remove_double_vertices(pos, tri)
%   [pos, tet] = remove_double_vertices(pos, tet)
%   [pos, hex] = remove_double_vertices(pos, hex)
%
% See also REMOVE_VERTICES

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

npos = size(pos, 1);
[dum, keeppos, i2] = unique(pos, 'rows');
clear dum

numb    = zeros(1,npos);
numb(keeppos) = 1:length(keeppos);

% re-index the indices in tri
tri = keeppos(i2(tri));
tri = numb(tri);

% remove the vertices and triangles
pos = pos(keeppos, :);


function [boolval, faxis] = checkfreq(varargin)

% last input is always the required string
tol      = varargin{end};
required = varargin{end-1};
varargin = varargin(1:end-2);

Ndata = numel(varargin);
Nfreq = zeros(1,Ndata);
faxis = zeros(1,0);
for i=1:Ndata
  Nfreq(i) = numel(varargin{i}.freq);
  faxis    = [faxis;varargin{i}.freq(:)];
end

if strcmp(required, 'unique')
  boolval = numel(unique(faxis))==numel(faxis) && ~all(isnan(faxis));
  % the second condition is included when the freq is set to dummy nan
elseif strcmp(required, 'identical')
  % the number of freq bins needs at least to be the same across
  % inputs
  boolval = all(Nfreq==Nfreq(1));
  if boolval
    % then check whether the axes are equal
    faxis   = reshape(faxis, Nfreq(1), []);
    boolval = all(all(abs(faxis - repmat(faxis(:,1), 1, Ndata))<tol)==1);
    faxis   = faxis(:,1);
  end
end


imageRootPath = '/n/fs/vision/datasets/SUN397/';

%% get image list
disp('generating image list...');
folders = genpath(imageRootPath);
folders = regexp(folders,':','split');
folders = folders(1:end-1);
imageList = {};
for f=1:length(folders)
    imagefiles = dir(fullfile(folders{f},'*.jpg'));
    if ~isempty(imagefiles)
        for i=1:length(imagefiles)
            imageList{end+1} = fullfile(folders{f},imagefiles(i).name);
        end
    end
end

%% read image, crop, and resize
disp('reading and resizing images...');

tWidth =32;
tHeight=32;
imArray = uint8(zeros(tHeight,tWidth,3,length(imageList)));

for i=1:length(imageList)
    im = imread(imageList{i});
    w = size(im,2);
    h = size(im,1);
    ch = w/tWidth*tHeight;
    if ch<h
        srow = max(1,floor(h/2-ch/2));
        erow = srow + round(ch)-1;
        im = im(srow:erow,:,:);
    elseif ch>h
        cw = h/tHeight*tWidth;
        if cw<w
            scol = max(1,floor(w/2-cw/2));
            ecol = scol + round(cw)-1;
            im = im(:,scol:ecol,:);
        end
    end

    if size(im,3)==1
        im = im(:,:,[1 1 1]);
    end

    imArray(:,:,:,i) = imresize(im,[tHeight tWidth]);

    if mod(i,100)==1
        fprintf('%d/%d\n',i,length(imageList));
    end
end

save('sun397.mat','-v7.3');

%%
%
load sun397.mat
imArray = double(imArray)/255;

baseImage = 'base9.png';
baseImage = im2double(imread(baseImage));
baseImage = baseImage(:,:,1:3);
nH = floor(size(baseImage,1)/tHeight);
nW = floor(size(baseImage,2)/tWidth);
baseImage = baseImage(1:nH*tHeight,1:nW*tWidth,:);

nI = size(imArray,4);
usedVector = false(1,nI);

mosaicImage = zeros(nH*tHeight,nW*tWidth,3);

for y=randperm(nH)
    ey = y*tHeight;
    sy = ey-tHeight+1;
    for x=randperm(nW)
        ex = x*tWidth;
        sx = ex-tWidth+1;

        sourcePath = baseImage(sy:ey,sx:ex,:);

        diff = sum(sum(sum(abs(imArray - repmat(sourcePath,[1,1,1,nI])),1),2),3);
        diff = reshape(diff,1,[]) + usedVector .* 100000;

        [minVal,minIdx]= min(diff);

        usedVector(minIdx) = true;

        mosaicImage(sy:ey,sx:ex,:) = imArray(:,:,:,minIdx);
    end
end

imwrite(mosaicImage,'mosaic9.png');
imshow(mosaicImage);


%%
%% Run this script in Matlab command window
%%

   function Installmex

   curdir = pwd;
   fprintf(' current directory is:  %s\n',curdir);
%%
%% generate mex files in Mexfun
%%
   if strcmp(computer,'PCWIN64') | strcmp(computer,'GLNXA64')
      computer_model = 64;
   else
      computer_model = 32;
   end
   matlabversion = sscanf(version,'%f');
   matlabversion = matlabversion(1);
   fsp = filesep;
%%
%%
%%
   src = [curdir,fsp,'Solver',fsp,'Mexfun'];
   eval(['cd ','Solver',fsp,'Mexfun']);
   fprintf ('\n Now compiling the mexFunctions in:\n');
   fprintf (' %s\n',src);

   fname{1} = 'mexProd2';
   fname{2} = 'mexProd2nz';
   fname{3} = 'mexinprod';
   fname{4} = 'mexmat';
   fname{5} = 'mexsmat';
   fname{6} = 'mexsvec';
   fname{7} = 'mexschur';
   fname{8} = 'mexqops';
   fname{9} = 'mexexpand';
   fname{10} = 'mexskron';
   fname{11} = 'mexnnz';
   fname{12} = 'mexschurfun';
   fname{13} = 'mexMatvec';
   fname{14} = 'mextriang';
   fname{15} = 'mextriangsp';

   if (matlabversion < 7.3)
      mexcmd = 'mex  -O  ';
   else
      mexcmd = 'mex  -O -largeArrayDims  ';
   end
   for k = 1:length(fname)
      cmd([mexcmd,fname{k},'.c']);
   end
   cd ..
   cd ..
%%
%% generate mex files in spchol
%%
   if (matlabversion < 7.3)
      clear fname
      src = [curdir,fsp,'Linsysolver',fsp,'spchol'];
      eval(['cd ','Linsysolver',fsp,'spchol']);
      fprintf ('\n Now compiling the mexFunctions in:\n');
      fprintf (' %s\n',src);

      fname{1} = 'mexordmmd.c ordmmd.c';
      fname{2} = 'mexsymbfct.c  symbfct.c';
      fname{3} = 'choltmpsiz.c';
      fname{4} = 'cholsplit.c';
      fname{5} = 'mexsparchol.c sparchol2.c sdmauxFill.c sdmauxScalarmul.c';
      fname{6} = 'mexfwblkslv.c sdmauxScalarmul.c';
      fname{7} = 'mexbwblkslv.c sdmauxFill.c sdmauxRdot.c';
      mexcmd = 'mex  -O  ';
      for k = 1:length(fname)
         cmd([mexcmd,fname{k}]);
      end
      cd ..
      cd ..
   end
%%***********************************************
   function cmd(s)

   fprintf(' %s\n',s);
   eval(s);
%%***********************************************


function [stat, cfg] = ft_statistics_mvpa(cfg, dat, design)

% FT_STATISTICS_MVPA performs multivariate pattern classification
% on the data. If the data has not been averaged over time, classification
% is performed separately for every time point. Additionally, searchlight
% analysis (classification for each channel/voxel
% separately) or time x time generalisation can be performed.
%
% This function should not be called directly, instead
% you should call the function that is associated with the type of
% data on which you want to perform the test.
%
% Use as
%   stat = ft_timelockstatistics(cfg, data1, data2, data3, ...)
%   stat = ft_freqstatistics    (cfg, data1, data2, data3, ...)
%   stat = ft_sourcestatistics  (cfg, data1, data2, data3, ...)
% where the data is obtained from FT_TIMELOCKANALYSIS, FT_FREQANALYSIS
% or FT_SOURCEANALYSIS respectively, or from FT_TIMELOCKGRANDAVERAGE,
% FT_FREQGRANDAVERAGE or FT_SOURCEGRANDAVERAGE respectively.
%
% The configuration can contain
%   cfg.searchlight     = 'yes' or 'no', performs searchlight analysis
%                         (default 'no'). More information see below
%   cfg.timextime       = 'yes' or 'no', performs time x time
%                         generalisation. In other words, the classifier
%                         is trained at each time point and tested at
%                         every time point. The result is a time x time
%                         matrix of classification performance.
%                         (default 'no')
%                         Note that searchlight and timextime cannot be
%                         run simultaneously (at least one option needs
%                         to be set to 'no').
%   cfg.mvpa            = structure that contains detailed options for the
%                         MVPA procedure. See
%                         https://github.com/treder/MVPA-Light for more
%                         details.
%
%
%   cfg.mvpa.classifier      = 'lda'          Regularised linear discriminant analysis
%                                        (LDA) (for two classes)
%                         'multiclass_lda' LDA for more than two classes
%                         'logreg'       Logistic regression
%                         'svm'          Support Vector Machine (SVM)
%                         'ensemble'     Ensemble of classifiers. Any of the other
%                                        classifiers can be used as a learner.
%                         'kernel_fda'   Kernel Fisher Discriminant Analysis
%   cfg.mvpa.metric          = string, performance metric. Possible metrics:
%                         accuracy auc tval dval confusion precision
%                         recall f1
%   See https://github.com/treder/MVPA-Light for an overview of all
%   classifiers and metrics.
%
%   cfg.mvpa.param           = struct, structure with hyperparameters for the
%                         classifier (see HYPERPARAMETERS below)
%
%   cfg.mvpa.balance         = string, for imbalanced data that does not have
%                         the same number of instances in each class
%                         'oversample'     oversamples the minority classes
%                         'undersample'    undersamples the minority classes
%                         such that all classes have the same number of
%                         instances. Note that undersampling is at the
%                         level of the repeats, whereas we oversampling occurs within each
%                         training set (for an explanation see mv_balance_classes).
%                         You can also give an integer number for undersampling.
%                         The samples will be reduced to this number. Note that
%                         concurrent over/undersampling (oversampling of the
%                         smaller class, undersampling of the larger class) is not
%                         supported at the moment
%  cfg.mvpa.replace          = bool, if balance is set to 'oversample' or 'undersample',
%                         replace determines whether data is drawn with
%                         replacement (default 1)
%  cfg.mvpa.normalise        = string, normalises the data across samples, for each time point
%                         and each feature separately, using 'zscore' or 'demean'
%                         (default 'zscore'). Set to 'none' or [] to avoid normalisation.
%  cfg.mvpa.feedback         = 'yes' or 'no', whether or not to print feedback on the console (default 'yes')
%
% To obtain a realistic estimate of classification performance,
% cross-validation is used. It is controlled by the following parameters:
%   cfg.mvpa.cv              = string, cross-validation type, either 'kfold', 'leaveout'
%                         or 'holdout'. If 'none', no cross-validation is
%                         used and the classifier is tested on the training
%                         set. (default 'kfold')
%   cfg.mvpa.k               = number of folds in k-fold cross-validation (default 5)
%   cfg.mvpa.repeat          = number of times the cross-validation is repeated
%                         with new randomly assigned folds (default 5)
%   cfg.mvpa.p               = if cfg.cv is 'holdout', p is the fraction of test
%                         samples (default 0.1)
%   cfg.mvpa.stratify        = if 1, the class proportions are approximately
%                         preserved in each test fold (default 1)
%
%
% More information about each classifier is found in the documentation of
% MVPA-Light (github.com/treder/MVPA-Light/).
%
% HYPERPARAMETERS:
% Each classifier comes with its own set of hyperparameters, such as
% regularisation parameters and the kernel. Hyperparameters can be set
% using the cfg.param substruct. For instance, in LDA, cfg.param.lambda =
% 'auto' sets the lambda regularisation parameter.
%
% The specification of the hyperparameters is found in the training function
% for each classifier at github.com/treder/MVPA-Light/tree/master/classifier
% If a hyperparameter is not specified, default values are used.
%
% SEARCHLIGHT ANALYSIS:
% Classification using a feature searchlight approach can highlight which
% feature(s) are informative. To this end, classification is performed on
% each feature separately. However, neighbouring features can enter the
% classification together when specified. Optional parameters:
%
% cfg.mvpa.neighbours   = neighbourhood structure, see FT_PREPARE_NEIGHBOURS
%                         Alternatively, a [features x features] matrix specifying
%                         which features are neighbours of each other. This
%                         matrix can be either
%                         a GRAPH consisting of 0's and 1's. A 1 in the
%                         (i,j)-th element signifies that feature i and feature j
%                         are neighbours, and a 0 means they are not neighbours
%                         or a DISTANCE MATRIX, where larger values mean larger distance.
%                         If no matrix is provided, every feature is only neighbour
%                         to itself and classification is performed for each feature
%                         separately.
% cfg.mvpa.size         = size of the 'neighbourhood' of a feature.
%                         number of steps taken through the neighbourhood
%                         to include neighbours
%                         0: only the feature itself is considered (no neighbours)
%                         1: the feature and its immediate neighbours
%                         2: the feature, its neighbours, and its neighbours'
%                         neighbours
%                         3+: neighbours of neighbours of neighbours etc
%                         (default 1)
%                         if cfg.neighbours is a distance matrix, size defines the number of
%                         neighbouring features that enter the classification
%                         0: only the feature itself is considered (no neighbours)
%                         1: the feature and its first closest neighbour
%                            according to the distance matrix
%                         2+: the 2 closest neighbours etc.
%
% -- TODO: for time x time generalisation, in MVPA light we can use two
% different datasets (one for training the classifier, the other one for
% testing). This could be realised eg using extra fields in cfg such as
% cfg.X2 for dataset 2 and cfg.design2 for the second design matrix
%
% Returns:
%   stat        = struct with results. the .metric field contains the
%                   requested metrics
%

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

ft_hastoolbox('mvpa-light', 1);

% do a sanity check on the input data
assert(isnumeric(dat),    'this function requires numeric data as input, you probably want to use FT_TIMELOCKSTATISTICS, FT_FREQSTATISTICS or FT_SOURCESTATISTICS instead');
assert(isnumeric(design), 'this function requires numeric data as input, you probably want to use FT_TIMELOCKSTATISTICS, FT_FREQSTATISTICS or FT_SOURCESTATISTICS instead');

% cfg: set defaults
cfg.searchlight     = ft_getopt(cfg, 'searchlight', 'no');
cfg.timextime       = ft_getopt(cfg, 'timextime',   'no');
cfg.mvpa            = ft_getopt(cfg, 'mvpa',        []);
cfg.mvpa.metric     = ft_getopt(cfg.mvpa, 'metric',   'accuracy');
cfg.mvpa.feedback   = ft_getopt(cfg.mvpa, 'feedback',   'yes');
cfg.mvpa.neighbours = ft_getopt(cfg.mvpa, 'neighbours', []);

% flip dimensions such that the number of trials comes first
dat = dat';

% if cfg.dim has two entries which are non-singleton then the data has been
% 3D before. We must reshape it from 2D to 3D to run it in MVPA-Light
data_is_3D = (numel(cfg.dim) > 1 && all(cfg.dim > 1));  % checks whether data was 3D before being reshaped
if data_is_3D
  dat = reshape(dat, size(dat,1), cfg.dim(1), cfg.dim(2));
end

y = design;

%% perform sanity checks on parameters
if istrue(cfg.timextime) && istrue(cfg.searchlight)
  ft_error('you should not set timextime = ''yes'' and searchlight = ''yes'' simultaneously')
end

% timextime = 'yes' but data is not 3D we should change timextime to 'no'
if istrue(cfg.timextime) && ~data_is_3D
  ft_warning('timextime = ''yes'' but data has no time dimension, setting timextime = ''no''');
  cfg.timextime = 'no';
end

label = [];
dim   = [];
dimord = [];

%% Call MVPA-Light

if strcmp(cfg.searchlight, 'yes')
  % --- searchlight analysis ---

  if isstruct(cfg.mvpa.neighbours)
    cfg.mvpa.neighbours = channelconnectivity(struct('neighbours',cfg.mvpa.neighbours, 'channel', {cfg.channel}));
  end
  [perf, result] = mv_searchlight(cfg.mvpa, dat, y);

  % this preserves any spatial dimension, so no adjustment is done to a
  % channel list, if present
  if isfield(cfg, 'channel')
    label = cfg.channel;
  end

  if isfield(cfg, 'dim')
    dim = cfg.dim;
  end

elseif strcmp(cfg.timextime, 'yes')
  % --- time x time generalisation ---
  [perf, result] = mv_classify_timextime(cfg.mvpa, dat, y);

  % this does note preserve any spatial dimension, so label should be
  % adjusted
  label = squeezelabel(label, cfg);
  dim   = squeezedim(dim, cfg);
  dimord = 'time_time';

elseif data_is_3D
  % --- classification across time ---
  [perf, result] = mv_classify_across_time(cfg.mvpa, dat, y);

  % this does note preserve any spatial dimension, so label should be
  % adjusted
  label = squeezelabel(label, cfg);
  dim   = squeezedim(dim, cfg);

else
  % --- data has no time dimension, perform only cross-validation ---
  [perf, result] = mv_crossvalidate(cfg.mvpa, dat, y);

  % this does note preserve any spatial dimension, so label should be
  % adjusted
  label = squeezelabel(label, cfg);
  dim   = squeezedim(dim, cfg);

end

%% setup stat struct
stat = [];
if ~iscell(cfg.mvpa.metric), cfg.mvpa.metric = {cfg.mvpa.metric}; end
if ~iscell(perf),            perf            = {perf};            end
for mm=1:numel(perf)

  % Performance metric
  stat.(cfg.mvpa.metric{mm}) = perf{mm};

  % Std of performance
  if iscell(result.perf_std)
    stat.([cfg.mvpa.metric{mm} '_std']) = result.perf_std{mm};
  else
    stat.([cfg.mvpa.metric{mm} '_std']) = result.perf_std;
  end
end

% return the MVPA-Light result struct as well
stat.mvpa = result;

if ~isempty(label)
  stat.label = label;
end

if ~isempty(dim)
  stat.dim = dim;
end

if ~isempty(dimord)
  stat.dimord = dimord;
end

function label = squeezelabel(label, cfg)

if isfield(cfg, 'channel')
  label = sprintf('combined(%s)', sprintf('%s',cfg.channel{:}));
end

function dim = squeezedim(dim, cfg)

if isfield(cfg, 'dim')
  dim = cfg.dim;
  dim(1) = 1;
end


function f = sinh(f)
%SINH   Hyperbolic sine of a CHEBFUN3T object.

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

% Empty check:
if ( isempty(f) )
    return
end

op = @(x,y,z) sinh(feval(f, x, y, z));     % Resample.
f = chebfun3t(op, f.domain);               % Call constructor.

end


function au_qmr_ilu_s_i(p)
%
%  Generates the data used in 'au_qmr_ilu_s'. Data are stored in global
%  variables.
%
%  NOTE that 'au_qmr_ilu_m_i' must be called before calling this routine.
%
%  Calling sequence:
%
%    au_qmr_ilu_s_i(p)
%
%  Input:
%
%    p         vector containing the ADI shift parameters p(i).
%
%  Remarks:
%
%    This routine has access to the matrix A and some other data, which
%    must be provided by the routine 'au_qmr_ilu_m_i',
%
%    The real parts of the entries of p must be negative.
%
%
%  LYAPACK 1.0 (Thilo Penzl, August 1999)

if nargin~=1
  error('Wrong number of input arguments.');
end

if any(real(p)>=0)
  error('Real parts of entries of p must be negative!');
end

l = length(p);

global LP_A LP_P LP_MC LP_TOL_ILU LP_INFO_QMR

if ~length(LP_A) | ~length(LP_MC) | ~length(LP_TOL_ILU) | ~length(LP_INFO_QMR)
  error('This routine needs global data which must be generated by calling ''au_qmr_ilu_m_i'' first.');
end

n = size(LP_A,1);

LP_P = p;

if LP_MC=='C'

  for i = 1:l

    eval(lp_e( 'global LP_L',i,' LP_U',i ));

    eval(lp_e( '[LP_L',i,',LP_U',i,'] = luinc(LP_A+p(i)*speye(n),LP_TOL_ILU);' ));

%
%  This shows the amount of fill-in created by the ILU preconditioner:
%

    if LP_INFO_QMR >= 5
      nnA = nnz(LP_A);
      eval(lp_e( 'nnLU = nnz(LP_L',i,')+nnz(LP_U',i,');'  ));
      disp(sprintf('ILU-Ratio (nnz(L)+nnz(U))/nnz(A) = %6g',nnLU/nnA));
    end
  end

end


function [params, names] = vargpTimeDynamicsExtractParam(model)

% VARGPTIMEDYNAMICSEXTRACTPARAM Extract parameters from the GP time dynamics model.
%
%	Description:
%
%	PARAMS = VARGPTIMEDYNAMICSEXTRACTPARAM(MODEL) extracts the model
%	parameters from a structure containing the information about a
%	Gaussian process dynamics model.
%	 Returns:
%	  PARAMS - a vector of parameters from the model.
%	 Arguments:
%	  MODEL - the model structure containing the information about the
%	   model.
%	DESC does the same as above, but also returns parameter names.
%	ARG model : the model structure containing the information about
%	the model.
%	RETURN params : a vector of parameters from the model.
%	RETURN names : cell array of parameter names.
%
%
%
%	See also
%	GPEXTRACTPARAM, GPTIMEDYNAMICSCREATE, GPTIMEDYNAMICSEXPANDPARAM, MODELEXTRACTPARAM

%	Based on GPTIMEDYNAMICSEXTRACTPARAM
% VARGPLVM

if nargout > 1
  returnNames = true; % Also return parameter names in an array
else
  returnNames = false;
end

% Parameters are extracted in the following order: (notation: % parameter{size})
% [dynamicsVardistParams{dynamics.vardist.nParams}        % mu_bar, lambda
%  dynamics.kernParams{dynamics.kern.nParams}]            % sigmaRBF, lt,
%  sigmaWhite

% Variational parameters (reparametrized means and covariances)
if returnNames
  [varParams, varNames] = modelExtractParam(model.vardist);
  names = varNames;
else
  %varParams = vardistExtractParam(model.vardist);
  varParams = modelExtractParam(model.vardist);
end
params = varParams;

% Kernel parameters
if returnNames
  [kernParams, kernParamNames] = kernExtractParam(model.kern);
  for i = 1:length(kernParamNames)
    kernParamNames{i} = ['Kernel, ' kernParamNames{i}];
  end
  names = {names{:}, kernParamNames{:}};
else
  kernParams = kernExtractParam(model.kern);
end

params = [params kernParams];


function[h]=lansey(N)
%LANSEY  The Lansey modification of Cynthia Brewer's "Spectral" colormap.
%   __________________________________________________________________
%
%   *|* lansey.png --- The lansey colormap versus parula and jet.
%   Type 'jhelp lansey' to view this image. *|*
%   __________________________________________________________________
%
%   LANSEY(M) returns an M-by-3 matrix containing the Lansey colormap.
%
%   LANSEY with no arguments returns a colormap having the same number of
%   colors as the colormap of the current figure.
%
%   This colormap is Jonathan Lansey's modification of the 11-division
%   version of Cynthia Brewer's "Spectral" colormap.
%
%   LINSPECER itself is available from
%
%       http://www.mathworks.com/matlabcentral/fileexchange/42673.
%
%   This product includes color specifications and designs developed by
%   Cynthia Brewer (http://colorbrewer.org/).
%
%   LANSEY is a simplified version of LINSPECER by Jonathan Lansey,
%   modified and redistributed in accordance with the copyright policies
%   of LINSPECER and ColorBrewer.org, see LANSEY_COPYRIGHT for details.
%
%   To make LANSEY your default colormap, add to your startup.m file the
%   line "set(0,'DefaultFigureColormap',lansey)".
%
%   'lansey --f' generates the figure shown above.
%
%   Usage: h=lansey(M);
%          colormap lansey
%   __________________________________________________________________
%   This is part of JLAB --- type 'help jlab' for more information
%   (C) 2015 J.M. Lilly --- type 'help jlab_license' for details

if nargin>0
    if strcmpi(N, '--f')
       type makefigs_lansey
       makefigs_lansey;
       return
    end
end

if nargin < 1, N = size(get(gcf,'colormap'),1); end

h = cmap2linspecer(colorm(N));
h = cell2mat(h);

function[vOut] = cmap2linspecer(vIn) % changes the format from a double array to a cell array with the right format
vOut = cell(size(vIn,1),1);
for ii=1:size(vIn,1)
    vOut{ii} = vIn(ii,:);
end

% Jonathan Lansay's notes:
% colorm returns a colormap which is really good for creating informative
% heatmap style figures.
% No particular color stands out and it doesn't do too badly for colorblind people either.
% It works by interpolating the data from the
% 'spectral' setting on http://colorbrewer2.org/ set to 11 colors
% It is modified a little to make the brightest yellow a little less bright.
function[cmap] = colorm(varargin)
n = varargin{1};
%frac=1;
frac=.95; % Slight modification from colorbrewer here to make the yellows in the center just a bit darker
cmapp = [158, 1, 66; 213, 62, 79; 244, 109, 67; 253, 174, 97; 254, 224, 139; 255*frac, 255*frac, 191*frac; 230, 245, 152; 171, 221, 164; 102, 194, 165; 50, 136, 189; 94, 79, 162];
x = linspace(1,n,size(cmapp,1));
xi = 1:n;
cmap = zeros(n,3);
for ii=1:3
    cmap(:,ii) = pchip(x,cmapp(:,ii),xi);
end
cmap = flipud(cmap/255);


function [f, logscale] = fwd1(engine, ev, t)
% Forwards pass for slice 1.

bnet = bnet_from_engine(engine);
ss = bnet.nnodes_per_slice;

CPDpot = cell(1,ss);
for n=1:ss
  fam = family(bnet.dag, n, 1);
  e = bnet.equiv_class(n, 1);
  CPDpot{n} = convert_to_pot(bnet.CPD{e}, engine.pot_type, fam(:), ev);
end
f.t = t;
f.evidence = ev;

pots = CPDpot;
slice1 = 1:ss;
CPDclqs = engine.clq_ass_to_node1(slice1);

[f.clpot, f.seppot] =  init_pot(engine.jtree_engine1, CPDclqs, CPDpot, engine.pot_type, engine.observed1);
[f.clpot, f.seppot] = collect_evidence(engine.jtree_engine1, f.clpot, f.seppot);
for c=1:length(f.clpot)
  [f.clpot{c}, ll(c)] = normalize_pot(f.clpot{c});
end
logscale = ll(engine.root1);


% this code is revised based on ILSVRC 2013 (http://www.image-net.org/challenges/LSVRC/2013/)

function  top_recall = top_recall_Phrase(Nre, tuple_confs_cell, tuple_labels_cell, sub_bboxes_cell, obj_bboxes_cell)

load('gt.mat','gt_tuple_label','gt_obj_bboxes','gt_sub_bboxes');

%num_imgs = length(gt_tuple_label);
num_imgs = 1000;
for i=1:num_imgs
    [tuple_confs_cell{i}, ind] = sort(tuple_confs_cell{i},'descend');
    if length(ind) >= Nre
        tuple_confs_cell{i} = tuple_confs_cell{i}(1:Nre);
        tuple_labels_cell{i} = tuple_labels_cell{i}(ind(1:Nre),:);
        obj_bboxes_cell{i} = obj_bboxes_cell{i}(ind(1:Nre),:);
        sub_bboxes_cell{i} = sub_bboxes_cell{i}(ind(1:Nre),:);
    else
        tuple_labels_cell{i} = tuple_labels_cell{i}(ind,:);
        obj_bboxes_cell{i} = obj_bboxes_cell{i}(ind,:);
        sub_bboxes_cell{i} = sub_bboxes_cell{i}(ind,:);
    end
end

num_pos_tuple = 0;
for ii = 1 : num_imgs
    num_pos_tuple = num_pos_tuple + size(gt_tuple_label{ii},1);
end

tp_cell = cell(1,num_imgs);
fp_cell = cell(1,num_imgs);

gt_thr = 0.5;
% iterate over images
for i=1:num_imgs

    gt_tupLabel = gt_tuple_label{i};

    if ~isempty(gt_obj_bboxes{i})
        gt_box_entity = [min(gt_obj_bboxes{i}(:,1:2),gt_sub_bboxes{i}(:,1:2)),max(gt_obj_bboxes{i}(:,3:4),gt_sub_bboxes{i}(:,3:4))];
    else
        gt_box_entity = [];
    end

    num_gt_tuple = size(gt_tupLabel,1);
    gt_detected = zeros(1,num_gt_tuple);

    labels = tuple_labels_cell{i};

    boxObj = obj_bboxes_cell{i};
    boxSub = sub_bboxes_cell{i};
    if ~isempty(boxObj)
        box_entity_our  = [min(boxObj(:,1:2), boxSub(:,1:2)), max(boxObj(:,3:4), boxSub(:,3:4))];
    else
        box_entity_our  = [];
    end

    num_obj = size(labels,1);
    tp = zeros(1,num_obj);
    fp = zeros(1,num_obj);
    for j=1:num_obj

        bbO = box_entity_our(j,:);
        ovmax = -inf;
        kmax = -1;

        for k=1:num_gt_tuple
            if norm(labels(j,:) - gt_tupLabel(k,:),2) ~= 0
                continue;
            end
            if gt_detected(k) > 0
                continue;
            end

            bbgtO = gt_box_entity(k,:);

            biO=[max(bbO(1),bbgtO(1)) ; max(bbO(2),bbgtO(2)) ; min(bbO(3),bbgtO(3)) ; min(bbO(4),bbgtO(4))];
            iwO=biO(3)-biO(1)+1;
            ihO=biO(4)-biO(2)+1;

            if iwO>0 & ihO>0
                % compute overlap as area of intersection / area of union
                uaO=(bbO(3)-bbO(1)+1)*(bbO(4)-bbO(2)+1)+...
                   (bbgtO(3)-bbgtO(1)+1)*(bbgtO(4)-bbgtO(2)+1)-...
                   iwO*ihO;
                ov =iwO*ihO/uaO;

                % makes sure that this object is detected according
                % to its individual threshold
                if ov >= gt_thr && ov > ovmax
                    ovmax=ov;
                    kmax=k;
                end
            end
        end

        if kmax > 0
            tp(j) = 1;
            gt_detected(kmax) = 1;
        else
            fp(j) = 1;
        end
    end

    % put back into global vector
    tp_cell{i} = tp;
    fp_cell{i} = fp;

end

t = tic;
tp_all = [];
fp_all = [];
confs = [];
for ii = 1 : num_imgs
tp_all = [tp_all; tp_cell{ii}(:) ];
fp_all = [fp_all; fp_cell{ii}(:) ];
confs = [confs; tuple_confs_cell{ii}(:)];
end

[confs, ind] = sort(confs,'descend');
tp_all = tp_all(ind);
fp_all = fp_all(ind);

tp = cumsum(tp_all );
fp = cumsum(fp_all );
recall =(tp/num_pos_tuple);
top_recall = recall(end);

end


function model = createToyModelForGeoFBA()
%createToyModelForMDFBA creates a toy model for
%MDFBA
% The model created looks as follows:
%
%
%   <-> A -> B ---> C --> E <->
%        \                ^
%         \              /
%           --> F --> G
%
%
% A normal FBA maximizing the production of E should not yield any flux
% through A -> D
% MDFBA should show this flux.

model = createModel();
%Reactions in {Rxn Name, MetaboliteNames, Stoichiometric coefficient} format
Reactions = {'R1',{'A','B'},[-1 1];...
             'R2',{'B','C'},[-1  1];...
             'R3',{'C','E'},[-1  1];...
             'R4',{'A','F'},[-1 1];...
             'R6',{'F','G'},[-1 1];...
             'R7',{'G','E'},[-1 1]};
ExchangedMets = {'A','E'};
%Add Reactions
for i = 1:size(Reactions,1)
    %All reactions are irreversible
    model = addReaction(model,Reactions{i,1},Reactions{i,2},Reactions{i,3},0,0,1000);
end

%Add Exchangers
model = addExchangeRxn(model,ExchangedMets,-1000*ones(numel(ExchangedMets),1),1000*ones(numel(ExchangedMets),1));
model = changeObjective(model,'EX_E',1);


%MATCHLABLIST Match entries of lablist1 with lablist2
%
%    I = MATCHLABLIST(LABLIST1,LABLIST2)
%
% INPUT
%    LABLIST1  list of class names
%    LABLIST2  list of class names
%
% OUTPUT
%    I         indices for LABLIST1 appearing in LABLIST2
%
% DESCRIPTION
% Find the indices of places where the entries of LABLIST1 appear
% in LABLIST2, i.e. LABLIST1 = LABLIST2(I).
% Note that this operation is not symmetric, changing the order of
% LABLIST1 and LABLIST2 changes I!
% I(i) = 0 for labels appearing in LABLIST1 that are not in LABLIST2.
%
% SEE ALSO (PRTools Guide)
% DATASETS, RENUMLAB

% Copyright: D.M.J. Tax davidt@ph.tn.tudelft.nl
% Faculty of Applied Sciences, Delft University of Technology
% P.O. Box 5046, 2600 GA Delft, The Netherlands

function I = matchlablist(lablist1,lablist2)
	n = size(lablist1,1);
I = zeros(n,1); % the resulting vector

if isempty(lablist2) % nothing fits
	return
end

if iscell(lablist1) & iscell(lablist2)
	lablist1 = char(lablist1);
	lablist2 = char(lablist2);
end

for i=1:n
	if isstr(lablist1) & isstr(lablist2)
  	tmp = strmatch(deblank(lablist1(i,:)),lablist2,'exact');
	elseif ~isstr(lablist1) & ~isstr(lablist2)
		tmp = find(~sum((lablist2 ~= repmat(lablist1(i),size(lablist2,1),1)),2));
	else
		tmp = zeros(size(lablist1,1),1);
	end
  if ~isempty(tmp)
		I(i) = tmp(1);
	else
		I(i) = 0;
  end
end

return


function [adfreq, n, ts, fn] = plx_ad_gap_info(filename, channel)
% plx_ad_gap_info(filename, channel): read a/d info from a .plx or .pl2 file
%
% [adfreq, n, ts, fn] = plx_ad_gap_info(filename, channel)
%
% INPUT:
%   filename - if empty string, will use File Open dialog
%   channel - 0-based channel number or channel name
%
%           a/d data come in fragments. Each fragment has a timestamp
%           and a number of a/d data points. The timestamp corresponds to
%           the time of recording of the first a/d value in this fragment.
%           All the data values stored in the vector ad.
%
% OUTPUT:
%   adfreq - digitization frequency for this channel
%   n - total number of data points
%   ts - array of fragment timestamps (one timestamp per fragment, in seconds)
%   fn - number of data points in each fragment

adfreq = 0;
n = 0;
ts = -1;
fn = -1;

if nargin ~= 2
    error 'expected 2 input arguments';
end

[ filename, isPl2 ] = internalPL2ResolveFilenamePlx( filename );
if isPl2 == 1
    pl2Channel = channel;
    % PL2 uses 1-based channel numbers
    if ischar(channel) == 0
        pl2Channel = channel+1;
    end
    pl2ad = PL2Ad(filename, pl2Channel);
    if numel(pl2ad.Values) > 0
        adfreq = pl2ad.ADFreq;
        n = numel(pl2ad.Values);
        ts = pl2ad.FragTs;
        fn = pl2ad.FragCounts;
    end
    return;
end

channelNumber = plx_ad_resolve_channel(filename, channel);
if channelNumber == -1
    fprintf('\n plx_ad_gap_info: no header for the specified A/D channel.');
    fprintf('\n    use plx_ad_info(filename) to print the list of a/d channels\n');
    return
end

[adfreq, n, ts, fn] = mexPlex(24, filename, channelNumber);

end


function cirpva()
    % unclear purpose, having to do with a circle selection
%   This subroutine "circle"  selects the Ni closest earthquakes
%   around a interactively selected point.  Resets ZG.newcat and ZG.newt2
%   Operates on "primeCatalog".
 % turned into function by Celso G Reyes 2017

ZG=ZmapGlobal.Data; % used by get_zmap_globals

%  Input Ni:
%
report_this_filefun();
ZG=ZmapGlobal.Data;

delete(findobj('Tag','plos1'));

axes(h1)
%zoom off

titStr ='Selecting EQ in Circles                         ';
messtext= ...
    ['                                                '
    '  Please use the LEFT mouse button              '
    ' to select the center point.                    '
    ' The "ni" events nearest to this point          '
    ' will be selected and displayed in the map.     '];

msg.dbdisp(messtext, titStr);

% Input center of circle with mouse
%
[xa0,ya0]  = ginput(1);

stri1 = [ 'Circle: ' num2str(xa0,5) '; ' num2str(ya0,4)];
stri = stri1;
pause(0.1)

if met == 'ni'
    % take first ni and sort by time
    [ZG.newt2, max_rad] = ZG.primeCatalog.selectClosestEvents(ya0, xa0, [], ni);
    messtext = ['Radius of selected Circle:' num2str(maxrad)  ' km' ];
    disp(messtext)
elseif  met == 'ra'
    ZG.newt2 = ZG.primeCatalog.selectRadius(ya0, xa0, ra,'kilometer');
    messtext = ['Number of selected events: ' num2str(ZG.newt2.Count)  ];
    disp(messtext)
elseif met == 'ti'
    global t1 t2 t3 t4
    ZG.newt2 = copy(ZG.primeCatalog);
    lt =  ZG.newt2.Date >= t1 &  ZG.newt2.Date <t2 ;
    bdiff(ZG.newt2.subset(lt));
    ZG.hold_state=true;
    lt =  ZG.newt2.Date >= t3 &  ZG.newt2.Date <t4 ;
    bdiff(ZG.newt2.subset(lt));

end
R2 = ra;

%
% plot Ni clostest events on map as 'x':

set(gca,'NextPlot','add')
plot(ZG.newt2.Longitude,ZG.newt2.Latitude,'xk','Tag','plos1');

% plot circle containing events as circle
x = -pi-0.1:0.1:pi;
pl = plot(xa0+sin(x)*R2/(cosd(ya0)*111), ya0+cos(x)*R2/(cosd(ya0)*111),'k')

set(gcf,'Pointer','arrow')

%
newcat = ZG.newt2;                   % resets ZG.newcat and ZG.newt2

        ZG=ZmapGlobal;
        ctp=CumTimePlot(ZG.newt2);
        ctp.plot();
MyPvalClass.pvalcat

end


function test_headmodel_interpolate

% WALLTIME 00:45:00
% MEM 6gb
% DEPENDENCY mesh_sphere ft_headmodeltype ft_headmodel_interpolate ft_prepare_vol_sens ft_compute_leadfield leadfield_interpolate ft_apply_transform

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% create a set of electrodes that nicely covers the upper half of a sphere
[pnt, tri] = mesh_sphere(162);
pnt = pnt .* 10; % convert to cm
sel = find(pnt(:,3)>0);
elec1 = [];
elec1.elecpos = pnt(sel,:);
for i=1:length(sel)
  elec1.label{i} = sprintf('elec%d', i);
end
elec1.unit = 'cm';

% create another set of electrodes covering the upper half of a sphere
pnt = elec1.elecpos(1:42,:) + randn(42,3);
elec2 = [];
for i=1:size(pnt,1)
  elec2.elecpos(i,:) = pnt(i,:)./norm(pnt(i,:)) * 10;
  elec2.label{i} = sprintf('rand%d', i);
end
elec2.unit = 'cm';

% create another set of electrodes representing a bipolar montage
bipolar = [];
bipolar.labelold = elec1.label;
bipolar.tra = zeros(length(elec1.label)-1, length(elec1.label));
for i=1:(length(bipolar.labelold)-1)
  bipolar.labelnew{i} = sprintf('%s-%s', bipolar.labelold{i}, bipolar.labelold{i+1});
  bipolar.tra(i,i  ) = +1;
  bipolar.tra(i,i+1) = -1;
end
elec3 = ft_apply_montage(elec1, bipolar);

% create an identical set of electrodes but with other channel names
elec4 = elec1;
for i=1:length(elec4.label)
  elec4.label{i} = sprintf('chan%d', i);
end

% update the electrode sets to the latest standards
elec1 = ft_datatype_sens(elec1);
elec2 = ft_datatype_sens(elec2);
elec3 = ft_datatype_sens(elec3);
elec4 = ft_datatype_sens(elec4);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% construct a singlesphere volume conduction model
volA   = [];
volA.c = 1;
volA.r = 10;
volA.o = [0 0 0];

% compute the precomputed leadfield
cfg = [];
cfg.headmodel = volA;
cfg.elec = elec1;
cfg.resolution = 1;
leadfield = ft_prepare_leadfield(cfg);

% remember one position
firstindx = find(leadfield.inside, 1, 'first');
pos1 = leadfield.pos(firstindx,:);
pos2 = [0 0 7];

% remember the precomputed leadfield for the first dipole
lf1 = leadfield.leadfield{firstindx};

% the following call generates the volume conduction model and writes all files to disk
filename = fullfile(tempname, 'leadfield');
ft_headmodel_interpolate(filename, elec1, leadfield, 'smooth', false);

% the next day you would start by reading it from disk
volB = ft_read_headmodel([filename '.mat']); % this is a mat file containing the "vol" structure

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% use the same electrodes
[volAA, elecAA] = ft_prepare_vol_sens(volA, elec1);
[volBB, elecBB] = ft_prepare_vol_sens(volB, elec1);

% compare the leadfields
lfa = ft_compute_leadfield(pos1, elecAA, volAA); % the original
lfb = ft_compute_leadfield(pos1, elecBB, volBB); % the interpolation

assert(all(mean(lfa, 1)<eps(double(1))), 'the leadfield is not average referenced'); % this is in double precision
assert(all(mean(lfb, 1)<eps(single(1))), 'the leadfield is not average referenced'); % this is in single precision
assert(isalmostequal(lf1, lfb, 'reltol', 1e-4), 'the leadfields are different');
assert(isalmostequal(lfa, lfb, 'reltol', 1e-4), 'the leadfields are different');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% use a subset of electrodes
[volAA, elecAA] = ft_prepare_vol_sens(volA, elec1, 'channel', elec1.label(1:50));
[volBB, elecBB] = ft_prepare_vol_sens(volB, elec1, 'channel', elec1.label(1:50));

% compare the leadfields
lfa = ft_compute_leadfield(pos1, elecAA, volAA); % the original
lfb = ft_compute_leadfield(pos1, elecBB, volBB); % the interpolation

assert(all(mean(lfa, 1)<eps), 'the leadfield is not average referenced');
assert(all(mean(lfb, 1)<eps), 'the leadfield is not average referenced');
assert(isalmostequal(lfa, lfb, 'reltol', 1e-3), 'the leadfields are different');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% use the same electrodes with with different names
[volAA, elecAA] = ft_prepare_vol_sens(volA, elec4);
[volBB, elecBB] = ft_prepare_vol_sens(volB, elec4);

% compare the leadfields
lfa = ft_compute_leadfield(pos1, elecAA, volAA); % the original
lfb = ft_compute_leadfield(pos1, elecBB, volBB); % the interpolation

assert(all(mean(lfa, 1)<eps), 'the leadfield is not average referenced');
assert(all(mean(lfb, 1)<eps), 'the leadfield is not average referenced');
assert(isalmostequal(lfa, lfb, 'reltol', 1e-4), 'the leadfields are different');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% use electrodes with a different placement
[volAA, elecAA] = ft_prepare_vol_sens(volA, elec2);
[volBB, elecBB] = ft_prepare_vol_sens(volB, elec2);

% compare the leadfields
lfa = ft_compute_leadfield(pos2, elecAA, volAA); % the original
lfb = ft_compute_leadfield(pos2, elecBB, volBB); % the interpolation

assert(all(mean(lfa, 1)<eps), 'the leadfield is not average referenced');
assert(all(mean(lfb, 1)<eps), 'the leadfield is not average referenced');
c = corrcoef(lfa(:), lfb(:)); c = c(1,2);
assert(c>0.8, 'the leadfields are different');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% use a bipolar electrode montage
[volAA, elecAA] = ft_prepare_vol_sens(volA, elec3);
[volBB, elecBB] = ft_prepare_vol_sens(volB, elec3);

% compare the leadfields
lfa = ft_compute_leadfield(pos2, elecAA, volAA); % the original
lfb = ft_compute_leadfield(pos2, elecBB, volBB); % the interpolation

assert(~all(mean(lfa, 1)<eps), 'the leadfield is average referenced'); % it should NOT be average referenced
assert(~all(mean(lfb, 1)<eps), 'the leadfield is average referenced'); % it should NOT be average referenced
assert(isalmostequal(lfa, lfb, 'abstol', inf, 'reltol', inf, 'relnormtol', 1e-3), 'the leadfields are different');


function W=watdet3(watermarkim,originalim);

a=marked-image1;
[ca ch cv cd]=dwt2(a,'db1');
imshow(ca);


% STD_REJECTOUTLIERS  - Commandline function, to reject outlier component(s) from clusters.
%                            Reassign the outlier component(s) to an outlier cluster specific to each cluster.
% Usage:
%                   >> [STUDY] = std_rejectoutliers(STUDY, ALLEEG, clusters, th);
% Inputs:
%   STUDY         - EEGLAB STUDY set comprising some or all of the EEG datasets in ALLEEG.
%   ALLEEG        - global EEGLAB vector of EEG structures for the dataset(s) included in the STUDY.
%                       ALLEEG for a STUDY set is typically created using LOAD_ALLEEG.
% Optional inputs:
%   clusters        - [numeric vector| 'all' ] specific cluster numbers (or 'all' clusters), which outliers
%                        will be rejected from. {default:'all'}.
%   th                 - [number] a threshold factor to select outliers. How far a component can be from the
%                       cluster centroid (in the cluster std multiples) before it will be considered as an outlier.
%                       Components that their distance from the cluster centroid are more than this factor
%                       times the cluster std (th *std) will be rejected. {default: 3}.
%
% Outputs:
%   STUDY    - the input STUDY set structure modified with the components reassignment,
%                    from the cluster to its outlier cluster.
%
%   Example:
%                         >> clusters = [10 15]; th = 2;
%                         >> [STUDY] = std_rejectoutliers(STUDY, ALLEEG, clusters, th);
%                    Reject outlier components (that are more than 2 std from the cluster centroid) from cluster 10 and 15.
%
%  See also  pop_clustedit
%
% Authors:  Hilit Serby, Arnaud Delorme, Scott Makeig, SCCN, INC, UCSD, July, 2005

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

function STUDY = std_rejectoutliers(STUDY, ALLEEG, varargin)

cls = 2:length(STUDY.cluster); % all clusters in STUDY
th = 3; % The threshold factor - default: 3

if length(varargin) > 1
    if isnumeric(varargin{1})
        cls = varargin{1};
        if isempty(cls)
            cls = 2:length(STUDY.cluster);
        end
    else
        if ischar(varargin{1}) && strcmpi(varargin{1}, 'all')
            cls = 2:length(STUDY.cluster);
        else
            error('std_prejectoutliers: clusters input takes either specific clusters (numeric vector) or keyword ''all''.');
        end
    end
end
tmp =[];
for k = 1: length(cls)
    % don't include 'Notclust' clusters
    if ~strncmpi('Notclust',STUDY.cluster(cls(k)).name,8) && ~strncmpi('ParentCluster',STUDY.cluster(cls(k)).name,13)
        tmp = [tmp cls(k)];
    end
end
cls = tmp;
clear tmp

if length(varargin) == 2
    if isnumeric(varargin{2})
        th = varargin{2};
    else
        error('std_prejectoutliers: std input must be a numeric value.');
    end
end

% Perform validity checks
for k = 1:length(cls)
	% Cannot reject outlier components if cluster is a 'Notclust' or 'Outlier' cluster
	if strncmpi('Notclust',STUDY.cluster(cls(k)).name,8) || strncmpi('Outliers',STUDY.cluster(cls(k)).name,8) || ...
        strncmpi('ParentCluster', STUDY.cluster(cls(k)).name,13)
        warndlg2('Cannot reject outlier components from a Notclust or Outliers cluster');
        return;
	end
	% Cannot reject outlier components if cluster has children clusters
	if ~isempty(STUDY.cluster(cls(k)).child)
        warndlg2('Cannot reject outlier components if cluster has children clusters.');
        return;
	end

    % If the PCA data matrix of the cluster components is empty (case of merged cluster)
    if isempty(STUDY.cluster(cls(k)).preclust.preclustdata) % No preclustering information
        warndlg2('Cannot reject outlier components if cluster was not a part of pre-clustering.');
        return;
	end
end

% For each of the clusters reject outlier components
for k = 1:length(cls)
    % The PCA data matrix of the cluster components
    clsPCA = STUDY.cluster(cls(k)).preclust.preclustdata;
    % The cluster centroid
    clsCentr = mean(clsPCA,1);
    % The std of the cluster (based on the distances between all cluster components to the cluster centroid).
    std_std = std(sum((clsPCA-ones(size(clsPCA,1),1)*clsCentr).^2,2),1);
    outliers = [];
    for l = 1:length(STUDY.cluster(cls(k)).comps)
        compdist = sum((clsPCA(l,:) - clsCentr).^2); % Component distance from cluster centroid
        if compdist > std_std * th % check if an outlier
            outliers = [ outliers l];
        end
    end
    % Move outlier to the outlier cluster
    if ~isempty(outliers) % reject outliers if exist
        STUDY = std_moveoutlier(STUDY, ALLEEG,cls(k) , outliers);
    end
end


function [predict_label,accuracy] = jddt(x_train,y_train,x_test,y_test,options)
%%jddt:packaged decision tree from Matlab,just for easier use.
%%==============================================================================
%%input:
%%------x_train,...,y_test  :   training and testing sets.                               [required]
%%------options             :   some options to build the tree,default is null.    [not required]

%%output:
%%------predict_label       :   predicted label vector for test case.
%%------accuracy            :   accuracy
%%==============================================================================
	predict_label = [];
    accuracy = 0;
	switch nargin
		case 4
			tre = fitctree(x_train,y_train);
	        predict_label = tre.predict(x_test);
			accuracy = mean(predict_label == y_test);
		case 5
			tre = fitctree(x_train,y_train,options);
			predict_label = tre.predict(x_test);
			accuracy = mean(predict_label == y_test);
		otherwise
			fprintf('++++++Fatal error!Please check the input!');
            return
	end
end


function [ alphas, betas, thetas, final_likelihood] = CCNF_training_bfgs(thresholdX, thresholdFun, x, y, alphas, betas, thetas, lambda_a, lambda_b, lambda_th, similarityFNs, sparsityFNs, varargin)
%CCNF_training_bfgs Performs CCNF training using BFGS (or LBFGS)

    if(sum(strcmp(varargin,'const')))
        ind = find(strcmp(varargin,'const')) + 1;
        const = varargin{ind};
    else
        const = false;
    end

    if(iscell(x))
        num_seqs = numel(x);

        x = cell2mat(x)';
        % add a bias term
        x =  cat(1, ones(1,size(x,2)), x);

        % If all of the sequences are of the same length can flatten them
        % to the same matrix
        if(const)

            y = cell2mat(y);
            y = reshape(y, numel(y)/num_seqs, num_seqs);
        end

    else
        % if not a cell it has already been flattened, and is constant
        % (most likely)
        num_seqs = varargin{find(strcmp(varargin, 'num_seqs'))+1};
    end

    % Should try a bunch of seed for initialising theta?
    if(sum(strcmp(varargin,'reinit')))
        ind = find(strcmp(varargin,'reinit')) + 1;
        reinit = varargin{ind};
    else
        reinit = false;
    end

    % It is possible to predefine the components B^(k) and C^(k) required
    % to compute B and and C terms and partial derivative (from equations
    % 30 and 31 in Appendix B), also can predefine yB^(k)y and yC^(k)y,
    % as they also do not change through the iterations
    % In constant case Precalc_Bs are same across the sequences, same for
    % PrecalcBsFlat, however yB^(k)y is defined per sequence
    if(sum(strcmp(varargin,'PrecalcBs')) && sum(strcmp(varargin,'PrecalcBsFlat'))...
             && sum(strcmp(varargin,'Precalc_yBy')))
        ind = find(strcmp(varargin,'PrecalcBs')) + 1;
        Precalc_Bs = varargin{ind};

        ind = find(strcmp(varargin,'PrecalcBsFlat')) + 1;
        Precalc_Bs_flat = varargin{ind};

        ind = find(strcmp(varargin,'Precalc_yBys')) + 1;
        Precalc_yBys = varargin{ind};
    else
        % if these are not provided calculate them
        [ ~, Precalc_Bs, Precalc_Bs_flat, Precalc_yBys ] = CalculateSimilarities( num_seqs, x, similarityFNs, sparsityFNs, y, const);
    end

    % Reinitialisation attempts to find a better starting point for the
    % model training (sometimes helps sometimes doesn't)
    if(reinit)

        rng(0);

        % By default try 200 times, but can override
        num_reinit = 200;

        if(sum(strcmp(varargin,'num_reinit')))
            num_reinit = varargin{find(strcmp(varargin,'num_reinit')) + 1};
        end

        thetas_good = cell(num_reinit, 1);
        lhoods = zeros(num_reinit, 1);
        for i=1:num_reinit
            initial_Theta = randInitializeWeights(size(thetas,2)-1, numel(alphas));
            lhoods(i) = LogLikelihoodCCNF(y, x, alphas, betas, initial_Theta, lambda_a, lambda_b, lambda_th, Precalc_Bs_flat, [], [], [], [], const, num_seqs);
            thetas_good{i} = initial_Theta;
        end
        [~,ind_max] = max(lhoods);
        thetas = thetas_good{ind_max};
    end

    params = [alphas; betas; thetas(:)];

    if(any(strcmp(varargin,'lbfgs')))
        options = optimset('Algorithm','interior-point','GradObj','on', 'Hessian', 'lbfgs', 'TolX', thresholdX, 'TolFun', thresholdFun, 'display', 'off');
    else
        options = optimset('Algorithm','interior-point','GradObj','on', 'Hessian', 'bfgs', 'TolX', thresholdX, 'TolFun', thresholdFun, 'display', 'off');
    end

    if(any(strcmp(varargin,'max_iter')))
        options.MaxIter = varargin{find(strcmp(varargin,'max_iter')) + 1};
    end

    objectiveFun = @(params)objectiveFunction(params, numel(alphas), numel(betas), size(thetas), lambda_a, lambda_b, lambda_th, Precalc_Bs, x, y, Precalc_yBys, Precalc_Bs_flat, const);

    lowerBound = [zeros(numel(alphas)+numel(betas),1); -Inf(numel(thetas),1)];

    upperBound = Inf(numel(params),1);
    params = fmincon(objectiveFun, params, [], [],[],[], lowerBound, upperBound, [], options);
    alphas = params(1:numel(alphas));
    betas = params(numel(alphas)+1:numel(alphas)+numel(betas));
    thetas = reshape(params(numel(alphas) + numel(betas) + 1:end), size(thetas));

    final_likelihood = LogLikelihoodCCNF(y, x, alphas, betas, thetas, lambda_a, lambda_b, lambda_th, Precalc_Bs_flat, [], [], [], [], const, num_seqs);

end

function [loss, gradient] = objectiveFunction(params, numAlpha, numBeta, sizeTheta, lambda_a, lambda_b, lambda_th, PrecalcQ2s, x, y, PrecalcYqDs, PrecalcQ2sFlat, const)

    alphas = params(1:numAlpha);
    betas = params(numAlpha+1:numAlpha+numBeta);
    thetas = reshape(params(numAlpha + numBeta + 1:end), sizeTheta);

    num_seqs = size(PrecalcYqDs,1);

    [gradient, SigmaInvs, CholDecomps, Sigmas, bs, all_x_resp] = gradientCCNF(params, numAlpha, numBeta, sizeTheta, lambda_a, lambda_b, lambda_th, PrecalcQ2s, x, y, PrecalcYqDs, PrecalcQ2sFlat, const, num_seqs);

    % as bfgs does gradient descent rather than ascent, negate the results
    gradient = -gradient;
    loss = -LogLikelihoodCCNF(y, x, alphas, betas, thetas, lambda_a, lambda_b, lambda_th, PrecalcQ2sFlat, SigmaInvs, CholDecomps, Sigmas, bs, const, num_seqs, all_x_resp);
end