% pop_rejchanspec() - reject artifacts channels in an EEG dataset using
%                  channel spectrum. The average spectrum for all selected
%                  is computed and a threshold is applied.
%
% Usage:
%   >> pop_rejchanspec( INEEG ) % pop-up interative window mode
%   >> [OUTEEG, indelec] = pop_rejchanspec( INEEG, 'key', 'val');
%
% Inputs:
%   INEEG       - input EEGLAB dataset
%
% Optional inputs:
%   'freqlims'  - [min max] frequency limits. May also be an array where
%                 each row defines a different set of limits. Default is
%                 35 to the Niquist frequency of the data.
%   'stdthresh' - [max] positive threshold in terms of standard deviation.
%                 Default is 5.
%   'absthresh' - [max] positive threshold in terms of spectrum units
%                 (overides the option above).
%   'averef'    - ['on'|'off'] 'on' computes average reference before
%                 applying threshold. Default is 'off'.
%   'plothist'  - ['on'|'off'] 'on' plot the histogram of values along
%                 with the threshold.
%   'plotchans'  - ['on'|'off'] 'on' plot the channels scrollplot with
%                 selected channels for rejection in red. Allow selected
%                 channels rejection with the 'REJECT' button.
%   'elec'      - [integer array] only include specific channels. Default
%                 is to use all channels.
%   'specdata'  - [fload array] use this array containing the precomputed
%                 spectrum instead of computing the spectrum. Default is
%                 empty.
%   'specfreqs' - [fload array] frequency array for precomputed spectrum
%                 above.
%   'verbose'   - ['on'|'off'] display information. Default is 'off'.
%
% Outputs:
%   OUTEEG    - output dataset with updated joint probability array
%   indelec   - indices of rejected electrodes
%   specdata  - data spectrum for the selected channels
%   specfreqs - frequency array for spectrum above
%
% Author: Arnaud Delorme, CERCO, UPS/CNRS, 2008-

% Copyright (C) 2008 Arnaud Delorme, CERCO, UPS/CNRS
%
% 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

function [EEG allrmchan specdata specfreqs com] = pop_rejchanspec(EEG, varargin)

if nargin < 1
    help pop_rejchanspec;
    return;
end;
allrmchan = [];
specdata  = [];
specfreqs = [];
com       = '';
if nargin < 2
    uilist = { { 'style' 'text' 'string' 'Electrode (number(s); Ex: 2 4 5)' } ...
               { 'style' 'edit' 'string' ['1:' int2str(EEG.nbchan)] } ...
               { 'style' 'text' 'string' 'Frequency limits [min max]' } ...
               { 'style' 'edit' 'string' [ '35 ' int2str(floor(EEG.srate/2)) ] } ...
               { 'style' 'text' 'string' 'Standard dev. threshold limits [max]' } ...
               { 'style' 'edit' 'string' '5' } ...
               { 'style' 'text' 'string' 'OR absolute threshold limit [min max]' } ...
               { 'style' 'edit' 'string' '' } ...
               { 'style' 'text' 'string' 'Compute average reference first (check=on)' } ...
               { 'style' 'checkbox' 'string' '' 'value' 0 } { } ...
               { 'style' 'text' 'string' 'Plot histogram of power values (check=on)' } ...
               { 'style' 'checkbox' 'string' '' 'value' 0 } { } ...
               { 'style' 'text' 'string' 'Plot channels scrollplot (check=on)' } ...
               { 'style' 'checkbox' 'string' '' 'value' 0 } { } ...
             };

    geom = { [2 1] [2 1] [2 1] [2 1] [2 0.3 0.7] [2 0.3 0.7] [2 0.3 0.7] };
    result = inputgui( 'uilist', uilist, 'geometry', geom, 'title', 'Reject channel using spectrum -- pop_rejchanspec()', ...
        'helpcom', 'pophelp(''pop_rejchan'')');
    if isempty(result), return; end;

    options = { 'elec' eval( [ '[' result{1} ']' ] ) 'stdthresh' str2num(result{3}) 'freqlims' str2num(result{2}) };
    if ~isempty(result{4})
        options = { options{:} 'absthresh' str2num(result{4}) };
    end;
    if result{5},
         options = { options{:} 'averef', 'on' };
    end;
    if result{6},
         options = { options{:} 'plothist', 'on' };
    end;
    % Begin: Added by Romain on 22 July 2010
    if result{7},
         options = { options{:} 'plotchans', 'on' };
    end;
    % End: Added by Romain on 22 July 2010

else
    options = varargin;
end;

% decode options
% --------------
opt = finputcheck( options, { 'averef'    'string'    { 'on';'off' }       'off';
                              'plothist'  'string'    { 'on';'off' }       'off';
                              'plotchans' 'string'    { 'on';'off' }       'off';
                              'verbose'   'string'    { 'on';'off' }       'off';
                              'elec'      'integer'   []                   [1:EEG.nbchan];
                              'freqlims'  'real'   []                      [35 EEG.srate/2];
                              'specdata'  'real'   []                      [];
                              'specfreqs' 'real'   []                      [];
                              'absthresh' 'real'   []                      [];
                              'stdthresh' 'real'   []                      5 }, 'pop_rejchanspec');
if isstr(opt), error(opt); end;

% compute average referecne if necessary
if strcmpi(opt.averef, 'on')
     NEWEEG = pop_reref(EEG, [], 'exclude', setdiff([1:EEG.nbchan], opt.elec));
else NEWEEG = EEG;
end;
if isempty(opt.specdata)
    [tmpspecdata specfreqs] = pop_spectopo(NEWEEG, 1, [], 'EEG' , 'percent', 100, 'freqrange',[0 EEG.srate/2], 'plot', 'off');
    % add back 0 channels
    devStd = std(EEG.data(:,:), [], 2);
    if any(devStd == 0)
        goodchan  = find(devStd ~= 0);
        specdata  = zeros(length(opt.elec), size(tmpspecdata,2));
        specdata(goodchan,:) = tmpspecdata;
    else
        specdata = tmpspecdata;
    end;
else
    specdata  = opt.specdata;
    specfreqs = opt.specfreqs;
end;

if size(opt.stdthresh,1) == 1 && size(opt.freqlims,1) > 1
    opt.stdthresh = ones(length(opt.stdthresh), size(opt.freqlims,1))*opt.stdthresh;
end;

allrmchan = [];
for index = 1:size(opt.freqlims,1)
    % select frequencies, compute median and std then reject channels
    % ---------------------------------------------------------------
    [tmp fbeg] = min(abs(specfreqs - opt.freqlims(index,1)));
    [tmp fend] = min(abs(specfreqs - opt.freqlims(index,2)));
    selectedspec = mean(specdata(opt.elec, fbeg:fend), 2);
    if ~isempty(opt.absthresh)
        rmchan = find(selectedspec <= opt.absthresh(1) | selectedspec >= opt.absthresh(2));
    else
        m = median(selectedspec);
        s = std( selectedspec);
        nbTresh = size(opt.stdthresh);
        if length(opt.stdthresh) > 1
            rmchan = find(selectedspec <= m+s*opt.stdthresh(index,1) | selectedspec >= m+s*opt.stdthresh(index,2));
        else
            rmchan = find(selectedspec > m+s*opt.stdthresh(index));
        end
    end;

    % print out results
    % -----------------
    if isempty(rmchan)
         textout = sprintf('Range %2.1f-%2.1f Hz: no channel removed\n',  opt.freqlims(index,1), opt.freqlims(index,2));
    else textout = sprintf('Range %2.1f-%2.1f Hz: channels %s removed\n', opt.freqlims(index,1), opt.freqlims(index,2), int2str(opt.elec(rmchan')));
    end;
    fprintf(textout);
    if strcmpi(opt.verbose, 'on')
        for inde = 1:length(opt.elec)
            if ismember(inde, rmchan)
                 fprintf('Elec %s power: %1.2f *\n', EEG.chanlocs(opt.elec(inde)).labels, selectedspec(inde));
            else fprintf('Elec %s power: %1.2f\n', EEG.chanlocs(opt.elec(inde)).labels  , selectedspec(inde));
            end;
        end;
    end;
    allrmchan = [ allrmchan rmchan' ];

    % plot histogram
    % --------------
    if strcmpi(opt.plothist, 'on')
        figure; hist(selectedspec);
        hold on; yl = ylim;
        if ~isempty(opt.absthresh)
            plot([opt.absthresh(1) opt.absthresh(1)], yl, 'r');
            plot([opt.absthresh(2) opt.absthresh(2)], yl, 'r');
        else
            if length(opt.stdthresh) > 1
                threshold1 =  m+s*opt.stdthresh(index,1);
                threshold2 =  m+s*opt.stdthresh(index,2);
                plot([m m], yl, 'g');
                plot([threshold1 threshold1], yl, 'r');
                plot([threshold2 threshold2], yl, 'r');
            else
                threshold =  m+s*opt.stdthresh(index,1);
                plot([threshold threshold], yl, 'r');
            end
        end;
        title(textout);
    end;

end;
allrmchan = unique_bc(allrmchan);

com = sprintf('EEG = pop_rejchan(EEG, %s);', vararg2str(options));
if strcmpi(opt.plotchans, 'on')
    tmpcom = [ 'EEGTMP = pop_select(EEG, ''nochannel'', [' num2str(opt.elec(allrmchan)) ']);' ];
    tmpcom = [ tmpcom ...
            'LASTCOM = ' vararg2str(com) ';' ...
            '[ALLEEG EEG CURRENTSET tmpcom] = pop_newset(ALLEEG, EEGTMP, CURRENTSET);' ...
            '   if ~isempty(tmpcom),' ...
            '     EEG = eegh(LASTCOM, EEG);' ...
            '     eegh(tmpcom);' ...
            '     eeglab(''redraw'');' ...
            '  end; clear EEGTMP tmpcom;' ];

    colors = cell(1,length(opt.elec)); colors(:) = { 'k' };
    colors(allrmchan) = { 'r' }; colors = colors(end:-1:1);
    fprintf('%d electrodes labeled for rejection\n', length(find(allrmchan)));
    tmpchanlocs = EEG.chanlocs;
    if ~isempty(EEG.chanlocs), tmplocs = EEG.chanlocs(opt.elec); tmpelec = { tmpchanlocs(opt.elec).labels }';
    else                       tmplocs = []; tmpelec = mattocell([1:EEG.nbchan]');
    end;
    eegplot(EEG.data(opt.elec,:,:), 'srate', EEG.srate, 'title', 'Scroll component activities -- eegplot()', ...
        'limits', [EEG.xmin EEG.xmax]*1000, 'color', colors, 'eloc_file', tmplocs, 'command', tmpcom);
else
    EEG = pop_select(EEG, 'nochannel', opt.elec(allrmchan));
end;

if nargin < 2
    allrmchan = sprintf('EEG = pop_rejchanspec(EEG, %s);', vararg2str(options));
end;


function test_suite = test_intersectLinePolygon
%TESTINTERSECTLINEPOLYGON Test case for function intersectLinePolygon
%   output = testIntersectLinePolygon(input)
%
%   Example
%   testIntersectLinePolygon
%
%   See also
%
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2009-04-22,    using Matlab 7.7.0.471 (R2008b)
% Copyright 2009 INRA - Cepia Software Platform.

test_suite = functiontests(localfunctions);

function testSquare(testCase) %#ok<*DEFNU>
% test with a square and orthogonal lines, inside and outside

poly = [0 0;10 0;10 10;0 10];

lineH1 = [5 5 1 0];
testCase.assertEqual(2, size(intersectLinePolygon(lineH1, poly), 1));

lineH2 = [5 15 1 0];
testCase.assertEqual(0, size(intersectLinePolygon(lineH2, poly), 1));

lineV1 = [5 5 0 1];
testCase.assertEqual(2, size(intersectLinePolygon(lineV1, poly), 1));

lineV2 = [15 5 0 1];
testCase.assertEqual(0, size(intersectLinePolygon(lineV2, poly), 1));

function testClosedSquare(testCase)
% test when the polygon has same vertices at end and at bginning

poly = [0 0;10 0;10 10;0 10;0 0];

lineH1 = [5 5 1 0];
testCase.assertEqual(2, size(intersectLinePolygon(lineH1, poly), 1));

lineH2 = [5 15 1 0];
testCase.assertEqual(0, size(intersectLinePolygon(lineH2, poly), 1));

lineV1 = [5 5 0 1];
testCase.assertEqual(2, size(intersectLinePolygon(lineV1, poly), 1));

lineV2 = [15 5 0 1];
testCase.assertEqual(0, size(intersectLinePolygon(lineV2, poly), 1));

function testDiamond(testCase)

poly = [10 0;20 10;10 20;0 10];

% definition from 14/02/2022 do not intersect lower vertices
lineH0 = [0 0 3 0];
intersects = intersectLinePolygon(lineH0, poly);
testCase.assertTrue(isempty(intersects));

lineH1 = [10 10 3 0];
intersects = intersectLinePolygon(lineH1, poly);
target = [20 10];
testCase.assertTrue(ismember(target, intersects, 'rows'));
target = [0 10];
testCase.assertTrue(ismember(target, intersects, 'rows'));

[intersects, inds] = intersectLinePolygon(lineH1, poly);
testCase.assertEqual(size(intersects, 1), size(inds, 1));

lineH2 = [0 20 3 0];
intersects = intersectLinePolygon(lineH2, poly);
target = [10 20];
testCase.assertTrue(ismember(target, intersects, 'rows'));

[intersects, inds] = intersectLinePolygon(lineH2, poly);
testCase.assertEqual(size(intersects, 1), size(inds, 1));

% definition from 14/02/2022 intersects upper vertices twice
lineV0 = [0 0 0 3];
intersects = intersectLinePolygon(lineV0, poly);
testCase.assertEqual(size(intersects, 2), 2);

[intersects, inds] = intersectLinePolygon(lineV0, poly);
testCase.assertEqual(size(intersects, 1), size(inds, 1));

lineV1 = [10 10 0 3];
intersects = intersectLinePolygon(lineV1, poly);
testCase.assertEqual(size(intersects, 1), 2);

[intersects, inds] = intersectLinePolygon(lineV1, poly);
testCase.assertEqual(size(intersects, 1), size(inds, 1));

% definition from 14/02/2022 do not intersect lower vertices
lineV2 = [20 0 0 3];
intersects = intersectLinePolygon(lineV2, poly);
testCase.assertTrue(isempty(intersects));

[intersects, inds] = intersectLinePolygon(lineV2, poly);
testCase.assertEqual(size(intersects, 1), size(inds, 1));

function testMShape(testCase)
% a more complicated polygon, with 4 intersections

poly = [10 10;60 10;60 40;40 20;30 20;10 40];
line = [0 30 3 0];

[inters, inds] = intersectLinePolygon(line, poly);
expInters = [10 30;20 30;50 30;60 30];
for i = 1:4
    assertTrue(testCase, ismember(expInters(i,:), inters, 'rows'));
end
expInds = [6;5;3;2];
testCase.assertEqual(ismember(expInds, inds), true(4,1));

function testUniquePoints(testCase)
% Check that function returns unique results, even for vertex points

poly = [0 0;10 0;10 10;0 10];
line = [5 5 1 1];
intersects = intersectLinePolygon(line, poly);
testCase.assertEqual(2, size(intersects, 1), 'Wrong number of intersections');

function testGetEdgesIndices(testCase)

poly = [0 0;10 0;10 10;0 10];
line = [5 5 1 0];
[intersects, inds] = intersectLinePolygon(line, poly); %#ok<ASGLU>

testCase.assertEqual(2, length(inds));
testCase.assertEqual([4;2], inds);


function a=bin2m(m)

%   a=bin2m(m)
%   converts from 0 and 1s to mseq in terms of -1 and 1

a=m*2-1;


function [pts, confvals] = confmaps2pts(C)
%CONFMAPS2PTS Convert a set of confidence maps into a set of points.
% Usage:
%   [pts, confvals] = confmaps2pts(C)
%
% See also: pts2confmaps

numChannels = size(C,3);
pts = zeros(numChannels,2,'single');
confvals = zeros(numChannels,1,'like',C);
for i = 1:numChannels
    [confvals(i), ind] = max(vert(C(:,:,i)));
    [r,c] = ind2sub(size(C(:,:,i)),ind);
    pts(i,:) = [c r];
end

end


function [K, C] = gp_trcov(gp, x1, predcf)
%GP_TRCOV  Evaluate training covariance matrix (gp_cov + noise covariance).
%
%  Description
%    K = GP_TRCOV(GP, TX, PREDCF) takes in Gaussian process GP and
%    matrix TX that contains training input vectors to GP. Returns
%    (noiseless) covariance matrix K for latent values, which is
%    formed as a sum of the covariance matrices from covariance
%    functions in gp.cf array. Every element ij of K contains
%    covariance between inputs i and j in TX. PREDCF is an array
%    specifying the indexes of covariance functions, which are used
%    for forming the matrix. If not given, the matrix is formed
%    with all functions.
%
%    [K, C] = GP_TRCOV(GP, TX, PREDCF) returns also the (noisy)
%    covariance matrix C for observations y, which is sum of K and
%    diagonal term, for example, from Gaussian noise.
%
%  See also
%    GP_SET, GPCF_*
%
% Copyright (c) 2006-2010, 2016 Jarno Vanhatalo
% Copyright (c) 2010 Tuomas Nikoskinen

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

% no covariance functions?
if length(gp.cf)==0 || (nargin>2 && ~isempty(predcf) && predcf(1)==0)
    K=[];
    C=[];
    if nargout>1 && isfield(gp.lik.fh,'trcov')
        C=sparse(0);
        % Add Gaussian noise to the covariance
        C = C + gp.lik.fh.trcov(gp.lik, x1);
        if ~isempty(gp.jitterSigma2)
            C=C+gp.jitterSigma2;
        end
    end
    return
end

[n,m]=size(x1);
ncf = length(gp.cf);
% Evaluate the covariance without noise
K = sparse(n,n);
if isfield(gp,'deriv') && gp.deriv  % derivative observations in use
    ind_Ddim = x1(:,gp.deriv);
    ind_Ddim_derivs = ind_Ddim(ind_Ddim>0);
    uDdim = unique(ind_Ddim_derivs);
    x1 = x1(:,setdiff(1:m,gp.deriv));   % Take only the non-index columns
    if any(strcmp(gp.type,{'FIC' 'PIC' 'PIC_BLOCK' 'CS+FIC' 'VAR' 'DTC' 'SOR'}))
        error('derivative observations have not been implemented for sparse GPs')
    end
end
% check whether predcf is used
if nargin < 3 || isempty(predcf)
    predcf = 1:ncf;
end
% loop through covariance functions
for i=1:length(predcf)
    gpcf = gp.cf{predcf(i)};
    if isfield(gp.lik, 'int_magnitude') && gp.lik.int_magnitude
        if ~isfield(gp,'comp_cf') || (isfield(gp,'comp_cf') && sum(gp.comp_cf{1}==predcf(i)))
            gpcf.magnSigma2=1;
        end
    end

    % derivative observations in use
    if isfield(gp,'deriv') && gp.deriv
        if (~isfield(gpcf, 'selectedVariables') || any(ismember(gpcf.selectedVariables,uDdim)))
            % !!! Note. The check whether to calculate derivative
            % matrices for a covariance function could/should be made
            % nicer
            if size(x1,2) <2    % One dimensional input
                Kff = gpcf.fh.trcov(gpcf, x1(ind_Ddim==0,:));
                Kdf = gpcf.fh.ginput4(gpcf, x1(ind_Ddim==1,:), x1(ind_Ddim==0,:));
                D = gpcf.fh.ginput2(gpcf, x1(ind_Ddim==1,:), x1(ind_Ddim==1,:));

                Kdf=Kdf{1};
                Kfd = Kdf';
                Kdd=D{1};
                % Add all the matrices into a one K matrix
                % K = K + [Kff Kfd; Kdf Kdd];
                Ktemp = [Kff Kfd; Kdf Kdd];
            else
                Ktemp = [];
                % the block of covariance matrix
                Ktemp(ind_Ddim==0,ind_Ddim==0) = gpcf.fh.trcov(gpcf, x1(ind_Ddim==0,:));
                for u1 = 1:length(uDdim)
                    % the blocks on the left side, below Kff
                    if sum(ind_Ddim==0)>0
                        Kdf = gpcf.fh.ginput4(gpcf, x1(ind_Ddim==uDdim(u1),:), x1(ind_Ddim==0,:), uDdim(u1));
                        Ktemp(ind_Ddim==uDdim(u1),ind_Ddim==0) = Kdf{1};
                        Ktemp(ind_Ddim==0,ind_Ddim==uDdim(u1)) = Kdf{1}';
                    end
                    D = gpcf.fh.ginput2(gpcf, x1(ind_Ddim==uDdim(u1),:), x1(ind_Ddim==uDdim(u1),:), uDdim(u1));
                    Ktemp(ind_Ddim==uDdim(u1),ind_Ddim==uDdim(u1)) = D{1};

                    uDdim2 = uDdim(u1+1:end);
                    for u2=1:length(uDdim2)
                        Kdf2 = gpcf.fh.ginput3(gpcf, x1(ind_Ddim==uDdim(u1),:) ,x1(ind_Ddim==uDdim2(u2),:), uDdim(u1), uDdim2(u2));
                        Ktemp(ind_Ddim==uDdim(u1),ind_Ddim==uDdim2(u2)) = Kdf2{1};
                        Ktemp(ind_Ddim==uDdim2(u2),ind_Ddim==uDdim(u1)) = Kdf2{1}';
                    end

                end
            end
        else
            Ktemp = zeros(n,n);
            Ktemp(ind_Ddim==0,ind_Ddim==0) = gpcf.fh.trcov(gpcf, x1(ind_Ddim==0,:));
        end
        K= K+ Ktemp;
    else
        % Regular GP without derivative observations
        K = K + gpcf.fh.trcov(gpcf, x1);
    end
end

n = size(K,1);
n1 = n+1;
if ~isempty(gp.jitterSigma2)
    if issparse(K)
        K = K + sparse(1:n,1:n,gp.jitterSigma2,n,n);
    else
        K(1:n1:end)=K(1:n1:end) + gp.jitterSigma2;
    end
end
if nargout>1
    C=K;
    if isfield(gp.lik.fh,'trcov')
        C = C + gp.lik.fh.trcov(gp.lik, x1);
    end
end

end


function DCM  = spm_dcm_nvc(P)
% Specify and estimate a DCM for multimodal fMRI and M/EEG
% FORMAT [DCM] = spm_dcm_nvc(P)
%
% Input:
% -------------------------------------------------------------------------
% P{1} - SPM structure or location of SPM.mat
% P{2} - Cell array of VOI filenames (the same order as sources in EEG DCM)
% P{3} - Location of DCM for M/EEG .mat file or DCM structure
% P{4} - Model specification for neurovascular coupling (NVC) mechanisms
% P{5} - Which neuronal populations should drive haemodynamics
% P{6} - Which fMRI experimental conditions to include
% P{7} - DCM options
%
% Where:
%
% P{4} - A cell array of strings with three elements:
%
%   P{4}{1} - 'pre', 'post' or decomposed ('de') neuronal signals excite
%              NVC. Decomposed means activity is grouped into intrinsic-
%              inhibitory, intrinisic-excitatory and extrinsic-excitatory.
%   P{4}{2} - NVC has the same ('s') or different ('d') parameters for all
%              regions.
%   P{4}{3} - extrinsic and intrinsic ('ext') or only intrinsic ('int')
%              neuronal activity contributes to regional BOLD
%              (for 'post', this should be 'na').
%
%   Supported options:
%   {'pre','d','int'},{'pre','s','int'}, {'pre','d','ext'},{'pre','s','ext'},
%   {'de','d', 'int'},{'de','d','exc'},  {'de','s','int'}, {'de','s','exc'},
%   {'post','d','na'},{'post','s','na'};
%
%   Example: P{4} = {'pre', 's', 'int'} means presynaptic neuronal drive
%   (from intrinsic connections only) inputs to a model of neurovascular
%   coupling that has the same parameters for all regions.
%
% P{5} - Which neuronal populations should drive haemodynamics, by setting
%   ones or zeros in a vector ordered:
%   [superficial pyramidal, inhibitory, excitatory, deep pyramidal]
%   (default is [1 1 1 1]).
%
%   Example: [1 0 1 1] means no NVC drive from inhibitory populations.
%
% P{6} - Binary vector indicating which experimental conditions to include.
%
% P{7} - options structure for DCM for fMRI:
%    options.name                   % name for the DCM
%    options.maxit                  % maximum number of iterations
%    options.hE                     % expected precision of the noise
%    options.hC                     % variance of noise expectation
%    options.TE                     % echo time (default: 0.04)
%
% Evaluates:
% -------------------------------------------------------------------------
% DCM.M                              % Model structure
% DCM.Ep                             % Condition means (parameter structure)
% DCM.Cp                             % Conditional covariances
% DCM.Vp                             % Conditional variances
% DCM.Pp                             % Conditional probabilities
% DCM.H1                             % 1st order hemodynamic kernels
% DCM.H2                             % 2nd order hemodynamic kernels
% DCM.K1                             % 1st order neuronal kernels
% DCM.K2                             % 2nd order neuronal kernels
% DCM.R                              % residuals
% DCM.y                              % predicted data
% DCM.T                              % Threshold for Posterior inference
% DCM.Ce                             % Error variance for each region
% DCM.F                              % Free-energy bound on log evidence
% DCM.ID                             % Data ID
% DCM.AIC                            % Akaike Information criterion
% DCM.BIC                            % Bayesian Information criterion
%
% Notes on parameters:
% -------------------------------------------------------------------------
% This scheme estimates DCM.H (haemodynamic parameters) and DCM.J
% (neurovascular coupling parameters):
%
% DCM.Ep.H.transit - transit time (t0)
% DCM.Ep.H.decay   - signal decay d(ds/dt)/ds)
% DCM.Ep.H.epsilon - ratio of intra- to extra-vascular components of the
%                    gradient echo signal
%
% DCM.Ep.J - neurovascular coupling parameters. The dimension depends upon
% the requested model specification. For p populations and n regions:
%
% P{7} (DCM.model)        dim(J)   notes
% =========================================
% {'pre'  'd' 'int'}      [p n]
% {'pre'  's' 'int'}      [p 1]
% {'pre'  'd' 'ext'}      [p n]
% {'pre'  's' 'ext'}      [p 1]
% {'de'   's' 'int}       [p 2]    dim2: intrinsic inhibitory, excitatory
% {'de'   's' 'ext'}      [p 3]    dim2: intrinsic inhibitory, excitatory, extrinsic
% {'de'   'd' 'int}       [p 2 n]  dim2: intrinsic inhibitory, excitatory
% {'de'   'd' 'ext'}      [p 3 n]  dim2: intrinsic inhibitory, excitatory, extrinsic
% {'post' 's' 'na'}       [p 1]
% {'post' 'd' 'na'}       [p n]
%
%__________________________________________________________________________
% Jafarian, A., Litvak, V., Cagnan, H., Friston, K.J. and Zeidman, P., 2019.
% Neurovascular coupling: insights from multi-modal dynamic causal modelling
% of fMRI and MEG. arXiv preprint arXiv:1903.07478.
%
% Friston, K.J., Preller, K.H., Mathys, C., Cagnan, H., Heinzle, J., Razi, A.
% and Zeidman, P., 2017. Dynamic causal modelling revisited. Neuroimage.
%__________________________________________________________________________
% Copyright (C) 2019 Wellcome Trust Centre for Neuroimaging

% Amirhossein Jafarian
% $Id: spm_dcm_nvc.m 7735 2019-12-02 09:15:27Z peter $

% Prepare input
%--------------------------------------------------------------------------
SPM                 =  P{1};
xY                  =  P{2};
MEEG                =  P{3};
try model           =  P{4}; catch, model        = {'pre','d','int'}; end
try n_exclude       =  P{5}; catch, n_exclude    = ones(1,4)        ; end
try sess_exclude    =  P{6}; catch, sess_exclude = 'not defined'    ; end
try options         =  P{7}; catch, options = struct()              ; end

try options.centre;    catch, options.centre      =  1;      end
try options.hE;        catch, options.hE          =  6;      end
try options.hC;        catch, options.hC          =  1/128;  end
try options.maxit;     catch, options.maxit       =  128;    end
try options.TE;        catch, options.TE          =  0.04;   end
try name=options.name; catch, name = sprintf('DCM_%s',date); end

% Set defaults
%--------------------------------------------------------------------------
if (length(n_exclude) < 4 || isempty(n_exclude))
    n_exclude     = ones(1,4);
end
if isempty(sess_exclude)
    sess_exclude = 'not defined';
end

% Specify haemodynamic model
%--------------------------------------------------------------------------
DCM    = spm_dcm_nvc_specify(SPM,xY,MEEG,model,n_exclude,sess_exclude,options);
n      = DCM.n;
v      = DCM.v;
U.dt   = DCM.U.dt;
U.u    = [];

% Prepare fMRI signals
%--------------------------------------------------------------------------
Y       = DCM.Y;
Y.y     = spm_detrend(Y.y);
scale   = max(max(Y.y)) - min(min(Y.y));
scale   = 4/max(scale,4);
Y.y     = Y.y*scale;
Y.scale = scale;
if ~isfield(Y,'X0'),Y.X0 = ones(v,1); end
if ~size(Y.X0,2),   Y.X0 = ones(v,1); end

% Set fMRI slice time sampling and echo time
%--------------------------------------------------------------------------
try M.delays = DCM.delays; catch, M.delays = ones(n,1); end
M.TE = options.TE;

% Set priors
%--------------------------------------------------------------------------
[pE,pC,x] = spm_dcm_nvc_priors(DCM);

% Prepare neuronal drive functions
%--------------------------------------------------------------------------
input     = spm_dcm_nvc_nd(DCM);

% Set hyperpriors over precision - expectation and covariance
%--------------------------------------------------------------------------
hE       = sparse(n,1) + DCM.options.hE;
hC       = speye(n,n)  * DCM.options.hC;

% Prepare model structure
%--------------------------------------------------------------------------
M.IS = @spm_nvc_gen;
M.x  = x;
M.pE = pE;
M.pC = pC;
M.hE = hE;
M.hC = hC;
M.m  = n;
M.n  = size(spm_vec(x),1);
M.l  = n;
M.ns = v;
M.Nmax = options.maxit ;
M.TE  = DCM.TE;
M.input = input;
M.Model = model;
M.nograph = spm('CmdLine');

% Model Identification methods
% =========================================================================
[Ep,Cp,Eh,F] = spm_nlsi_GN(M,U,Y);

% Compute the prediction, residuals and error variance
%--------------------------------------------------------------------------
yhat     = feval(M.IS,Ep,M,U);
R        = Y.y - yhat;
R        = R - Y.X0*spm_inv(Y.X0'*Y.X0)*(Y.X0'*R);
Ce       = exp(-Eh);

% Compute variance that is captured by the data
%--------------------------------------------------------------------------
PSS      = sum(yhat.^2);
RSS      = sum(R.^2);
D        = 100.*PSS./(PSS + RSS);

% Compute kernels
%--------------------------------------------------------------------------
H.f      = @spm_fx_hdm;
H.g      = @spm_gx_hdm;
H.x      = M.x;
H.m      = n;
[H0,H1]  = spm_kernels(H,Ep.H,64,1/2);

% Compute posterior probabilities per parameter
%--------------------------------------------------------------------------
T        = full(spm_vec(pE));
sw       = warning('off','SPM:negativeVariance');
Pp       = spm_unvec(1 - spm_Ncdf(T,abs(spm_vec(Ep)),diag(Cp)),Ep);
Vp       = spm_unvec(full(diag(Cp)),Ep);
warning(sw);
try  M = rmfield(M,'nograph'); end

% Store parameter estimates
%--------------------------------------------------------------------------
DCM.M       = M;
DCM.Y       = Y;
DCM.U       = U;
DCM.Ce      = Ce;
DCM.Ep      = Ep;
DCM.Cp      = Cp;
DCM.Pp      = Pp;
DCM.Vp      = Vp;
DCM.H1      = H1;
DCM.D       = D;
DCM.R       = R;
DCM.y       = yhat;
DCM.t       = (1:size(yhat,1))*DCM.Y.dt;

% Compute data ID
%--------------------------------------------------------------------------
if isfield(M,'FS')
    try
        ID = spm_data_id(feval(M.FS,Y.y,M));
    catch
        ID = spm_data_id(feval(M.FS,Y.y));
    end
else
    ID     = spm_data_id(Y.y);
end

% Store evidence
%--------------------------------------------------------------------------
DCM.F      = F;
DCM.ID     = ID;

%-Save DCM
%--------------------------------------------------------------------------
DCM.name = name;
save(DCM.name, 'DCM', spm_get_defaults('mat.format'));


% Copyright (C) 1993-2014, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

%%begin
% if you have a gaming joystick connected to your computer you use the
% sticks to control the position and orientation of a coordinate frame.

T = eye(4,4);
h = trplot(T, 'axis', [-5 5 -5 5 -5 5]);

while true
    T = joy2tr(T, 'tool');
    trprint(T, 'fmt', '%.1f')
    trplot(h, T);
end


function weights = update_weight_fcn(step_size, err_sig, delayed_signal, filter_coefficients, reset_weights)
% This function updates the adaptive filter weights based on LMS algorithm

% NOTE: To instruct Embedded MATLAB to compile an external function,
% add the following compilation directive or pragma to the function code
%#eml

fm = fimath(step_size);

step_sig = fi(step_size .* err_sig, 1, 32, 20, fm);
correction_factor = fi(delayed_signal .* step_sig, 1, 32, 20, fm);
updated_weight = fi(correction_factor + filter_coefficients, 1, 16, 16, fm);

if reset_weights
    weights = fi(zeros(1,40), 1, 16, 16, fm);
else
    weights = updated_weight;
end


function output = calloptidsdp(interfacedata)

% Retrieve needed data
options = interfacedata.options;
F_struc = interfacedata.F_struc;
c       = interfacedata.c;
K       = interfacedata.K;
x0      = interfacedata.x0;
ub      = interfacedata.ub;
lb      = interfacedata.lb;

model = yalmip2opticsdp(interfacedata);
if options.showprogress;showprogress(['Calling ' interfacedata.solver.tag],options.showprogress);end

if options.savedebug
    save csdpdebug model
end

solvertime = tic;
model.ops = csdpset;
[y,fvals,exitflag,stats,X] = csdp(model.f,model.A,model.b,model.lb,model.ub,model.sdcone,model.y0,model.ops);
solvertime = toc(solvertime);

% Create dual variable in internal format
if options.saveduals
    if K.l > 0
        top = 1;
        D_struc = X{1};
    else
        top = 0;
        D_struc = [];
    end
    if K.s(1) > 0
        for j = 1:length(K.s)
            D_struc = [D_struc;X{j+top}(:)];
        end
    end
else
    D_struc = [];
end

x = y;  % Our notation do not coincide ...
switch exitflag
    case 0
       problem = 0;
    case 1
        problem = 2;
    case 2
        problem = 1;
    case {3,5,6,7,8,9,10}
        problem = 4;
    case {4,-27}
        problem = 3;
    case -50
        problem = 16;
    case 11
        problem = 7;
    otherwise
        problem = -1;
end
infostr = yalmiperror(problem,interfacedata.solver.tag);

if options.savesolveroutput
	solveroutput.y = y;
    solveroutput.fvals = fvals;
    solveroutput.exitflag = exitflag;
    solveroutput.stats = stats;
    solveroutput.X = X;
else
	solveroutput = [];
end

if options.savesolverinput
	solverinput.model = model;
else
	solverinput = [];
end

% Standard interface
output = createOutputStructure(x,D_struc,[],problem,infostr,solverinput,solveroutput,solvertime);


% DEMGPDISIMMEF2 Run experiments on Mef2 data. The raw data is pre-processed by the PUMA package.

% SHEFFIELDML

%/~
% path(path, '/local/Matlab/underDevelopment/GPSIM016');
%~/

clear; close all;
expNo = 2;
type = 'Dros';
warning('off');
saveFigures = 0;

tf = 'mef2';

%/~
if exist('./data/mef2Data.mat') == 2
%~/
load('./data/mef2Data.mat');
%/~
else

  drosLoadMef2Data;
  targetsFull = drosFindTargets(drosmef2chip);
  % targets = ([targetsFull(1:6); targetsFull(8:10)])';
  % selection = [8 34 19 26 2];
  selection = [25 34 19 37 21 40];
  targets = targetsFull(selection)';

  % targets = drosTargets(tf);
  tflabel = drosTF.labels(strcmp(tf, drosTF.names));

  genes = [tflabel, targets];

  [y, yvar, gene, times, scale, rawExp, rawVar] = gpdisimGetDrosData(drosexp, ...
                                                    genes);

  save('./data/mef2Data.mat', 'y', 'yvar', 'gene', 'times', 'scale', 'rawVar', ...
       'rawExp', 'genes', 'targets');

end
%~/
genenames = genes;

% Get the default options structure.
options = gpsimOptions;
options.includeNoise = 1;
% Fix one decay (from the fourth gene --- p21) to 0.8 hr^-1, and
% the corresponding sensitivity (see just after eqn 2 in the
% mathematical methods of Barenco et al.)
options.fix(1).index = 2;
options.fix(1).value = expTransform(1, 'xtoa');
options.fix(2).index = 6;
options.fix(2).value = expTransform(1, 'xtoa');
%options.fix(2).index = 1;
%options.fix(2).value = expTransform(.3, 'xtoa');;

% initialise the model.
model.type = 'cgpdisim';  % This new model type is a hack to run
                        % the model in a hierarchical manner.
                        % need to do this more elegantly later.
for i =1:3          %% 3 original
  model.comp{i} = gpdisimCreate(length(targets), 1, times, y{i}, yvar{i}, options);
end

% Learn the model.
model = modelOptimise(model, [], [], 1, 3000);

tfName = tf;
tfName(1) = upper(tfName(1));
fileName = ['dem' tfName type num2str(expNo)];
save(fileName);

% Plot
% figure(1); clf; plot_tf_exps(exp_struct, expse_struct);
% figure(2); clf; plot_expros(genes, exp_struct, expse_struct, genenames);
% figure(3); clf;

numGenes = model.comp{1}.numGenes;
genenames{2} = 'Rya-r44F';
genenames{4} = 'ttk';

for j = 1:length(model.comp)

  % Generate predictions of the functions.
  % to do this we need to compute the K_xf portions of the kernel
  % (simXrbfKernCompute does this for us).
  predt = [1:0.1:12 model.comp{j}.t']';
  proteinKern = kernCreate(model.comp{j}.t, 'sim');
  proteinKern.inverseWidth = model.comp{j}.kern.comp{1}.inverseWidth;
  proteinKern.decay = model.comp{j}.delta;
  proteinKern.variance = model.comp{j}.kern.comp{2}.di_variance;
  K = simXrbfKernCompute(proteinKern, model.comp{j}.kern.comp{1}, ...
                               predt, model.comp{j}.t);
  for i=2:model.comp{j}.kern.numBlocks
    blockK =  disimXsimKernCompute(model.comp{j}.kern.comp{i}, proteinKern, ...
                               model.comp{j}.t, predt);
    K = [K blockK'];
  end

  ymean = reshape(ones(length(times),1)*y{j}(1,:), length(model.comp{j}.y), ...
                                                     1);
%  ymean = mean(model.comp{j}.y);

  predF = K*model.comp{j}.invK*(model.comp{j}.y-ymean);
  varF = kernDiagCompute(proteinKern, predt) - sum(K'.* ...
                                                   (model.comp{j}.invK* ...
                                                    K'))';
%  varF = proteinKern.variance - sum(K'.*(model.comp{j}.invK*K'))';

%   % predict gene via the model
%   predF(end-length(model.comp{j}.t)+1:end) = [];
%   varF(end-length(model.comp{j}.t)+1:end) = [];
%   predt(end-length(model.comp{j}.t)+1:end) = [];
%   model.comp{j}.mapt = predt;
%   model.comp{j}.g = predF;
%   model.comp{j}.numMapPts = length(model.comp{j}.mapt);
%   model.comp{j}.step = 0.1;
%
%   model.comp{j}.times_index = [];
%   for i = 1:length(times)
%     model.comp{j}.times_index(i) = find((times(i) - model.comp{j}.mapt)==0);
%   end
%
%   model.comp{j} = gpsimMapUpdateYpred(model.comp{j});
%
%   predExprs = zeros(length(predt), model.comp{j}.numGenes+1);
%   varExprs = zeros(length(predt), model.comp{j}.numGenes+1);
%
%   predExprs(:,2:end) = model.comp{j}.ypred;
%   predFdelay = zeros(size(predF));
%   predFdelay(1) = predF(1);
%   predFdelay(2:end) = predF(1:end-1);
%   df = (predF - predFdelay)/0.1;
%
%   predDi = (df + model.comp{j}.delta*predF)/ ...
%       model.comp{j}.sigma;
%   scaleExprs = sqrt(var(predExprs))./sqrt(var(y{j}));
%   meanExprs = mean(predExprs);
%
%   model.comp{j}.sigma = model.comp{j}.sigma*scaleExprs(1);
%   model.comp{j}.B = (model.comp{j}.B-model.comp{j}.D.*meanExprs(2:end))./ ...
%       scaleExprs(2:end) + model.comp{j}.D.*mean(y{j}(2:end));
%   model.comp{j}.B = model.comp{j}.B./scaleExprs(2:end);
%   model.comp{j}.S = model.comp{j}.S./scaleExprs(2:end);
%
%   model.comp{j}.kern.comp{2}.di_variance = model.comp{j}.sigma^2;
%   for i = 2:model.comp{j}.kern.numBlocks
%     model.comp{j}.kern.comp{i}.variance = model.comp{j}.S(i-1)^2;
%   end
%
%   model.comp{j} = gpsimMapUpdateYpred(model.comp{j});
%   predExprs(:,2:end) = model.comp{j}.ypred;
%   predExprs(:,1) = (df + model.comp{j}.delta*model.comp{j}.g)/ ...
%       model.comp{j}.sigma;

  % Predicted Gene Expressions
  Kxx = multiKernCompute(model.comp{j}.kern, predt, model.comp{j}.t);
  meanPredX = reshape(ones(length(predt),1)*([0 model.comp{j}.B./ ...
                      model.comp{j}.D]), length(predt)*(numGenes+1), 1);
  predX = meanPredX + real(Kxx*model.comp{j}.invK*(model.comp{j}.y-ymean));
  varX = real(kernDiagCompute(model.comp{j}.kern, predt) - sum(Kxx'.* ...
                           (model.comp{j}.invK*Kxx'), 1)');

  % Take out predictions at data points.
  % Use them to get the scale for the other data.
  numData = length(predX)/(numGenes+1);
  predExprs = reshape(predX, numData, numGenes+1);
  meanExprs = ones(numData, 1)*mean(predExprs);
  scaleExprs = ones(numData, 1)*(sqrt(var(predExprs))./sqrt(var(y{j})));
  % Driving input can only be adjusted by the scale constant.
%  predExprs(:,1) = predExprs(:,1)./scaleExprs(:,1);
  % predictions of other genes can be generally normalised.
%   predExprs(:,2:end) =  ones(numData, 1)*mean(y{j}(:,2:end)) + ...
%       (predExprs(:,2:end) - meanExprs(:,2:end))./scaleExprs(:,2:end);
  predExprs(end-length(model.comp{j}.t)+1:end,:) = [];
  varExprs = reshape(varX, numData, numGenes+1);
  varExprs = varExprs./scaleExprs./scaleExprs;
  varExprs(end-length(model.comp{j}.t)+1:end,:) = [];
  predF(end-length(model.comp{j}.t)+1:end) = [];
  varF(end-length(model.comp{j}.t)+1:end) = [];
  predt(end-length(model.comp{j}.t)+1:end) = [];

  yscale = ones(length(times), 1)*sqrt(var(y{j}));
  ymean = ones(length(times),1)*mean(y{j});
  ynormal = ymean + (y{j}-ymean)./yscale;
  yvarNormal = yvar{j}./yscale./yscale;

  scalePred = sqrt(var(predExprs));

  figure;
%  subplot(length(model.comp), 1, j);
  lin = plot(predt, predF, '-');
  hold on,
  bh = plot(predt, predF + 2*sqrt(varF), '--');
  bh = [bh plot(predt, predF - 2*sqrt(varF), '--')];
  hold off
%  ylabel(['Replica' num2str(j)]);
  title('Inferred Mef2 Protein', 'fontsize', 20);
  set(bh, 'lineWidth', 2);
  set(lin, 'lineWidth', 3);
  %set(lin, 'markersize', 20);
  set(gca, 'fontname', 'arial', 'fontsize', 24, 'xlim', [min(model.comp{j}.t) ...
                                                    max(model.comp{j} ...
                                                    .t)]);
  set(gca, 'ylim', [-0.1 0.4]);
  if saveFigures==1
    saveFileName = [fileName 'TF_profile_Rep' num2str(j)];
    print('-dpng', ['./results/' saveFileName]);
    pos = get(gcf, 'paperposition');
    origpos = pos;
    pos(3) = pos(3);
    pos(4) = pos(4);
    set(gcf, 'paperposition', pos);
    lineWidth = get(gca, 'lineWidth');
    set(gca, 'lineWidth', lineWidth*2);
    print('-deps', ['./results/' saveFileName]);
    set(gca, 'lineWidth', lineWidth);
    set(gcf, 'paperposition', origpos);
  end

  for index = 1:numGenes+1
    figure;
    lin = plot(predt, predExprs(:,index), '-');
    hold on,
    bh = plot(predt, predExprs(:,index)+2*real(sqrt(varExprs(:,index))), '--');
    bh = [bh plot(predt, predExprs(:,index)-2*real(sqrt(varExprs(:,index))), '--')];
    lin = [lin plot(times, y{j}(:,index), 'rx')];
    lin1 = errorbar(times, y{j}(:,index), 2*sqrt(yvar{j}(:,index)), ...
                    'rx');
    if index == 1
      titleText = ['Driving Input mRNA'];
%      lin = [lin plot(predt, predDi, 'm-')];
    else
      titleText = ['Gene ' genenames{index} ' mRNA'];
    end
    title(titleText, 'fontsize', 20);
    set(bh, 'lineWidth', 3);
    set(lin, 'lineWidth', 4);
    set(lin, 'markersize', 20);
    set(lin1, 'lineWidth', 2);
    set(gca, 'fontname', 'arial', 'fontsize', 24, 'xlim', [min(predt) ...
                        max(predt)]);

    if saveFigures
      saveFileName = [fileName '_ExprsProfile_Rep' num2str(j) '_Gene' num2str(index)];
      print('-deps', ['./results/' saveFileName]);
      pos = get(gcf, 'paperposition');
      origpos = pos;
      pos(3) = pos(3);
      pos(4) = pos(4);
      set(gcf, 'paperposition', pos);
      lineWidth = get(gca, 'lineWidth');
      set(gca, 'lineWidth', lineWidth*2);
      print('-dpng', ['./results/' saveFileName]);
      set(gca, 'lineWidth', lineWidth);
      set(gcf, 'paperposition', origpos);
    end
  end

end


function [g1, g2] = simwhiteXsimwhiteKernGradient(simKern1, simKern2, t1, varargin)

% SIMWHITEXSIMWHITEKERNGRADIENT Compute a cross gradient between two
% SIM-WHITE kernels.
% FORMAT
% DESC computes cross gradient of parameters of a cross kernel
% between two SIM-WHITE kernels for the multiple output kernel.
% ARG simKern1 : the kernel structure associated with the first SIM-WHITE
% kernel.
% ARG simKern2 : the kernel structure associated with the second SIM-WHITE
% kernel.
% ARG t1 : inputs for which kernel is to be computed.
% ARG covGrad : gradient of the objective function with respect to
% the elements of the cross kernel matrix.
% RETURN g1 : gradient of the parameters of the first kernel, for
% ordering see simwhiteKernExtractParam.
% RETURN g2 : gradient of the parameters of the second kernel, for
% ordering see simwhiteKernExtractParam.
%
% FORMAT
% DESC computes cross kernel terms between two SIM-WHITE kernels for
% the multiple output kernel.
% ARG simKern1 : the kernel structure associated with the first SIM-WHITE
% kernel.
% ARG simKern2 : the kernel structure associated with the second SIM-WHITE
% kernel.
% ARG t1 : row inputs for which kernel is to be computed.
% ARG t2 : column inputs for which kernel is to be computed.
% ARG covGrad : gradient of the objective function with respect to
% the elements of the cross kernel matrix.
% RETURN g1 : gradient of the parameters of the first kernel, for
% ordering see simwhiteKernExtractParam.
% RETURN g2 : gradient of the parameters of the second kernel, for
% ordering see simwhiteKernExtractParam.
%
% SEEALSO : multiKernParamInit, multiKernCompute, simwhiteKernParamInit,
% simwhiteKernExtractParam
%
% COPYRIGHT : David Luengo, 2009

% KERN

if nargin < 5
    t2 = t1;
else
    t2 = varargin{1};
end
covGrad = varargin{end};

if size(t1, 2) > 1 | size(t2, 2) > 1
  error('Input can only have one column');
end
if simKern1.variance ~= simKern2.variance
  error('Kernels cannot be cross combined if they have different variances.')
end

% Parameters of the kernels required in the computation
variance = simKern1.variance;
sensitivity1 = simKern1.sensitivity;
sensitivity2 = simKern2.sensitivity;
decay1 = simKern1.decay;
decay2 = simKern2.decay;

isStationary = (simKern1.isStationary == true) & (simKern2.isStationary == true);

% Auxiliary constants, vectors and matrices
g1 = zeros(1,3);
g2 = zeros(1,3);

T1 = repmat(t1, 1, size(t2, 1));
T2 = repmat(t2.', size(t1, 1), 1);
ind1 = (T1 < T2);
ind2 = ~ind1;
Dv = decay2 .* ind1 + decay1 .* ind2;
K1 = exp(-Dv.*abs(T1-T2));
if (isStationary == false)
    K2 = exp(-(decay1 * T1 + decay2 * T2));
end

if (isStationary == false)
    % Gradient w.r.t. the decays (D_p and D_q)
    g1(1) = (variance * sensitivity1 * sensitivity2 / (decay1 + decay2)) ...
        * sum(sum((-(K1 - K2)/(decay1 + decay2) ...
            - abs(T1 - T2) .* K1 .* ind2 + T1 .* K2) .* covGrad));
    g2(1) = (variance * sensitivity1 * sensitivity2 / (decay1 + decay2)) ...
        * sum(sum((-(K1 - K2)/(decay1 + decay2) ...
            - abs(T1 - T2) .* K1 .* ind1 + T2 .* K2) .* covGrad));
    % Gradient w.r.t. the variance of the driving process
    g1(2) = (sensitivity1 * sensitivity2 / (decay1 + decay2)) ...
        * sum(sum((K1-K2) .* covGrad));
    g2(2) = 0; % Otherwise it is counted twice
    % Gradient w.r.t. the sensitivities
    g1(3) = (variance * sensitivity2 / (decay1 + decay2)) ...
        * sum(sum((K1-K2) .* covGrad));
    g2(3) = (variance * sensitivity1 / (decay1 + decay2)) ...
        * sum(sum((K1-K2) .* covGrad));
else
    % Gradient w.r.t. the decays (D_p and D_q)
    g1(1) = - (variance * sensitivity1 * sensitivity2 / (decay1 + decay2)) ...
        * sum(sum((K1/(decay1 + decay2) + abs(T1 - T2) .* K1 .* ind2) .* covGrad));
    g2(1) = - (variance * sensitivity1 * sensitivity2 / (decay1 + decay2)) ...
        * sum(sum((K1/(decay1 + decay2) + abs(T1 - T2) .* K1 .* ind1) .* covGrad));
    % Gradient w.r.t. the variance of the driving process
    g1(2) = (sensitivity1 * sensitivity2 / (decay1 + decay2)) ...
        * sum(sum(K1 .* covGrad));
    g2(2) = 0; % Otherwise it is counted twice
    % Gradient w.r.t. the sensitivities
    g1(3) = (variance * sensitivity2 / (decay1 + decay2)) ...
        * sum(sum(K1 .* covGrad));
    g2(3) = (variance * sensitivity1 / (decay1 + decay2)) ...
        * sum(sum(K1 .* covGrad));
end


function doTheCalcThingMonte(obj)
		%everything for the calculation itself goes in here
		import mapseis.projector.*;
		import mapseis.calc.declustering.*;

		%Calculation with an added MonteCarlo simulation
		%(the things done by Thomas Van Stiphout)
		%LATER, first to the normal version

		%What the monte-carlo reasenberg does is simple

		%get parameter into variables
		ShortCatalog = getShortCatalog(obj.Datastore,obj.SendedEvents);
		taumin=obj.CalcParameter.Tau_min;
		taumax=obj.CalcParameter.Tau_max;
		xk=obj.CalcParameter.XMagFactor;
		xmeff=obj.CalcParameter.XMagEff;
		P=obj.CalcParameter.ProbObs;
		rfact=obj.CalcParameter.RadiusFactor;
		err=obj.CalcParameter.EpiError;
		derr=obj.CalcParameter.DepthError;

		%run declustering
		disp('please wait....');

		tic;
		[clusterID,EventType,AlgoInfo] = ReasenbergDecluster(taumin,taumax,xk,xmeff,P,rfact,err,derr,ShortCat);
		obj.CalcTime=toc;
		disp('finished!');

		%store result
		obj.CalcRes.clusterID=clusterID;
		obj.EventType=EventType;
		obj.AlgoInfo=AlgoInfo;

		%write to datastore
		obj.Datastore.setDeclusterData(EventType,clusterID,obj.SendedEvents,[]);
		obj.Datastore.DeclusterMetaData=AlgoInfo;

		%correct for old datastore version, it makes sense to do this here, because it is needed only by the declustering
		NumberedUserData=getNumberedFields(obj.Datastore);
		setNumberedFields(obj.Datastore,union(NumberedUserData,{'Month','Day','Hour','Minute','Second','MilliSecond' ,'DecYear'}));

end


function  dtiFindFGOI

%This functions takes [fgA, A, embbasis] (this is atlas), a set of nvecs in that
%atlas space that define an fgOI, and a new fibergroup fgS. The new fibergroup
%get embedded into the space, and those fibers that fall within the
%boundaries of the fgOI, are highlighted.

nvec=size(fgOI, 2);

%Compute embedding vectors for S;
E=dtiNewDataOntoEmbeddingVectors(A, S, embbasis, nvec);


function bow_map = sift(I, siftParam, vocab)
	paths = getPaths();

	% Sift Param
	% siftParam = struct('ds_sampling', 1, 'scales', 1.2, 'descriptor', 'opponentsift');

	%% Compute the SIFT Features
	% Generate three filenames
	ext = {'png', 'txt'};
	r = randsample(100000, length(ext), false);
	pid = getPID();
	for i = 1:length(ext),
		%f{i} = fullfile('/tmp', sprintf('sgupta-sift-%07d-%06d.%s', pid, r(i)), ext{i});
		f{i} = fullfile('/dev/shm', sprintf('sgupta-sift-%07d-%06d.%s', pid, r(i), ext{i}));
	end

	imwrite(im2uint8(I), f{1}, 'png');
	str = sprintf('%s %s --detector densesampling --ds_spacing %d --ds_scales %0.4f --descriptor %s --output %s\n', paths.siftLib, f{1}, siftParam.ds_sampling, siftParam.scales, siftParam.descriptor, f{2});
	system(str);

	info = imfinfo(f{1});
	feats = feat_txt2mat(f{2}, siftParam.scales);

	% Remove the temporary files.
	for i = 1:length(f)
		system(sprintf('rm %s &', f{i}));
	end

	%% Compute the SIFT bow here
	data_img = feats.data';
	feats.pos = double(feats.pos);
	pos = sub2ind([info.Height, info.Width], feats.pos(:,1), feats.pos(:,2));
	cnt_id = 1:numel(pos);
	im_pos = zeros([info.Height info.Width]);
	im_pos(pos) = cnt_id;
	clear feats;

	[drop, binsa] = min(vl_alldist(vocab, single(data_img)), [], 1) ;

	ind = (im_pos > 0);

	bow_map = zeros(size(im_pos));
	bow_map(ind) = binsa(im_pos(ind));
end


function bgdiff = bgtdiff(ll,llex)
    %bgtdiff.m                                         A.Allmann
    %calculates the time difference between jth and biggest event
    %in an aftershock sequence
    %works with eqtime from function clustime.m
    %gives the indices ac of the eqs not already related to cluster k1
    %Last modification 6/95
    global  eqtime k1 bg mbg

    z=ll(llex);                               %indices of the eqs to examine
    %mbg(k1)=bg(k1);                   %bgdiff not calculated from the last
    %  biggest eq but the first biggest eq
    bgdiff=zeros(length(z),1);
    if bg(k1)~=mbg(k1)                          %if more eqs with biggest magnitude
        tm1 = max(find(z<=mbg(k1)));                 %position of mbg

        if size(tm1)~=0                          %if eqs before mbg(k1)
            bgdiff(1:tm1,1)=eqtime(z(1:tm1),1)-eqtime(bg(k1));

            if tm1~=length(z)                    %if mbg(k1) is not the last eq to examine
                bgdiff((tm1+1):length(z),1)=eqtime(z((tm1+1):length(z)),1)-eqtime(mbg(k1));
            end

        else                          %bg and mbg are smaller than all indices in z
            bgdiff=eqtime(z)-eqtime(mbg(k1));
        end

    else                              %only one eq with biggest magnitude
        bgdiff=eqtime(z)-eqtime(bg(k1));

    end


 function st = nufft_table_init(om, Nd, Jd, Kd, n_shift, Ld, varargin)
%function st = nufft_table_init(om, Nd, Jd, Kd, n_shift, Ld, ...)
%|
%| Initialize structure for d-dimension NUFFT using table-based interpolator,
%| This should be called only by nufft_init with its 'table' argument!
%| (So this m-file belongs in the private directory.)
%|
%| in
%|	om, Nd, Jd, Kd, n_shift		see nufft_init.m
%|	Ld [d]				table over-sampling factor(s)
%|
%| optional arguments (same as nufft_init.m, to specify interp type)
%| out
%|	st.interp_table		function: X = st.interp_table(st, Xk);
%|	st.interp_table_adj	function: Xk = st.interp_table_adj(st, Xk);
%|	st.phase_shift		phase shift due to n_shift
%|	st.*			same as in nufft_init.m
%|
%| Copyright 2004-3-30, Jeff Fessler and Yingying Zhang, University of Michigan

if nargin < 5, help(mfilename), error args, end

% dimensionality of input space (usually 2 or 3)
dd = length(Nd);
if dd > 1 && length(Ld) == 1
	Ld = Ld * ones(1,dd); % allow scalar L to be used for all dimensions
end
if dd ~= length(Jd) || dd ~= length(Kd) || dd ~= length(Ld)
	printm('dd:'), disp(dd)
	printm('Jd:'), disp(Jd)
	printm('Kd:'), disp(Kd)
	printm('Ld:'), disp(Ld)
	error 'inconsistent dim'
end
if dd ~= size(om,2), error('omega needs %d columns', dd), end

% D-dim NUFFT structure with desired scaling factors, using fake omega=0
st = nufft_init(zeros(size(Nd)), Nd, Jd, Kd, 0*n_shift, varargin{:});
st.p = [];
st.om = om;
st.Ld = Ld;
st.M = size(om,1);
st.n_shift = n_shift; % trick: store it in structure for history

% phase shift associated with indexing n_shift
% trick: because we put this phase shift here, we use "0" for n_shift below
% when building the tables.  in fact, n_shift definitely cannot be in table.
if any(n_shift ~= 0)
	st.phase_shift = exp(1i * (om * n_shift(:))); % [M 1]
end

% 1D tables for each dimension
for id = 1:dd
	J = Jd(id);
	L = Ld(id);
	K = Kd(id);

	% This is a slow and inefficient way to get the table
	% since it builds a huge sparse matrix but only uses 1 column!
	t0 = [-J*L/2:J*L/2]' / L; % [J*L+1]
	if 0
		om0 = t0 * 2*pi/K; % gam(id)
		s1 = nufft_init(om0, Nd(id), J, K, ...
			0*n_shift(id), varargin{:}); % user's interpolator
		h0 = full(s1.p(:,1));
	end

	% This efficient way uses only "J" columns of sparse matrix!
	% The trick to this is to use fake small values for N and K,
	% which works for interpolators that depend only on the ratio K/N.
	ktype = varargin{1};
	if 0 && (streq(ktype, 'minmax:kb') || streq(ktype, 'kaiser'))

		if streq(ktype, 'minmax:kb')
			args = {'minmax:user', {st.alpha{id}}, {st.beta{id}}};
		elseif streq(ktype, 'kaiser')
			args = {'kaiser'};
			if length(varargin) > 1, warning 'bug?', end
		else
			error 'bug'
		end

		Nfake = J;
		Kfake = Nfake * K/Nd(id);
		t1 = J/2-1 + [0:(L-1)]' / L;	% [L]
		om1 = t1 * 2*pi/Kfake;		% "gam"
		s1 = nufft_init(om1, Nfake, J, Kfake, 0, args{:});

		h = [];
		for jj=J:-1:1
			h = [h; full(s1.p(:,jj))]; % stack up pieces
		end
		h = [h; 0]; % finally J*L+1 long.
		h = h .* exp(1i * pi * t0 * (1/K - 1/Kfake)); % fix phase

		if 0	% testing
			clf, subplot(211)
			plot(t0, real(h0), 'c-', t0, real(h), 'y.')
			plot(t0, real(h0-h), 'y.')
			subplot(212)
			plot(t0, imag(h0), 'c-', t0, imag(h), 'y.')
			plot(t0, imag(h0-h), 'y.')
			printf('diff=%g', max_percent_diff(h0, h))
			keyboard
		end
		st.h{id} = double(h); % table mex files want double

	% This way is "J times faster" than the slow way, but still not ideal.
	% It works for any user-specified interpolator.
	else
		t1 = J/2-1 + [0:(L-1)]' / L; % [L]
		om1 = t1 * 2*pi/K; % gam(id)

		% trick: handle {'kaiser', [kb_alf], [kb_m]} in multidim case
		if streq(varargin{1}, 'kaiser') && length(varargin) == 3
			kb_alf = varargin{2};
			kb_m = varargin{3};
			if any(kb_alf ~= kb_alf(1)) || any(kb_m ~= kb_m(1))
				error 'table based needs identical interpolator for each dimension'
			end
			varargin{2} = kb_alf(1);
			varargin{3} = kb_m(1);
		end

		s1 = nufft_init(om1, Nd(id), J, K, 0*n_shift(id), varargin{:});

		h = [];
		for jj=J:-1:1
			h = [h; full(s1.p(:,jj))];
		end
		h = [h; 0];

		st.h{id} = double(h); % table mex files want double
		if 0	% testing
			clf, subplot(211)
			plot(t0, real(h0), 'c-', t0, real(h), 'y.')
			subplot(212)
			plot(t0, imag(h0), 'c-', t0, imag(h), 'y.')
			printf('diff=%g', max_percent_diff(h0, h))
			keyboard
		end
	end

	if isreal(st.h{id})
		if J == 1
			st.h{id} = complex(st.h{id});
		else
			whos
			warning 'real kernel?'
			keyboard
		end
	end

end

% interface routines
% st.interp_table = inline('nufft_table_interp(st, Xk)', 'st', 'Xk');
st.interp_table		= @nufft_table_interp;
st.interp_table_adj	= @nufft_table_adj;


%%*****************************************************************
%% HKMcorr: corrector step for the HKM direction.
%%
%% SDPT3: version 3.1
%% Copyright (c) 1997 by
%% K.C. Toh, M.J. Todd, R.H. Tutuncu
%% Last Modified: 16 Sep 2004
%%*****************************************************************

  function [dX,dy,dZ,resnrm,EinvRc] = HKMcorr(blk,At,par,rp,Rd,sigmu,hRd,...
            dX,dZ,coeff,L,X,Z);

    global matfct_options solve_ok

    printlevel = par.printlevel;
%%
    [rhs,EinvRc] = HKMrhsfun(blk,At,par,X,Z,rp,Rd,sigmu,hRd,dX,dZ);
    m = length(rp); ncolU = size(coeff.mat12,2);
    rhs = [rhs; zeros(m+ncolU-length(rhs),1)];
%%
    solve_ok = 1; resnrm = norm(rhs);
    if strcmp(matfct_options,'chol') | strcmp(matfct_options,'spchol') ...
       | strcmp(matfct_options,'ldl') | strcmp(matfct_options,'spldl')
       [xx,resnrm,solve_ok] = symqmr(coeff,rhs,L,[],[],printlevel);
       if (solve_ok<=0) & (printlevel)
          fprintf('\n  warning: symqmr fails: %3.1f.',solve_ok);
       end
    else
       [xx,resnrm,solve_ok] = mybicgstab(coeff,rhs,L,[],[],printlevel);
       if (solve_ok<=0) & (printlevel)
          fprintf('\n  warning: bicgstab fails: %3.1f.',solve_ok);
       end
    end
    if (printlevel>=3); fprintf('%2.0d ',length(resnrm)-1); end
%%
    [dX,dy,dZ] = HKMdirfun(blk,At,par,Rd,EinvRc,X,xx,m);
%%*****************************************************************


function [calories] = getDietEnergy(diet)
%Given a nx2 cell array of diet components and serving sizes, computes how
%many Calories are in the diet. Does not consider calories of metabolites
load('fdTable.mat');
calIndex=find(contains(fdTable.Var1,'Energy_in_Kcal'));
for i=1:length(diet(:,1))
    try
        cals(i)=table2array(fdTable(calIndex,find(strcmp(fdTable.Properties.VariableNames,diet(i,1)))));
    catch
        cals(i)=0;
    end
end
calories=cals*cell2mat(diet(:,2));
end


classdef linop
%linop A class for linear operators

% written by M. Storath
% $Date: 2015-10-15 15:07:43 +0200 (Do, 15. Okt 2015) $	$Revision: 132 $

    properties
        % function handle for evaluation A * x
        eval;
        % function handle for evaluation A' * x
        ctrans;
        % A'A
        normalOp;
        % true if A'A positive definite
        posdef;
        % true if A'A positive definite
        lseSolver;
    end

    methods
        % constructor
        function A = linop(eval, ctrans, varargin)
            % if it is a matrix
            if ~isa(eval, 'function_handle')
                A.eval = @(x) eval * x;
                A.ctrans = @(x) eval' * x;
                M = eval' * eval;
                A.normalOp = @(x) M * x;
            else
                A.eval = eval;
                A.ctrans = ctrans;
                A.normalOp = @(x) A.ctrans(A.eval(x));
            end
            ip = inputParser;
            addParamValue(ip, 'posdef', false);
            addParamValue(ip, 'lseSolver', []);
            parse(ip, varargin{:});
            par = ip.Results;
            A.posdef = par.posdef;
            A.lseSolver = par.lseSolver;
        end

        % ctranspose (')
        function C = ctranspose(A)
            C =  linop(A.ctrans, A.eval);
        end

        % mtimes (*)
        function C = mtimes( A, B )
            if isa(B, 'linop')
                C = linop( @(x) A.eval(B.eval(x)), @(x) B.ctrans(A.ctrans(x)));
            else
                C = A.eval(B);
            end
        end

        % size
        function s = size(A)
            %warning('Size is deprecated for class linop');
            s = [1 1];
        end

    end
end


clear all; close all; clc

%% folder setup
outputDir = GetOutputDataDir;

%% init

hfig = figure;
InitializeAppData(hfig);
ResetDisplayParams(hfig);

%% run fish
range_fish = GetFishRange;%[1:3,5:18];%

M_stim = {'5','P','O','L','D','Y'};
M_stimname = {'phT-DF','phT','OMR','Loom','DF','Dot'};

M_pair_range = {[2,1],[2,1],[12,11],[14,15],[0,3],[13,0]}; % [3,2] for PT L vs R; [9,8] for OMR L vs R
%     leftstates_full = [2,12,14,22];
%     rightstates_full = [1,11,15,21];
%     leftstates_full = [2,12,14,22];
%     rightstates_full = [1,11,15,21];
%
% if fishset == 1,
%     States = [0,1,2,3];
%     singleNames = {'black','phototaxis R','phototaxis L','white'};%,...
% %         'L on','R on','L off','R off'};
% % elseif fishset == 2,
% %     States = [0,1,2,3,4,10,11,12];
% %     names = {'black','phototaxis left','phototaxis right','white','grey',...
% %         'OMR forward','OMR left','OMR right',...
% %         'left PT&OMR','right PT&OMR'};
% else%if fishset == 2,
%        States = [0,1,2,3,4,9,10,11,12,13,14,15,21,22,23];
%     singleNames = {'black','phototaxis R','phototaxis L','white','grey',...% 0-4
%         'OMR backward', 'OMR forward','OMR right','OMR left',... % 9-12
%         'Dot','looming L','looming R',... % 13-15
%         'red/blue R','red/blue L','red/red',...
%         };
% end
nStim = length(M_stim);
% for fictive channels (5 channels)
P_pval5= nan(18,5,nStim);
% for motor-seeds (L/R)
P_pval2= nan(18,2,nStim);

ClusterIDs = [1,1];%GetClusterIDs('all');
% M_stimname = {'OMR'};
for i_stim = 1:length(M_stim)
    [M_stimrange,stimrange] = GetStimRange(M_stim{i_stim});

    for i_fish = range_fish
        stimrange = M_stimrange{i_fish};

        tteststimrange = M_pair_range{i_stim};

        if ~isempty(stimrange)
            setappdata(hfig,'isMotorseed',0);
            LoadSingleFishDefault(i_fish,hfig,ClusterIDs,stimrange,0);
            stim = getappdata(hfig,'stim');
            behavior = getappdata(hfig,'behavior');

            %%
            samples = cell(1,length(tteststimrange));
            for i = 1:length(tteststimrange),
                IX = find(stim==tteststimrange(i));
                samples{i} = behavior(:,IX)';
            end

            [~, p] = ttest2(samples{1},samples{2});

            P_pval5(i_fish,:,i_stim) = p;

            %%
            setappdata(hfig,'isMotorseed',1);
            [~,~,behavior] = UpdateTimeIndex(hfig);

            samples = cell(1,length(tteststimrange));
            for i = 1:length(tteststimrange),
                IX = find(stim==tteststimrange(i));
                samples{i} = behavior(:,IX)';
            end

            [~, p] = ttest2(samples{1},samples{2});

            P_pval2(i_fish,:,i_stim) = p;

        end
    end
end

%%
figure('Position',[550,100,800,120]);
for i_stim = 2:6
    subplot(1,5,i_stim-1); hold on;
    y = P_pval2(:,:,i_stim);
    h = histogram(y(:),[0:0.05:1]);
    h.FaceColor = [0.5,0.5,0.5];
    set(gca,'xscale','log');
%     xlim([0,1]);
    ylim([0,30])
    plot([0.05,0.05],[0,30],'r--')
    title(M_stimname{i_stim})
    length(find(y(:)>1))
end


function save_yuv(data, new_file, height, width, h_factor, w_factor, SDR_HDR)
%%% Save YUV frame of SDR or HDR videos %%%
% 'SDR_HDR' flag should be specified with either 'SDR' or 'HDR'

% get size of data
datasize = size(data);
datasizelength = length(datasize);

% open file
fid = fopen(new_file,'a');

% subsampling of U and V
if datasizelength == 2 || h_factor == 0
    %4:0:0
    y(1:height, 1:width) = data(:, :, 1);
elseif datasizelength == 3
    y(1:height, 1:width) = double(data(:, :, 1));
    u(1:height, 1:width) = double(data(:, :, 2));
    v(1:height, 1:width) = double(data(:, :, 3));
    if w_factor == 1
        %4:1:1
        u2 = u;
        v2 = v;
    elseif h_factor == 0.5
        %4:2:0
        u2(1:height/2, 1:width/2) = u(1:2:end, 1:2:end)+u(2:2:end, 1:2:end)+u(1:2:end, 2:2:end)+u(2:2:end, 2:2:end);
        u2                         = u2/4;
        v2(1:height/2, 1:width/2) = v(1:2:end, 1:2:end)+v(2:2:end, 1:2:end)+v(1:2:end, 2:2:end)+v(2:2:end, 2:2:end);
        v2                         = v2/4;
    elseif w_factor == 0.25
        %4:1:1
        u2(1:height, 1:width/4) = u(:, 1:4:end)+u(:, 2:4:end)+u(:, 3:4:end)+u(:, 4:4:end);
        u2                       = u2/4;
        v2(1:height, 1:width/4) = v(:, 1:4:end)+v(:, 2:4:end)+v(:, 3:4:end)+v(:, 4:4:end);
        v2                       = v2/4;
    elseif w_factor == 0.5 && h_factor == 1
        %4:2:2
        u2(1:height, 1:width/2) = u(:, 1:2:end)+u(:, 2:2:end);
        u2                       = u2/2;
        v2(1:height, 1:width/2) = v(:, 1:2:end)+v(:, 2:2:end);
        v2                       = v2/2;
    end
end

if strcmp(SDR_HDR,'HDR')
    fwrite(fid,uint16(y'),'uint16'); % write Y-Data

    if h_factor ~= 0
        % write U- and V-Data if not 4:0:0 format
        fwrite(fid, uint16(u2'), 'uint16');
        fwrite(fid, uint16(v2'), 'uint16');
    end
elseif strcmp(SDR_HDR, 'SDR')
        fwrite(fid, uint8(y'), 'uchar'); % write Y-Data

    if h_factor ~= 0
        % write U- and V-Data if not 4:0:0 format
        fwrite(fid, uint8(u2'), 'uchar');
        fwrite(fid, uint8(v2'), 'uchar');
    end
end

fclose(fid);


function [dat,algo] =  training(algo,dat)

 disp(['training ' get_name(algo) '.... '])
 [algo.input algo.target]= get_xy(dat);
 [n D] = size(algo.input);

 algo.H = zeros(D+2,1);
 [algo.H, fX] = minimize(algo.H, 'gpS00', algo.length, {algo.input, algo.target});

 dat=set_x(dat,get_y(dat));


function [m,varargout] = max(varargin)

funname = 'max';

narginchk(1, 2)
if nargin == 1;
    nargoutchk(0, 2)
    [m,varargout{1}] = max(varargin{1}.Z(:));

elseif nargin == 2;
    nargoutchk(0, 1)

    % which one of the two input arguments is a GRIDobj
    isGRIDobj = cellfun(@(x) isa(x,'GRIDobj'),varargin);

    % if both
    if all(isGRIDobj)
        validatealignment(varargin{1},varargin{2});
        M = builtin(funname,varargin{1}.Z,varargin{2}.Z);
    else
        varargin = varargin(~isGRIDobj + 1);
        if ~isscalar(varargin{2});
            validatealignment(varargin{1},varargin{2});
        end
        M = builtin(funname,varargin{1}.Z,varargin{2});
    end

    m = varargin{1};
    m.name = funname;
    m.Z = M;
    m.zunit = '';
end


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

indexS = planC{end};

%Calculate width of bins, use to find middle of each bin.
binWidthsV = diff(planC{indexS.DVH}(DVHNum).DVHMatrix(:,1));
lastBinWidth = binWidthsV(end);
binWidthsV(end+1,1) = lastBinWidth;

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


% std_topo() - uses topoplot() to get the interpolated Cartesian grid of the
%               specified component topo maps. The topo map grids are saved
%               into a (.icatopo) file and a pointer to the file is stored
%               in the EEG structure. If such a file already exists,
%               loads the information from it.
%
%               Returns the topo map grids of all the requested components. Also
%               returns the EEG sub-structure etc (i.e EEG.etc), which is modified
%               with a pointer to the float file and some information about the file.
% Usage:
%               >> X = std_topo(EEG, components, option);
%
%                  % Returns the ICA topo map grid for a dataset.
%                  % Updates the EEG structure in the Matlab environment and re-saves
% Inputs:
%   EEG        - an EEG dataset structure.
%   components - [numeric vector] components in the EEG structure to compute topo maps
%                      {default|[] -> all}
%   option     - ['gradient'|'laplacian'|'none'] compute gradient or laplacian of
%                the scale topography. This does not acffect the saved file which is
%                always 'none' {default is 'none' = the interpolated topo map}
% Outputs:
%   X          - the topo map grid of the requested ICA components, each grid is
%                     one ROW of X.
%
% File output: [dataset_name].icatopo
%
% Authors:  Hilit Serby, Arnaud Delorme, SCCN, INC, UCSD, January, 2005
%
% See also  topoplot(), std_erp(), std_ersp(), std_spec(), std_preclust()

% Copyright (C) Hilit Serby, SCCN, INC, UCSD, October 11, 2004, hilit@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

function [X] = std_topo(EEG, comps, option, varargin)

if nargin < 1
    help std_topo;
    return;
end;
if isfield(EEG,'icaweights')
   numc = size(EEG.icaweights,1);
else
   error('EEG.icaweights not found');
end
if nargin < 2
   comps = 1:numc;
elseif isempty(comps)
   comps = 1:numc;
end

if nargin < 3
    option = 'none';
end;

g = finputcheck( varargin, { 'recompute'   'string'   { 'on' 'off' }   'off' }, 'std_topo');
if isstr(g), error(g); end;

% figure; toporeplot(grid,'style', 'both','plotrad', 0.5, 'intrad', 0.5, 'xsurface' ,Xi, 'ysurface',Yi );

% Topo information found in dataset
% ---------------------------------
if exist(fullfile(EEG.filepath, [ EEG.filename(1:end-3) 'icatopo' ])) & strcmpi(g.recompute, 'off')
    for k = 1:length(comps)
        tmp = std_readtopo( EEG, 1, comps(k));
        if strcmpi(option, 'gradient')
            [tmpx, tmpy]  = gradient(tmp); %Gradient
            tmp = [tmpx(:); tmpy(:)]';
        elseif strcmpi(option, 'laplacian')
            tmp = del2(tmp); %Laplacian
            tmp = tmp(:)';
        else
            tmp = tmp(:)';
        end;

        tmp = tmp(find(~isnan(tmp)));
        if k == 1
            X = zeros(length(comps),length(tmp)) ;
        end
        X(k,:) =  tmp;
    end
    return
end

all_topos = [];
for k = 1:numc

    % compute topo map grid (topoimage)
    % ---------------------------------
    [hfig grid plotrad Xi Yi] = topoplot( EEG.icawinv(:,k), EEG.chanlocs(EEG.icachansind), ...
                                          'verbose', 'off',...
                                           'electrodes', 'on' ,'style','both',...
                                           'plotrad',0.55,'intrad',0.55,...
                                           'noplot', 'on', 'chaninfo', EEG.chaninfo);

    all_topos = setfield(all_topos, [ 'comp' int2str(k) '_grid' ], grid);
    all_topos = setfield(all_topos, [ 'comp' int2str(k) '_x' ]   , Xi(:,1));
    all_topos = setfield(all_topos, [ 'comp' int2str(k) '_y' ]   , Yi(:,1));

end

% Save topos in file
% ------------------
all_topos.datatype = 'TOPO';
tmpfile = fullfile( EEG.filepath, [ EEG.filename(1:end-3) 'icatopo' ]);
std_savedat(tmpfile, all_topos);

for k = 1:length(comps)
    tmp =  getfield(all_topos, [ 'comp' int2str(comps(k)) '_grid' ]);

    if strcmpi(option, 'gradient')
        [tmpx, tmpy]  = gradient(tmp); % Gradient
        tmp = [tmpx(:); tmpy(:)]';
    elseif strcmpi(option, 'laplacian')
        tmp = del2(tmp); % Laplacian
        tmp = tmp(:)';
    else
        tmp = tmp(:)';
    end;

    tmp = tmp(find(~isnan(tmp)));
    if k == 1
        X = zeros(length(comps),length(tmp)) ;
    end
    X(k,:) =  tmp;
end


% LOC_SUBSETS - Separate channels into maximally evenly-spaced subsets.
%                 This is achieved by exchanging channels between subsets so as to
%                 increase the sum of average of distances within each channel subset.
% Usage:
%       >> subset = loc_subsets(chanlocs, nchans); % select an evenly spaced nchans
%       >> [subsets subidx pos] = loc_subsets(chanlocs, nchans, plotobj, plotchans, keepchans);
%
% Inputs:
%
%   chanlocs    - EEGLAB dataset channel locations structure (e.g., EEG.chanlocs)
%
%   nchans      - (1,N) matrix containing number of channels that should be in each
%                 of N channel subsets respectively. if total number of channels in
%                 all subsets is less than the number of EEG channels in the chanlocs
%                 structure, N+1 subsets are created. The last subset includes the
%                 remaining channels.
%
% Optional inputs:
%
%   plotobj     - (true|false|1|0) plot the time course of the objective function
%                 {default: false|0)
%   plotchans   - (true|false|1|0) make 3-D plots showing the channel locations of
%                 the subsets {default: false|0)
%   keepchans   - (cell array) channels that has to be kept in each set and
%                 not undergo optimization. You can use this option to make
%                 sure certain channels will be assigned to each set. For
%                 example, to keep channels 1:10 to the first subset and
%                 channels 20:30 to the second, use keepchans = {[1:10], [20:30]}.
%                 To only keeps channels 1:5 in the first set, use
%                 keepchans = {1:5}.  {default: {}}
%
% Outputs:
%
%   subsets     - {1,N} or {1,N+1} cell array containing channel indices for each
%                 requested channel subset.
%   subidx      - (1, EEG.nbchans) vector giving the index of the subset associated
%                 with each channel.
%   pos         - (3,N) matrix, columns containing the cartesian (x,y,z) channel
%                 positions plotted.
% Example:
%
%   % Create three sub-montages of a 256-channel montage containing 32, 60, and 100
%   % channels respectively.The 64 remaining channels will be put into a fourth subset.
%   % Also visualize time course of optimization and the channel subset head locations.
%
%   >> subset = loc_subsets(EEG.chanlocs, [32 60 100], true, true);
%
% Author: Nima Bigdely Shamlo, SCCN/INC/UCSD, 2007

% Copyright (C) 2007 Nima Bigdely Shamlo, SCCN/INC/UCSD, nima@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.

% if plotOptimization|plotSubsets in line 130 removed by nima 3/6/2007
% line 133, removed num2str  removed by nima 3/6/2007

function [subset idx pos] = loc_subsets(chanlocs, numberOfChannelsInSubset, plotOptimization, plotSubsets, mandatoryChannelsForSet);

if sum(numberOfChannelsInSubset)> length(chanlocs)
    error('Total channels in requested subsets larger than number of EEG channels.');
end
if min(numberOfChannelsInSubset) < 2
    error('Number of channels in the requested subsets must be >= 2.');
end

rand('state',0);
if nargin < 5
    mandatoryChannelsForSet = {};
end

if nargin < 4
    plotSubsets = false;
end

if nargin < 3
    plotOptimization = false;
end

pos=[cell2mat({chanlocs.X}); cell2mat({chanlocs.Y}); cell2mat({chanlocs.Z});];
dist = squareform(pdist(pos'));

nChans = length(chanlocs);
idx = ones(nChans,1);
setId = cell(1, length(numberOfChannelsInSubset)); % cell array containing channels in each set

remainingChannels = 1:nChans; % channels that are to be assigned to subsets

% channels that have to stay in their original subset (as in
% mandatoryChannelsForSet) and should not be re-assigned
allMandatoryChannels = cell2mat(mandatoryChannelsForSet);

% assign requested mandatory channels to subset
for i=1:length(mandatoryChannelsForSet)
    setId{i} = mandatoryChannelsForSet{i};
    remainingChannels(mandatoryChannelsForSet{i}) = NaN; % flag with Nan so they can be deleted later, this is to keep indexing simple
end
remainingChannels(isnan(remainingChannels)) = [];

r = remainingChannels(randperm(length(remainingChannels)));

% randomly assign remaining channels to subsets
for i=1:length(numberOfChannelsInSubset)
    numberOfChannelsTobeAddedToSubset = numberOfChannelsInSubset(i) - length(setId{i})
    setId{i} = [setId{i} r(1:numberOfChannelsTobeAddedToSubset)];
    r(1:numberOfChannelsTobeAddedToSubset) = [];
end

if length(r) > 0
    setId{length(numberOfChannelsInSubset) + 1} = r; % last set gets remaining channels
end

if plotOptimization|plotSubsets
fprintf(['Creating total of ' num2str(length(setId)) ' channel subsets:\n']);
end

if plotOptimization
    figure;
  xp = floor(sqrt(length(setId)));
  yp = ceil(length(setId)/xp);
end
    counter = 1;
exchangeHappened = true;

while exchangeHappened
    exchangeHappened = false;
    for set1 = 1:length(setId)
        for set2 = (set1 + 1):length(setId)
            for i = 1:length(setId{set1})
                for j = 1:length(setId{set2})
                    chan(1) = setId{set1}(i);
                    chan(2) = setId{set2}(j);
                    if cost_of_exchanging_channels(chan,[set1 set2], setId, dist) < 0 && ~any(ismember(chan, allMandatoryChannels))
                        setId{set1}(find(setId{set1} == chan(1))) = chan(2);
                        setId{set2}(find(setId{set2} == chan(2))) = chan(1);
                        sumDistances(counter) = 0;
                        for s = 1:length(setId)
                            sumDistances(counter) = sumDistances(counter) ...
                                 + (sum(sum(dist(setId{s},setId{s}))) / length(setId{s}));
                        end
                        if plotOptimization
                            plot(1:counter,sumDistances,'-b');
                            xlabel('number of exchanges');
                            ylabel('sum mean distances within each channel subset');
                            drawnow;
                        else
                            if mod(counter, 20) ==0
                                fprintf('number of exchanges = %d\nsum of mean distances = %g\n',...
                                           counter, sumDistances(counter));
                            end
                        end
                        counter = counter + 1;
                        exchangeHappened = true;
                    end
                end
            end
        end
    end
end

for set = 1:length(setId)
    idx(setId{set}) = set;
%    legendTitle{set} = ['subset ' num2str(set)];
end

subset = setId;

if plotSubsets
    FIG_OFFSET = 40;
    fpos = get(gcf,'position');
    figure('position',[fpos(1)+FIG_OFFSET,fpos(2)-FIG_OFFSET,fpos(3),fpos(4)]);
    scatter3(pos(1,:), pos(2,:), pos(3,:),100,idx,'fill');
    axis equal;
    %legend(legendTitle); it does not work propr
    th=title('Channel Subsets');
    %set(th,'fontsize',14)
end

if length(r)>0 && (plotOptimization|plotSubsets)
    fprintf('The last subset returned contains the %d unused channels.\n',...
                   length(r));
end

function cost = cost_of_exchanging_channels(chan, betweenSets, setId, dist);

mirrorChan(1) = 2;
mirrorChan(2) = 1;

for i=1:2
    newSetId{betweenSets(i)} = setId{betweenSets(i)};
    newSetId{betweenSets(i)}(find(newSetId{betweenSets(i)} == chan(i))) = chan(mirrorChan(i));
end

cost = 0;
for i=betweenSets
    distSumBefore{i} = sum(sum(dist(setId{i},setId{i})));
    distSumAfter{i} = sum(sum(dist(newSetId{i},newSetId{i})));
    cost = cost + (distSumBefore{i} - distSumAfter{i}) / length(setId{i});
end

%cost = (distSumAfter{1} > distSumBefore{1}) && (distSumAfter{2} > distSumBefore{2});


function sub_sst = delete_sst(sst,t1,t2,edge_mode)

%DELETE_SST: Delete event SST (Start/Stop Times) between t1 and t2
%
%USAGE: sub_sst = delete_sst(sst,t1,t2,edge_mode)
%
%INPUTS: sst - Event Start/Stop Times [Nx2 array of numeric time values]
%        t1  - time value, delete all events in sst between t1 (start)
%              and t2 (end)
%        t2  - see 't1'
%        edge_mode  - If t1 or t2 falls between an event start time and
%                stop time in sst, edge_mode determines if the event is
%                deleted, retained, or partially deleted at time t1 or t2.
%           'delete' - whole event is removed from array sub_sst
%           'keep'   - whole event is retained in array sub_sst
%           'part'   - event in sub_sst is split - i.e. deleted
%                       before t1 or after t2
%
%OUTPUTS: sub_sst - Subset of origianl sst (Event Start/Stop Times)
%                   [Nx2 array of numeric time values]
%
% See also ADD_SST, CHK_T, COMPARE_SST, DELETE_SST, EXTRACT_SST, IS_SST,
%          ISTEQUAL, MERGE_SST, SEARCH_SST, SORT_SST, NAN2SST, SSD2SST,
%          SST2NAN, SST2SSD, SST2VAL, SST2WFA, WFA2SST
%
% Author: Dane Ketner, Alaska Volcano Observatory
% $Date$
% $Revision$

if nargin < 4
   error('DELETE_SST: Too few input arguments')
elseif nargin > 4
   error('DELETE_SST: Too many input arguments')
end

if is_sst(sst)
   if iscell(sst)
      for m = 1:numel(sst)
         sub_sst{m} = DELETE_SST(sst{m},t1,t2,edge_mode);
      end
   else
      sub_sst = DELETE_SST(sst,t1,t2,edge_mode);
   end
else
   error('DELETE_SST: Not a valid Start/Stop Time Argument')
end

%%
function sub_sst = DELETE_SST(sst,t1,t2,edge_mode)

[N1 P1] = search_sst(t1,sst);
[N2 P2] = search_sst(t2,sst);

% 'first' and 'last' refer to the first and last events within the time
%  span defined by t1 and t2. N1 is the event number within sst
%  corresponding to t1, and P1 is the corresponding event position with
%  relation to t1. P1 = 1 if t1 falls inside the event time. P1 = 0 if t1
%  is before the start of the event.

if P1 == 1
   if strcmpi(edge_mode,'part')
      first = [sst(N1,1) t1];
   elseif strcmpi(edge_mode,'delete')
      first = [];
   elseif strcmpi(edge_mode,'keep')
      first = sst(N1,:);
   end
elseif P1 == 0
   first = [];
end

if P2 == 1
   if strcmpi(edge_mode,'part')
      last = [t2 sst(N2,2)];
   elseif strcmpi(edge_mode,'delete')
      last = [];
   elseif strcmpi(edge_mode,'keep')
      last = sst(N2,:);
   end
elseif P2 == 0
   last = sst(N2,:);
end

sub_sst = [sst(1:N1-1,:); first; last; sst(N2+1:end,:)];


function chns = chnsCompute( I, varargin )
% Compute channel features at a single scale given an input image.
%
% Compute the channel features as described in:
%  P. Doll�r, Z. Tu, P. Perona and S. Belongie
%  "Integral Channel Features", BMVC 2009.
% Channel features have proven very effective in sliding window object
% detection, both in terms of *accuracy* and *speed*. Numerous feature
% types including histogram of gradients (hog) can be converted into
% channel features, and overall, channels are general and powerful.
%
% Given an input image I, a corresponding channel is a registered map of I,
% where the output pixels are computed from corresponding patches of input
% pixels (thus preserving overall image layout). A trivial channel is
% simply the input grayscale image, likewise for a color image each color
% channel can serve as a channel. Other channels can be computed using
% linear or non-linear transformations of I, various choices implemented
% here are described below. The only constraint is that channels must be
% translationally invariant (i.e. translating the input image or the
% resulting channels gives the same result). This allows for fast object
% detection, as the channels can be computed once on the entire image
% rather than separately for each overlapping detection window.
%
% Currently, three channel types are available by default (to date, these
% have proven the most effective for sliding window object detection):
%  (1) color channels (computed using rgbConvert.m)
%  (2) gradient magnitude (computed using gradientMag.m)
%  (3) quantized gradient channels (computed using gradientHist.m)
% For more information about each channel type, including the exact input
% parameters and their meanings, see the respective m-files which perform
% the actual computatons (chnsCompute is essentially a wrapper function).
% The converted color channels serve as input to gradientMag/gradientHist.
%
% Additionally, custom channels can be specified via an optional struct
% array "pCustom" which may have 0 or more custom channel definitions. Each
% custom channel is generated via a call to "chns=feval(hFunc,I,pFunc{:})".
% The color space of I is determined by pColor.colorSpace, use the setting
% colorSpace='orig' if the input image is not an 'rgb' image and should be
% left unchanged (e.g. if I has multiple channels). The input I will have
% type single and the output of hFunc should also have type single.
%
% "shrink" (which should be an integer) determines the amount to subsample
% the computed channels (in applications such as detection subsamping does
% not affect performance). The params for each channel type are described
% in detail in the respective function. In addition, each channel type has
% a param "enabled" that determines if the channel is computed. If
% chnsCompute() is called with no inputs, the output is the complete
% default params (pChns). Otherwise the outputs are the computed channels
% and additional meta-data (see below). The channels are computed at a
% single scale, for (fast) multi-scale channel computation see chnsPyramid.
%
% An emphasis has been placed on speed, with the code undergoing heavy
% optimization. Computing the full set of channels used in the BMVC09 paper
% referenced above on a 480x640 image runs over *100 fps* on a single core
% of a machine from 2011 (although runtime depends on input parameters).
%
% USAGE
%  pChns = chnsCompute()
%  chns = chnsCompute( I, pChns )
%
% INPUTS
%  I           - [hxwx3] input image (uint8 or single/double in [0,1])
%  pChns       - parameters (struct or name/value pairs)
%   .shrink       - [4] integer downsampling amount for channels
%   .pColor       - parameters for color space:
%     .enabled      - [1] if true enable color channels
%     .smooth       - [1] radius for image smoothing (using convTri)
%     .colorSpace   - ['luv'] choices are: 'gray', 'rgb', 'hsv', 'orig'
%   .pGradMag     - parameters for gradient magnitude:
%     .enabled      - [1] if true enable gradient magnitude channel
%     .colorChn     - [0] if>0 color channel to use for grad computation
%     .normRad      - [5] normalization radius for gradient
%     .normConst    - [.005] normalization constant for gradient
%     .full         - [0] if true compute angles in [0,2*pi) else in [0,pi)
%   .pGradHist    - parameters for gradient histograms:
%     .enabled      - [1] if true enable gradient histogram channels
%     .binSize      - [shrink] spatial bin size (defaults to shrink)
%     .nOrients     - [6] number of orientation channels
%     .softBin      - [0] if true use "soft" bilinear spatial binning
%     .useHog       - [0] if true perform 4-way hog normalization/clipping
%     .clipHog      - [.2] value at which to clip hog histogram bins
%   .pCustom      - parameters for custom channels (optional struct array):
%     .enabled      - [1] if true enable custom channel type
%     .name         - ['REQ'] custom channel type name
%     .hFunc        - ['REQ'] function handle for computing custom channels
%     .pFunc        - [{}] additional params for chns=hFunc(I,pFunc{:})
%     .padWith      - [0] how channel should be padded (e.g. 0,'replicate')
%   .complete     - [] if true does not check/set default vals in pChns
%
% OUTPUTS
%  chns       - output struct
%   .pChns      - exact input parameters used
%   .nTypes     - number of channel types
%   .data       - [nTypes x 1] cell [h/shrink x w/shrink x nChns] channels
%   .info       - [nTypes x 1] struct array
%     .name       - channel type name
%     .pChn       - exact input parameters for given channel type
%     .nChns      - number of channels for given channel type
%     .padWith    - how channel should be padded (0,'replicate')
%
% EXAMPLE - default channels
%  I=imResample(imread('peppers.png'),[480 640]); pChns=chnsCompute();
%  tic, for i=1:100, chns=chnsCompute(I,pChns); end; toc
%  figure(1); montage2(cat(3,chns.data{:}));
%
% EXAMPLE - default + custom channels
%  I=imResample(imread('peppers.png'),[480 640]); pChns=chnsCompute();
%  hFunc=@(I) 5*sqrt(max(0,max(convBox(I.^2,2)-convBox(I,2).^2,[],3)));
%  pChns.pCustom=struct('name','Std02','hFunc',hFunc); pChns.complete=0;
%  tic, chns=chnsCompute(I,pChns); toc
%  figure(1); im(chns.data{4});
%
% See also rgbConvert, gradientMag, gradientHist, chnsPyramid
%
% Piotr's Computer Vision Matlab Toolbox      Version 3.23
% Copyright 2014 Piotr Dollar & Ron Appel.  [pdollar-at-gmail.com]
% Licensed under the Simplified BSD License [see external/bsd.txt]

% get default parameters pChns
if(nargin==2), pChns=varargin{1}; else pChns=[]; end
if( ~isfield(pChns,'complete') || pChns.complete~=1 || isempty(I) )
  p=struct('enabled',{},'name',{},'hFunc',{},'pFunc',{},'padWith',{});
  pChns = getPrmDflt(varargin,{'shrink',4,'pColor',{},'pGradMag',{},...
    'pGradHist',{},'pCustom',p,'complete',1},1);
  pChns.pColor = getPrmDflt( pChns.pColor, {'enabled',1,...
    'smooth',1, 'colorSpace','luv'}, 1 );
  pChns.pGradMag = getPrmDflt( pChns.pGradMag, {'enabled',1,...
    'colorChn',0,'normRad',5,'normConst',.005,'full',0}, 1 );
  pChns.pGradHist = getPrmDflt( pChns.pGradHist, {'enabled',1,...
    'binSize',[],'nOrients',6,'softBin',0,'useHog',0,'clipHog',.2}, 1 );
  nc=length(pChns.pCustom); pc=cell(1,nc);
  for i=1:nc, pc{i} = getPrmDflt( pChns.pCustom(i), {'enabled',1,...
      'name','REQ','hFunc','REQ','pFunc',{},'padWith',0}, 1 ); end
  if( nc>0 ), pChns.pCustom=[pc{:}]; end
end
if(nargin==0), chns=pChns; return; end

% create output struct
info=struct('name',{},'pChn',{},'nChns',{},'padWith',{});
chns=struct('pChns',pChns,'nTypes',0,'data',{{}},'info',info);

% crop I so divisible by shrink and get target dimensions
shrink=pChns.shrink; [h,w,~]=size(I); cr=mod([h w],shrink);
if(any(cr)), h=h-cr(1); w=w-cr(2); I=I(1:h,1:w,:); end
h=h/shrink; w=w/shrink;

% compute color channels
p=pChns.pColor; nm='color channels';
I=rgbConvert(I,p.colorSpace); I=convTri(I,p.smooth);
if(p.enabled), chns=addChn(chns,I,nm,p,'replicate',h,w); end

% compute gradient magnitude channel
p=pChns.pGradMag; nm='gradient magnitude';
full=0; if(isfield(p,'full')), full=p.full; end
if( pChns.pGradHist.enabled )
  [M,O]=gradientMag(I,p.colorChn,p.normRad,p.normConst,full);
elseif( p.enabled )
  M=gradientMag(I,p.colorChn,p.normRad,p.normConst,full);
end
if(p.enabled), chns=addChn(chns,M,nm,p,0,h,w); end

% compute gradient histgoram channels
p=pChns.pGradHist; nm='gradient histogram';
if( p.enabled )
  binSize=p.binSize; if(isempty(binSize)), binSize=shrink; end
  H=gradientHist(M,O,binSize,p.nOrients,p.softBin,p.useHog,p.clipHog,full);
  chns=addChn(chns,H,nm,pChns.pGradHist,0,h,w);
end

% compute custom channels
p=pChns.pCustom;
for i=find( [p.enabled] )
  C=feval(p(i).hFunc,I,p(i).pFunc{:});
  chns=addChn(chns,C,p(i).name,p(i),p(i).padWith,h,w);
end

end

function chns = addChn( chns, data, name, pChn, padWith, h, w )
% Helper function to add a channel to chns.
[h1,w1,~]=size(data);
if(h1~=h || w1~=w), data=imResampleMex(data,h,w,1);
  assert(all(mod([h1 w1]./[h w],1)==0)); end
chns.data{end+1}=data; chns.nTypes=chns.nTypes+1;
chns.info(end+1)=struct('name',name,'pChn',pChn,...
  'nChns',size(data,3),'padWith',padWith);
end


function c = bitshift(a,b)
	checkinputs(a,b);

	if numel(b)==1
		if b<0
			c = int64rightshift(int64(a),int64(-b));
		else
			c = int64leftshift(int64(a),int64(b));
		end
	else
		c = zeros(size(b),'int64');
		neg = b < 0;
		if numel(a)==1
			c(neg)  = int64rightshift(int64(a),int64(-b(neg)));
			c(~neg) = int64leftshift(int64(a),int64(b(~neg)));
		else
			c(neg)  = int64rightshift(int64(a(neg)),int64(-b(neg)));
			c(~neg) = int64leftshift(int64(a(~neg)),int64(b(~neg)));
		end
	end
end


%% Copyright (C) 2006 Sylvain Pelissier <sylvain.pelissier@gmail.com>
%% Copyright (C) 2015-2016 Colin B. Macdonald <cbm@m.fsf.org>
%%
%% This program is free software; you can redistribute it and/or modify it under
%% the terms of the GNU General Public License as published by the Free Software
%% Foundation; either version 3 of the License, or (at your option) any later
%% version.
%%
%% This program is distributed in the hope that it will be useful, but WITHOUT
%% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
%% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
%% details.
%%
%% You should have received a copy of the GNU General Public License along with
%% this program; if not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defun dirac (@var{x})
%% Compute the Dirac delta (generalized) function.
%%
%% The Dirac delta ``function'' is a generalized function (or distribution)
%% which is zero almost everywhere, except at the origin where it is
%% infinite.
%%
%% Examples:
%% @example
%% @group
%% dirac (0)
%%   @result{} Inf
%% dirac (1)
%%   @result{} 0
%% dirac ([-10 -1 0 1 inf])
%%   @result{} 0     0   Inf     0     0
%% @end group
%% @end example
%% @seealso{heaviside, @@sym/dirac}
%% @end defun

function y = dirac(x)
  if (nargin ~= 1)
    print_usage ();
  end

  if (~isreal (x))
    error ('dirac: X must not contain complex values');
  end

  y = zeros (size (x), class (x));
  y(x == 0) = Inf;

  y(isnan (x)) = NaN;
end

%!assert (isinf (dirac (0)))
%!assert (dirac (1) == 0)
%!assert (isnan (dirac (nan)))
%!assert (isequaln (dirac ([-1 1 0 eps inf -inf nan]), [0 0 inf 0 0 0 nan]))
%!error <complex values> dirac (1i)
%!assert (isa (dirac (single (0)), 'single'))