% POP_JOINTPROB - reject artifacts in an EEG dataset using joint
%                   probability of the recorded electrode or component
%                   activities observed at each time point.  e.g., Observing
%                   large absolute values at most electrodes or components
%                   is improbable and may well mark the presence of artifact.
% Usage:
%   >> pop_jointprob( INEEG, typerej) % pop-up interactive window mode
%   >> [OUTEEG, locthresh, globthresh, nrej] = ...
%		= pop_jointprob( INEEG, typerej, elec_comp, ...
%                   locthresh, globthresh, superpose, reject, vistype);
%
% Graphic interface:
%   "Electrode|Component" - [edit box] electrodes or components indices to take
%                 into consideration for rejection. Same as the 'elec_comp'
%                 parameter in the command line call (see below).
%   "Single-channel limit|Single-component limit" - [edit box] activity
%                 probability limit(s) (in  std. dev.) Sets the 'locthresh'
%                  command line parameter. If more than one, defined individual
%                 electrode|channel limits. If fewer values than the number
%                 of electrodes|components specified above, the last input
%                 value is used for all remaining electrodes|components.
%   "All-channel limit|All-component limit" - [edit box] activity probability
%                 limit(s) (in std. dev.) for all channels (grouped).
%                 Sets the 'globthresh' command line parameter.
%   "visualization type" - [popup menu] can be either 'REJECTRIALS'|'EEGPLOT'.
%                 This correspond to the command line input option 'vistype'
%   "Display with previous rejection(s)" - [checkbox] This checkbox set the
%                 command line input option 'superpose'.
%   "Reject marked trial(s)" - [checkbox] This checkbox set the command
%                  line input option 'reject'.
% Inputs:
%   INEEG      - input dataset
%   typerej    - [1|0] data to reject on (0 = component activations;
%              1 = electrode data). {Default: 1 = electrode data}.
%   elec_comp  - [n1 n2 ...] electrode|component number(s) to take into
%              consideration for rejection
%   locthresh  - activity probability limit(s) (in std. dev.) See "Single-
%              channel limit(s)" above.
%   globthresh - global limit(s) (all activities grouped) (in std. dev.)
%   superpose  - [0|1] 0 = Do not superpose rejection marks on previously
%              marks stored in the dataset: 1 = Show both current and
%              previous marks using different colors. {Default: 0}.
%   reject     - 0 = do not reject marked trials (but store the marks:
%              1 = reject marked trials {Default: 1}.
%   vistype    - Visualization type. [0] calls REJSTATEPOCH and [1] calls
%              EEGPLOT default is [0].When added to the command line
%              call it will not display the plots if the option 'plotflag'
%              is not set.
% topcommand   - [] Deprecated argument , keep to ensure backward compatibility
% plotflag     - [1,0] [1]Turns plots 'on' from command line, [0] off.
%              (Note for developers: When called from command line
%              it will make 'calldisp = plotflag') {Default: 0}
%
% Outputs:
%   OUTEEG     - output dataset with updated joint probability array
%   locthresh  - electrodes probability of activity thresholds in terms
%              of standard-dev.
%   globthresh - global threshold (where all electrode activity are
%              regrouped).
%   nrej       - number of rejected sweeps
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: JOINTPROB, REJSTATEPOCH, EEGPLOT, EEGLAB, POP_REJEPOCH

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

% 01-25-02 reformated help & license -ad
% 03-07-02 added srate argument to eegplot call -ad
% 03-08-02 add eeglab options -ad

function [EEG, locthresh, globthresh, nrej, com] = pop_jointprob( EEG, icacomp, elecrange, ...
                       		locthresh, globthresh, superpose, reject, vistype, topcommand,plotflag);
nrej = []; com = '';
if nargin < 1
   help pop_jointprob;
   return;
end;
if nargin < 2
   icacomp = 1;
end;

if icacomp == 0
	if isempty( EEG.icasphere )
	    ButtonName=questdlg( 'Do you want to run ICA now ?', ...
                         'Confirmation', 'NO', 'YES', 'YES');
    	switch ButtonName,
        	case 'NO', disp('Operation cancelled'); return;
        	case 'YES', [ EEG com ] = pop_runica(EEG);
    	end % switch
	end
end;
if exist('reject') ~= 1
    reject = 1;
end

if nargin < 3

    % which set to save
    % -----------------
    promptstr   = { [ fastif(icacomp, 'Electrode', 'Component') ' (indices; Ex: 2 6:8 10):' ], ...
                    [ fastif(icacomp, 'Single-channel', 'Single-component') ' limit(s) (std. dev(s).: Ex: 2 2 2.5):'], ...
                    [ fastif(icacomp, 'All-channel', 'All-component') ' limit(s) (std. dev(s).: Ex: 2 2.1 2):'], ...
                    'Visualization type',...
                    'Display previous rejection marks', ...
                    'Reject marked trial(s)'};

    inistr = { fastif(icacomp, ['1:' int2str(EEG.nbchan)], ['1:' int2str(size(EEG.icaweights,1))])...
               fastif(icacomp, '3', '5'),  ...
               fastif(icacomp, '3', '5'), ...
               '',...
               '1', ...
               '0'};

    vismodelist= {'REJECTTRIALS','EEGPLOT'};
    g1  = [1 0.1 0.75];
    g2 = [1 0.26 0.9];
    g3 = [1 0.22 0.85];
    geometry = {g1 g1 g1 g2 [1] g3 g3};

    uilist = {...
              { 'Style', 'text', 'string', promptstr{1}} {} { 'Style','edit'      , 'string' ,inistr{1} 'tag' 'cpnum'}...
              { 'Style', 'text', 'string', promptstr{2}} {} { 'Style','edit'      , 'string' ,inistr{2} 'tag' 'singlelimit'}...
              { 'Style', 'text', 'string', promptstr{3}} {} { 'Style','edit'      , 'string' ,inistr{3} 'tag' 'alllimit'}...
              { 'Style', 'text', 'string', promptstr{4}} {} { 'Style','popupmenu' , 'string' , vismodelist 'tag' 'specmethod' 'value' 2 }...
              {}...
              { 'Style', 'text', 'string', promptstr{5}} {} { 'Style','checkbox'  ,'string'  , ' ' 'value' str2double(inistr{5}) 'tag','rejmarks' }...
              { 'Style', 'text', 'string', promptstr{6}} {} { 'Style','checkbox'  ,'string'  ,' ' 'value'  str2double(inistr{6})  'tag' 'rejtrials'} ...
              };
    figname = fastif( ~icacomp, 'Reject. improbable comp. -- pop_jointprob()', 'Reject improbable data -- pop_jointprob()');
    result = inputgui( geometry,uilist,'pophelp(''pop_jointprob'');', figname);

    size_result  = size( result );
    if size_result(1) == 0, locthresh = []; globthresh = []; return; end
    elecrange    = result{1};
    locthresh    = result{2};
    globthresh   = result{3};
    switch result{4}, case 1, vistype=0; otherwise, vistype=1; end
    superpose    = result{5};
    reject       = result{6};

end

if ~exist('vistype'  ,'var'), vistype   = 0; end
if ~exist('reject'   ,'var'), reject    = 0; end
if ~exist('superpose','var'), superpose = 1; end

if ischar(elecrange) % convert arguments if they are in text format
    calldisp = 1;
	elecrange  = eval( [ '[' elecrange ']'  ]  );
	locthresh  = eval( [ '[' locthresh ']'  ]  );
	globthresh = eval( [ '[' globthresh ']' ]  );
else
    calldisp = 0;
end

if exist('plotflag','var') && ismember(plotflag,[1,0])
    calldisp = plotflag;
else
    plotflag = 0;
end

if isempty(elecrange)
	error('No electrode selectionned');
end;

% compute the joint probability
% -----------------------------
if icacomp == 1
	fprintf('Computing joint probability for channels...\n');
    tmpdata = eeg_getdatact(EEG);
    if isempty(EEG.stats.jpE)
		[ EEG.stats.jpE rejE ] = jointprob( tmpdata, locthresh, EEG.stats.jpE, 1);
	end
	[ tmp rejEtmp ] = jointprob( tmpdata(elecrange,:,:), locthresh, EEG.stats.jpE(elecrange,:), 1);
    rejE    = zeros(EEG.nbchan, size(rejEtmp,2));
	rejE(elecrange,:) = rejEtmp;

	fprintf('Computing all-channel probability...\n');
	tmpdata2 = permute(tmpdata, [3 1 2]);
	tmpdata2 = reshape(tmpdata2, size(tmpdata2,1), size(tmpdata2,2)*size(tmpdata2,3));
	[ EEG.stats.jp rej ] = jointprob( tmpdata2, globthresh, EEG.stats.jp, 1);
    clear tmpdata2;
else
    tmpdata = eeg_getica(EEG);
	fprintf('Computing joint probability for components...\n');
    if isempty(EEG.stats.icajpE)
		[ EEG.stats.icajpE rejE ] = jointprob( tmpdata, locthresh, EEG.stats.icajpE, 1);
	end
	[ tmp rejEtmp ] = jointprob( tmpdata(elecrange,:), locthresh, EEG.stats.icajpE(elecrange,:), 1);
    rejE    = zeros(size(tmpdata,1), size(rejEtmp,2));
	rejE(elecrange,:) = rejEtmp;

	fprintf('Computing global joint probability...\n');
	tmpdata2 = permute(tmpdata, [3 1 2]);
	tmpdata2 = reshape(tmpdata2, size(tmpdata2,1), size(tmpdata2,2)*size(tmpdata2,3));
	[ EEG.stats.icajp  rej] = jointprob( tmpdata2, globthresh, EEG.stats.icajp, 1);
	clear tmpdata2;
end
rej = rej' | max(rejE, [], 1);
fprintf('%d/%d trials marked for rejection\n', sum(rej), EEG.trials);

if calldisp
	if vistype == 1 % EEGPLOT -------------------------
	    if icacomp == 1 macrorej  = 'EEG.reject.rejjp';
	        			macrorejE = 'EEG.reject.rejjpE';
	    else			macrorej  = 'EEG.reject.icarejjp';
	        			macrorejE = 'EEG.reject.icarejjpE';
	    end
		colrej = EEG.reject.rejjpcol;
		eeg_rejmacro; % script macro for generating command and old rejection arrays

	    if icacomp == 1
	        eegplot( tmpdata(elecrange,:,:), 'srate', ...
		      EEG.srate, 'limits', [EEG.xmin EEG.xmax]*1000 , 'command', command, eegplotoptions{:});
	    else
	        eegplot( tmpdata(elecrange,:,:), 'srate', ...
		      EEG.srate, 'limits', [EEG.xmin EEG.xmax]*1000 , 'command', command, eegplotoptions{:});
	    end;
    else % REJECTRIALS -------------------------
	  	if icacomp	== 1
			[ rej, rejE, n, locthresh, globthresh] = ...
				rejstatepoch( tmpdata(elecrange,:,:), EEG.stats.jpE(elecrange,:), 'global', 'on', 'rejglob', EEG.stats.jp, ...
						'threshold', locthresh, 'thresholdg', globthresh, 'normalize', 'off'  );
		else
			[ rej, rejE, n, locthresh, globthresh] = ...
				rejstatepoch( tmpdata(elecrange,:,:), EEG.stats.icajpE(elecrange,:), 'global', 'on', 'rejglob', EEG.stats.icajp, ...
						'threshold', locthresh, 'thresholdg', globthresh, 'normalize', 'off' );
		end;
		nrej = n;
	end;
else
	% compute rejection locally
	rejtmp = max(rejE(elecrange,:),[],1);
	rej = rejtmp | rej;
	nrej =  sum(rej);
	fprintf('%d trials marked for rejection\n', nrej);
    if reject
        EEG = pop_rejepoch(EEG, rej, 0);
    end
end
if ~isempty(rej)
	if icacomp	== 1
		EEG.reject.rejjp = rej;
		EEG.reject.rejjpE = rejE;
	else
		EEG.reject.icarejjp = rej;
		EEG.reject.icarejjpE = rejE;
	end
end
nrej = sum(rej);

com = [ com sprintf('EEG = pop_jointprob(EEG,%s);', ...
		vararg2str({icacomp,elecrange,locthresh,globthresh,superpose,reject & ~calldisp, vistype, [],plotflag})) ];
if nargin < 3 && nargout == 2
	locthresh = com;
end

return;


clear all;
close all;
clc;
spx.cluster.ssc.util.bench_subspace_preservation(@ssc_omp, 'ssc_omp');


function imgs = readspefile(inputfile)
% imgs = readspefile(inputfile)
% Reads SPE file. This is copied from CSSTORM.m

fid = fopen(inputfile, 'r', 'l');
header = fread(fid,2050,'*uint16');

% parsing .spe header
x_dim = double(header(22));
y_dim = double(header(329));
z_dim = double(header(724));
img_mode = header(55);
if img_mode == 0
    imgs = fread(fid, inf, 'float32');
elseif img_mode == 1
    imgs = fread(fid, inf, 'uint32');
elseif img_mode == 2
    imgs = fread(fid, inf, 'int16');
elseif img_mode == 3
    imgs = fread(fid, inf, 'uint16');
end

fclose(fid);

imgs = reshape(imgs, [x_dim y_dim z_dim]);


% PURPOSE: detects ICA process in a dataset
%
% FORMAT
%
% value = isica(EEG);
%
% if value = 1 then the EEG dataset is ICA-ed. Otherwise, value = 0
%
% Author: Javier Lopez-Calderon
% Center for Mind and Brain
% University of California, Davis,
% Davis, CA
% July 7, 2011

function value = isica(EEG)
value     = 0; % no ica-ed file by default
if nargin<1
        help isica
        return
end
icafields = {'icaact','icawinv','icasphere','icaweights','icachansind','specicaact','icasplinefile'};
nif       = length(icafields);
for k=1:nif
        if isfield(EEG, icafields{k}) && ~isempty(EEG.(icafields{k}))
                value = 1; % ica-ed file detected
                break
        end
end
return


function y=check_states(x,s,t_start,t)
x=x+s.*(t-t_start);
dx=min(diff(x));
if (dx<-1e-6)
	y=0;
	dx
else
	y=1;
end;


function X=transpose(X)
%TRANSPOSE (overloaded)

if isa(X,'blkvar')
    X = sdpvar(X);
end

n = X.dim(1);
m = X.dim(2);
ind = reshape(reshape(1:n*m,n,m)',n*m,1);
X.basis = X.basis(ind,:);
X.dim(1) = m;
X.dim(2) = n;
% Reset info about conic terms
X.conicinfo = [0 0];
X = transposefactor(X);


classdef ODE5Integrator < AbstractFixedStepIntegrator
    %ODE5Integrator Summary of this class goes here
    %   Detailed explanation goes here

    properties
        options(1,1) FixedStepSizeIntegratorOptions = FixedStepSizeIntegratorOptions()
        integratorEnum = IntegratorEnum.ODE5;
    end

    methods
        function obj = ODE5Integrator(options)
            if(nargin > 0)
                obj.options = options;
            else
                obj.options = FixedStepSizeIntegratorOptions();
            end
        end

        function [t,y,te,ye,ie] = integrate(obj, odefun, tspan, y0, evtsFunc, odeOutputFun)
%             odeSetOptions = obj.options.getIntegratorOptions();
            odeSetOptions = odeset();
            optionsToUse = odeset(odeSetOptions, 'Events',evtsFunc, 'OutputFcn',odeOutputFun);

            [t,y, te,ye,ie] = AbstractFixedStepIntegrator.integrate(odefun, tspan, y0, optionsToUse);
        end

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

    methods(Static,Access=protected)
        function [A,B,C] = getButcherTableauData()
            A = [  1/5,          0,           0,            0,         0
                   3/40,         9/40,        0,            0,         0
                   44/45        -56/15,       32/9,         0,         0
                   19372/6561,  -25360/2187,  64448/6561,  -212/729,   0
                   9017/3168,   -355/33,      46732/5247,   49/176,   -5103/18656];

            B = [35/384, 0, 500/1113, 125/192, -2187/6784, 11/84];

            C = [1/5; 3/10; 4/5; 8/9; 1];

            A = A.';
            B = B(:);
            C = C(:);
        end
    end
end


function [ obblist, labellist ] = visualizeRelpos3_alignment( kids, mergereps, leafreps, params, labelset )
%VISUALIZERELPOS3_ALIGNMENT
% to visualize the absolute position of objects
% from the relative position respecting to its parents
% the layout needs to be adjust based on the "same orientation" and "alignment"
%
% the default setting is 2D, one-hot label vectors
%
% INPUT: kids, mergereps, leafreps, params   - the data to be visualized
%        labelset  - the name of the categories (order matters)
%
% OUTPUT: obblist  - the 3d obblist of all the leaves
%         labellist  - labels of all the leaves

dim = 2;
BOX = 0;
SUPPORT = 1;
GROUP = 2;
SURROUND = 3;

LABELLEN = length(labelset);
labeldefs = zeros(LABELLEN, LABELLEN);
for i = 1:LABELLEN
    labeldefs(i,i) = 1;
end

% transform the layers to discrete values
layers = [0.2,0.4,0.6,0.8,1];
for i = 1:size(leafreps,2)
    dist = abs(layers - leafreps(3,i));
    [~,I] = min(dist);
    leafreps(3,i) = layers(I)*5;
end

% transform the labels to one-hot labels
labellist = {};
for i = 1:size(leafreps,2)
    label = leafreps(4:end,i);
    [~,I] = max(label);
    leafreps(4:end,i) = labeldefs(:,I);
    labellist{length(labellist)+1} = labelset{I};
end

% back propagate the positions
rcent = [0;0]; % root center
rfront = [1;0]; % root front
framelist = zeros(4,length(kids));
framelist(:,length(kids)) = [rcent;rfront];
for i = length(kids):-1:1
    k = kids{i};
    frame = framelist(:,i);
    pcent = frame(1:2);
    pfront = frame(3:4);
    paxes = [-pfront(2);pfront(1)];
    transform = [pfront(:)';paxes(:)'];
%     transform = inv(transform);

    rps = mergereps{i};
    for j = 2:length(k)
        ind = k(j);
        rp = rps(:,j-1);

        % adjust the orientation
        sameori = rp(end);
        gtori = [-1,0,1];
        dist = abs(sameori - gtori);
        [~,I] = min(dist);
        sameori = gtori(I);
        if(sameori==1)
            rp(3:4) = [1;0];
        end
        if(sameori==-1)
            rp(3:4) = [-1;0];
        end

        ccent = rp(1:2);
        cfront = rp(3:4);
        cfront = cfront/norm(cfront,2);
        ncent = transform\ccent;
        ncent = ncent + pcent;
        nfront = transform\cfront;
        nfront = nfront/norm(nfront,2);
        nframe = [ncent;nfront];
        framelist(:,ind) = nframe;
    end
end

obblist = [];
for i = 1:length(kids)
    k = kids{i};
    if(k(1)==0)
        frame = framelist(:,i);
        leaf = leafreps(:,i);
        obb = [frame(1);0;frame(2);frame(3);0;frame(4);0;1;0;leaf(1);0;leaf(2)];
        obblist = [obblist,obb];
    end
end

%% forward propagate to adjust the alignments
translationlist = cell(length(kids),1);
nobblist = zeros(size(obblist,1),length(kids));
gtparam = [0,0.25,0.5,0.75,1];
for i = 1:length(kids)
    k = kids{i};
    flag = k(1);
    mparam = params{i};
    for j = 1:length(mparam)
       dist = abs(mparam(j)- gtparam);
       [~,I] = min(dist);
       mparam(j) = gtparam(I)*4;
    end
    if(flag==BOX)
        translationlist{i} = [0;0;0];
        obb = obblist(:,i);
        nobblist(:,i) = obb;
    end
    if(flag==SUPPORT)
        translationlist{i} = [0;0;0];
        list = k(2:end);
        nobblist(:,i) = updateOBB(nobblist,list);
    end
    if(flag==GROUP)
        if(all(mparam>0))
            obb1 = nobblist(:,k(2));
            obb2 = nobblist(:,k(3));
            [trans1, trans2, pobb] = adjustGroupOBB(obb1,obb2,mparam);
            translationlist{k(2)} = translationlist{k(2)} + trans1;
            translationlist{k(3)} = translationlist{k(3)} + trans2;
            translationlist{i} = [0;0;0];
            nobblist(:,i) = pobb;
        else
            translationlist{i} = [0;0;0];
            list = k(2:end);
            nobblist(:,i) = updateOBB(nobblist,list);
        end
    end
    if(flag==SURROUND)
        if(all(mparam>0))
            obb1 = nobblist(:,k(2));
            obb2 = nobblist(:,k(3));
            obb3 = nobblist(:,k(4));
            [trans1, trans2, trans3, pobb] = adjustSurroundOBB(obb1,obb2,obb3,mparam);
            translationlist{i} = [0;0;0];
            translationlist{k(2)} = translationlist{k(2)} + trans1;
            translationlist{k(3)} = translationlist{k(3)} + trans2;
            translationlist{k(4)} = translationlist{k(4)} + trans3;
            nobblist(:,i) = pobb;
        else
            translationlist{i} = [0;0;0];
            list = k(2:end);
            nobblist(:,i) = updateOBB(nobblist,list);
        end
    end
end

for i = length(kids):-1:1
    trans = translationlist{i};
    k = kids{i};
    list = k(2:end);
    for j = 1:length(list)
        ctrans = translationlist{list(j)};
        ctrans = ctrans+trans;
        translationlist{list(j)} = ctrans;
    end
end

for i = 1:size(obblist,2)
    obb = obblist(:,i);
    trans = translationlist{i};
    obb(1) = obb(1)+trans(1);
    obb(3) = obb(3)+trans(3);
    obblist(:,i) = obb;
end

end


function [r2,mn,st]= cv_mean(a,r,loss_type,param1)

if nargin<3
  [r2,st]=get_mean2(r);
  [mn,st]=get_mean2(r,[],1);
else
  [r2,st]=get_mean2(r,loss_type);
  [mn,st]=get_mean2(r,loss_type,1);
end


function lik = lik_liks(varargin)
%  LIKS creates a likelihood structure which is composed by many
%       different likelihoods.
%
%  Description:
%    LIK_LIK = LIK_LIKS(LIKELIHOODS, VALUE1, ...) creates a likelihood
%    structure that allows alternative likelihoods for latent variables.
%    The full likelihood is the product of independent likelihoods
%    (independent observations given the latent process),
%
%               __k     __
%      p(y|f) = ||      ||   L_j(y_i|f_i, th_j)
%                 j=1   i \in I_j
%
%      f = (f1' f2' ... fk')'
%      y = (y1' y2' ... yk')'
%
%    Here j is the index for different likelihoods and I_j is the index
%    vector telling for which observations likelihood j is used.
%
%    When using the Liks likelihood you must give the vector/matrix z as
%    an extra parameter to each function that requires also y. The matrix z
%    must include the covariates for independent likelihoods (see e.g.
%    LIK_POISSON) and a column telling the index of likelihood attached to
%    respective observation. For example:
%      lik = lik_liks('likelihoods', {lik1 lik2}, 'classVariables', 2);
%      gp = gp_set('lik', lik, 'cf', k, 'latent_method', 'EP');
%      z = [1 1 1 2 2 2]';
%      gp_optim(gp, x, y, 'z', z)
%    Here z is a vector telling that the first 3 observations are related
%    to likelihood 1 and the last 3 to likelihood 2.
%
%    Parameters for Liks likelihood are [default]
%      likelihoods      - array of likelyhood structures [ {} ]
%      classVariables   - a scalar telling which column of matrix z defines
%                         the likelihood indices
%
%    For the demonstration of the use of lik_liks see DEMO_MULTIVARIATEGP.
%
%  See also
%    GP_SET, LIK_*, PRIOR_*
%
% Copyright (c) 2011 Jaakko Riihimäki
% Copyright (c) 2011 Aki Vehtari
% Copyright (c) 2012 Ville Tolvanen
% Copyright (c) 2015-2017 Jarno Vanhatalo
% ------------- 2015-2017 Marcelo Hartmann
% Copyright (c) 2017 Ville Tolvanen

% 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.

  ip = inputParser;
  ip.FunctionName = 'LIK_LIKS';
  ip.addOptional('lik', [], @isstruct);
  ip.addParamValue('likelihoods', {}, @(x) ~isempty(x) && iscell(x));
  ip.addParamValue('classVariables', [], @(x) ~isempty(x) && isscalar(x));
  ip.parse(varargin{:});
  lik = ip.Results.lik;

  if isempty(lik)
      init = true;
      lik.type = 'Liks';
  else
      if ~isfield(lik, 'type') || ~isequal(lik.type, 'Liks')
          error('First argument does not seem to be a valid likelihood function structure')
      end
      init = false;
  end

  % Initialize likelihoods
  if init || ~ismember('likelihoods', ip.UsingDefaults)
      lik.liks = ip.Results.likelihoods;
  end

  % number of likelihood functions
  lik.nliks = length(lik.liks);
  if lik.nliks < 2
      error('use one likelihood structure')

  else
      % column of z where the classVariables can be found
      lik.classVariables = ip.Results.classVariables;
  end

  % Initialize prior structure
  % Even if there is no prior at all
  % see line 2065 in the file gpla_e.m, and you may see the light !!!
  if init
      lik.p = [];
  end

  if init
      % Set the function handles to the subfunctions
      lik.fh.pak = @lik_liks_pak;
      lik.fh.unpak = @lik_liks_unpak;
      lik.fh.lp = @lik_liks_lp;
      lik.fh.lpg = @lik_liks_lpg;
      lik.fh.ll = @lik_liks_ll;
      lik.fh.llg = @lik_liks_llg;
      lik.fh.llg2 = @lik_liks_llg2;
      lik.fh.llg3 = @lik_liks_llg3;
      lik.fh.tiltedMoments = @lik_liks_tiltedMoments;
      lik.fh.siteDeriv = @lik_liks_siteDeriv;
      lik.fh.predy = @lik_liks_predy;
      lik.fh.invlink = @lik_liks_invlink;
      lik.fh.recappend = @lik_liks_recappend;
  end

end

function [w, s, h] = lik_liks_pak(lik)
% LIK_LIKS_PAK  Combines each likelihood parameters into one vector.
%
%  Description:
%    W = LIK_LIKS_PAK(LIK) takes a likelihood structure LIK and
%    combines the parameters into a single row vector W. This is a
%    mandatory subfunction used for example in energy and gradient
%    computations.
%
%   See also
%   LIK_LIKS_UNPAK, GP_PAK

 w = []; s = {}; h = [];

 for j = 1:lik.nliks
     lik_j = lik.liks{j};
     [wj, sj, hj] = lik_j.fh.pak(lik_j);
     w = [w wj];
     s = [s; sj];
     h = [h hj];

 end

end

function [lik, w] = lik_liks_unpak(lik, w)
% LIK_LIKS_UNPAK  Extracts each likelihood parameters from the vector.
%
%  Description:
%    [LIK, W] = LIK_LIKS_UNPAK(W, LIK) takes each likelihood
%    structure inside LIK and extracts the parameters from the vector W
%    to the whole LIK structure. This is a mandatory subfunction used
%    for example in energy and gradient computations.
%
%   See also:
%   LIK_LIKS_PAK, GP_UNPAK

% Assignment is inverse parameter transformation

 for j = 1:lik.nliks
     lik_j = lik.liks{j};
     [lik_j, w] = lik_j.fh.unpak(lik_j, w);
     lik.liks{j} = lik_j;

 end

end

function lp = lik_liks_lp(lik, varargin)
% LIK_LIKS_LP  log(prior) of each the likelihood parameters
%
%  Description:
%    LP = LIK_LIKS_LP(LIK) takes the a likelihood structure LIK and
%    returns log(p(th)), where th collects the parameters. This
%    subfunction is needed when there are likelihood parameters.
%
%  See also:
%    LIK_LIKS_LLG, LIK_LIKS_LLG2, LIK_LIKS_LLG3, GPLA_E

 % If there is prior for the likelihood parameters
 lp = 0;

 for j = 1:lik.nliks
     if ~isempty(lik.liks{j}.fh.pak(lik.liks{j}))
         lp = lp + lik.liks{j}.fh.lp(lik.liks{j});
     end
 end

end

function lpg = lik_liks_lpg(lik)
% LIK_LIKS_LPG  dlog(prior)/dth of each the likelihood parameters th
%
%  Description:
%    E = LIK_LIKS_LPG(LIK) takes a likelihood structure LIK and
%    returns d log(p(th))/dth for each likelihood function,
%    where th collects the parameters.
%    This subfunction is needed when there are likelihood parameters.
%
%  See also:
%    LIK_LIKS_LLG, LIK_LIKS_LG3, LIK_LIKS_LLG2, GPLA_G

 lpg = [];

 for j = 1:lik.nliks
     if ~isempty(lik.liks{j}.fh.pak(lik.liks{j}))
         lpg = [lpg lik.liks{j}.fh.lpg(lik.liks{j})];
     end
 end

end

function ll = lik_liks_ll(lik, y, ff, z)
% LIK_LIKS_LL log-likelihood
%
%  Description:
%    LL = LIK_LIKS_LL(LIK, Y, F) takes a likelihood structure LIK.
%    Returns the log-likelihood, sum_{i=1}^{k} (log p_i(y|f)).
%    This subfunction is needed when using Laplace approximation
%    or MCMC for inference with non-Gaussian likelihoods. This
%    subfunction is also used in information criteria (DIC, WAIC)
%    computations.
%
%  See also:
%    LIK_LLG, LIK_LLG3, LIK_LLG2, GPLA_E

 n  = size(y, 1);
 indClass = 1:size(z,2)==lik.classVariables;
 zi = z(:, indClass);
 z  = z(:, ~indClass);

 indj  = unique(zi);
 nind = numel(indj);

 if n ~= numel(zi)
     error('row-length of y and z are different')
 end

 f = ff(:);
 ll = 0;
 for j = 1:nind
     ind = zi==indj(j);
     likj = lik.liks{indj(j)};

     yj = y(ind);
     fj = f(ind);
     if isempty(z)
         zj = z;
     else
         zj = z(ind);
     end
     ll = ll + likj.fh.ll(likj, yj, fj, zj);

 end

end

function llg = lik_liks_llg(lik, y, ff, param, z)
% LIK_LIKS_LLG  Gradient of the log-likelihood
%
%  Description:
%    LLG = LIK_LIKS_LLG(LIK, Y, F, PARAM) takes a likelihood
%    structure LIK, Returns the gradient of the log likelihood
%    with respect to PARAM for each likelihood function. At the moment PARAM
%    can be 'param' or 'latent'. This subfunction is needed when using
%    Laplace approximation or MCMC for inference with non-Gaussian
%    likelihoods.
%
%  See also:
%    LIK_LIKS_LL, LIK_LIKS_LLG2, LIK_LIKS_LLG3, GPLA_E

 n  = size(y, 1);
 indClass = 1:size(z,2)==lik.classVariables;
 zi = z(:, indClass);
 z  = z(:, ~indClass);

 indj  = unique(zi);
 nind = numel(indj);

 if n ~= numel(zi)
     error('row-length of y and z are different')
 end

 f = ff(:);

 switch param
     case 'param'
         llg = [];
     case 'latent'
         llg=zeros(size(f));
 end
 for j = 1:nind
     ind = zi==indj(j);
     likj = lik.liks{indj(j)};

     yj = y(ind);
     fj = f(ind);
     if isempty(z)
         zj = z;
     else
         zj = z(ind);
     end

     switch param
         case 'param'
             if ~isempty(lik.liks{j}.fh.pak(likj))
                 llg = [llg likj.fh.llg(likj, yj, fj, param, zj)];
             end
         case 'latent'
             llg(ind) = likj.fh.llg(likj, yj, fj, param, zj);
     end
 end

end

function llg2 = lik_liks_llg2(lik, y, ff, param, z)
% LIK_LIKS_LLG2  Second gradients of the log-likelihood
%
%  Description
%    LLG2 = LIK_LIKS_LLG2(LIK, Y, F, PARAM) takes a likelihood
%    structure LIK, Returns the hessian of the log likelihood
%    with respect to PARAM. At the moment PARAM can be only
%    'latent'. LLG2 is a vector with diagonal elements of the
%    Hessian matrix (off diagonals are zero). This subfunction
%    is needed when using Laplace approximation or EP for
%    inference with non-Gaussian likelihoods.
%
%  See also
%    LIK_LIKS_LL, LIK_LIKS_LLG, LIK_LIKS_LLG3, GPLA_E

 n  = size(y, 1);
 indClass = 1:size(z,2)==lik.classVariables;
 zi = z(:, indClass);
 z  = z(:, ~indClass);

 indj = unique(zi);
 nind = numel(indj);

 if n ~= numel(zi)
     error('row-length of y and z are different')
 end

 f = ff(:);

 nlikpar = length(lik.fh.pak(lik));
 z0 = zeros(n, nlikpar);
 aux(1) = 0;

 switch param
     case 'latent'
         llg2=zeros(size(f));
     case 'latent+param'
         llg2 = [];
 end
 for j = 1:nind
     ind = zi==indj(j);
     likj = lik.liks{indj(j)};

     yj = y(ind);
     fj = f(ind);
     if isempty(z)
         zj = z;
     else
         zj = z(ind);
     end

     switch param
         case 'param'

         case 'latent'
             llg2(ind) = likj.fh.llg2(likj, yj, fj, param, zj);

         case 'latent+param'
             if ~isempty(likj.fh.pak(likj))
                 % take the column vectors
                 llg2_tmp = likj.fh.llg2(likj, yj, fj, param, zj);

                 % auxiliar indexes
                 aux(end + 1) = aux(end) + size(likj.fh.pak(likj), 2);

                 % auxiliar matrices for derivatives w.r.t. parameters in
                 % the specific likelihood j
                 z0(ind, (aux(end - 1) + 1) : aux(end)) = llg2_tmp;
                 llg2 = [llg2 z0(:, aux(end - 1) + 1 : aux(end))];
                 z0(ind, (aux(end - 1) + 1) : aux(end)) = 0;

             end
     end

 end

end

function llg3 = lik_liks_llg3(lik, y, ff, param, z)
% LIK_LIKS_LLG3  Third gradients of the log likelihood
%
%  Description:
%    LLG3 = LIK_LIKS_LLG3(LIK, Y, F, PARAM) takes a likelihood
%    structure LIK, returns the third gradients of the log
%    likelihood with respect to PARAM. At the moment PARAM can be
%    only 'latent'. LLG3 is a vector with third gradients. This
%    subfunction is needed when using Laplace approximation for
%    inference with non-Gaussian likelihoods.
%
%  See also:
%    LIK_LIKS_LL, LIK_LIKS_LLG, LIK_LIKS_LLG2, GPLA_E, GPLA_G

 n  = size(y, 1);
 indClass = 1:size(z,2)==lik.classVariables;
 zi = z(:, indClass);
 z  = z(:, ~indClass);

 indj  = unique(zi);
 nind = numel(indj);

 if n ~= numel(zi)
     error('row-length of y and z are different')
 end

 f = ff(:);

 switch param
     case 'latent'
         llg3=zeros(size(f));
     case 'latent2+param'
         llg3 = [];
 end
 % auxiliar matrix for derivatives of parameters w.r.t. many likelihoods
 nlikpar = length(lik.fh.pak(lik));
 z0 = zeros(n, nlikpar);
 aux(1) = 0;

 for j = 1:nind
     switch param
         case 'param'

         case 'latent'
             ind = zi==indj(j);
             likj = lik.liks{indj(j)};

             yj = y(ind);
             fj = f(ind);
             if isempty(z)
                 zj = z;
             else
                 zj = z(ind);
             end

             llg3(ind) = likj.fh.llg3(likj, yj, fj, param, zj);

         case 'latent2+param'
             if ~isempty(lik.liks{indj(j)}.fh.pak(lik.liks{indj(j)}))
                 % take indexes and respective observations for specific likelihood
                 ind = zi==indj(j);
                 likj = lik.liks{indj(j)};

                 yj = y(ind);
                 fj = f(ind);
                 if isempty(z)
                     zj = z;
                 else
                     zj = z(ind);
                 end

                 % take the column vectors
                 llg3_tmp = likj.fh.llg3(likj, yj, fj, param, zj);

                 % auxiliar indexes
                 aux(end + 1) = aux(end) + size(likj.fh.pak(likj), 2);

                 % auxiliar matrices for derivatives w.r.t parameters in
                 % the specific likelihood j
                 z0(ind, (aux(end - 1) + 1) : aux(end)) = llg3_tmp;
                 llg3 = [llg3 z0(:, aux(end - 1) + 1 : aux(end))];
                 z0(ind, (aux(end - 1) + 1) : aux(end)) = 0;

             end

     end

 end

end

function [logM_0, m_1, sigm2hati1] = lik_liks_tiltedMoments(lik, y, i1, sigm2_i, myy_i, z)
% LIK_LIKS_TILTEDMOMENTS  Returns the marginal moments for EP algorithm
%
%  Description
%    [M_0, M_1, M2] = LIK_LIKS_TILTEDMOMENTS(LIK, Y, I, S2,
%    MYY) takes a likelihood structure LIKS, the observation Y, index
%    I, cavity variance S2 and mean MYY. Returns the zeroth
%    moment M_0, mean M_1 and variance M_2 of the posterior
%    marginal (see Rasmussen and Williams (2006): Gaussian
%    processes for Machine Learning, page 55). This subfunction
%    is needed when using EP for inference with non-Gaussian
%    likelihoods.
%
%  See also
%    GPEP_E

 n  = size(y, 1);
 indClass = 1:size(z,2)==lik.classVariables;
 zi = z(:, indClass);
 z  = z(:, ~indClass);

 indj = unique(zi);
 nind = numel(indj);

 if n ~= numel(zi)
     error('row-length of y and z are different')
 end

 logM_0 = zeros(n, 1);
 m_1 = zeros(n, 1);
 sigm2hati1 = zeros(n, 1);

 for j = 1:nind
     likj = lik.liks{indj(j)};
     ind = zi==indj(j);
     if numel(sigm2_i)>1
         yj = y(ind);
         if isempty(z)
             zj = z;
         else
             zj = z(ind);
         end
         sigm2_ij = sigm2_i(ind);
         myy_ij = myy_i(ind);
         [logM_0(ind), m_1(ind), sigm2hati1(ind)] = ...
             likj.fh.tiltedMoments(likj, yj, 1:length(yj), sigm2_ij, myy_ij, zj);
     else
         if any(find(ind)==i1)
             [logM_0, m_1, sigm2hati1] = ...
                 likj.fh.tiltedMoments(likj, y, i1, sigm2_i, myy_i, z);
         end
     end

 end

end

function [g_i] = lik_liks_siteDeriv(lik, y, i1, sigm2_i, myy_i, z)
% LIK_LIKS_SITEDERIV  Evaluate the expectation of the gradient
%                 of the log likelihood term with respect
%                 to the multiple-likelihood parameters for EP
%
%  Description [M_0, M_1, M2] =
%    LIK_LIKS_SITEDERIV(LIK, Y, I, S2, MYY, Z) takes a
%    likelihood structure LIKS, incedence counts Y, expected
%    counts Z, index I and cavity variance S2 and mean MYY.
%    Returns E_f [d log p(y_i|f_i) /d a], where a is the
%    likelihood parameter and the expectation is over the
%    marginal posterior. This is done for all likelihoods.
%    This term is needed when evaluating the
%    gradients of the marginal likelihood estimate Z_EP with
%    respect to the likelihood parameters (see Seeger (2008):
%    Expectation propagation for exponential families). This
%    subfunction is needed when using EP for inference with
%    non-Gaussian likelihoods and there are likelihood parameters.
%
%  See also
%    GPEP_G

 n  = size(y, 1);
 indClass = 1:size(z,2)==lik.classVariables;
 zi = z(:, indClass);
 z  = z(:, ~indClass);

 indj = unique(zi);
 nind = numel(indj);

 if n ~= numel(zi)
     error('row-length of y and z are different')
 end

 nlikpar = length(lik.fh.pak(lik));
 g_i = zeros(1, nlikpar);
 aux = 0;

 for j = 1:nind
     if ~isempty(lik.liks{indj(j)}.fh.pak(lik.liks{indj(j)}))
         % auxiliar indexes for paramters
         aux = aux + 1;

         % indexes for that specific likelihood
         ind = find(zi==indj(j));
         likj = lik.liks{indj(j)};

         if any(ind == i1)
             % !!!! if some specific likelihood has more than one parameter this will not work
             g_i(1, aux) = likj.fh.siteDeriv(likj, y, i1, sigm2_i, myy_i, z);
         end
     end

 end

end

function [lpy, Ey, Vary] = lik_liks_predy(lik, Ef, Varf, yt, zt)
% LIK_LIKS_PREDY  Returns the predictive mean, variance and density of y
%
%  Description:
%    LPY = LIK_LIKS_PREDY(LIK, EF, VARF YT, ZT)
%    Returns logarithm of the predictive density PY of YT, that is
%    p(yt | zt) = \int p(yt | f, zt) p(f|y) df.
%    This requires the observations YT.
%    This subfunction is needed when computing posterior predictive
%    distributions for future observations.
%
%    [LPY, EY, VARY] = LIK_LIKS_PREDY(LIK, EF, VARF) takes a
%    likelihood structure LIK, posterior mean EF and posterior
%    Variance VARF of the latent variable and returns the
%    posterior predictive mean EY and variance VARY of the
%    observations related to the latent variables. This subfunction
%    is needed when computing posterior predictive distributions for
%    future observations.
%
%
%  See also:
%    GPLA_PRED, GPEP_PRED, GPMC_PRED1

% number of values to predict;
n = size(Ef, 1);
indClass = 1:size(zt,2)==lik.classVariables;
zi = zt(:, indClass);
zt  = zt(:, ~indClass);

% check some conditions
if ~issorted(zi)
    error('you need to give the class variable increasing downwards');
end

if max(zi) > lik.nliks
    error('more classes than the number of classes you are trying to model');
end

% getting the information of the classes in the data
indj = unique(zi);
nind = numel(indj);

% log-density
lpy = zeros(n, 1);
if nargout > 1
    Ey = zeros(n, 1);
    Vary = zeros(n, 1);

    for j = 1:nind
        ind = zi==indj(j);
        likj = lik.liks{indj(j)};

        if numel(yt) ~= 0
           [lpy(ind), Ey(ind), Vary(ind)] = ...
           likj.fh.predy(likj, Ef(ind), Varf(ind), yt(ind), zt(ind));
        else
           [~, Ey(ind), Vary(ind)] = likj.fh.predy(likj, Ef(ind), Varf(ind), yt, zt(ind));
        end
    end
else
    for j = 1:nind
        ind = zi==indj(j);
        likj = lik.liks{indj(j)};

        if isempty(zt)
            lpy(ind) = likj.fh.predy(likj, Ef(ind), Varf(ind), yt(ind), []);
        else
            lpy(ind) = likj.fh.predy(likj, Ef(ind), Varf(ind), yt(ind), zt(ind));
        end
    end
end

end

function mu = lik_liks_invlink(lik, f, z)
%LIK_LIKS_INVLINK  Returns values of inverse link function
%
%  Description
%    P = LIK_LIKS_INVLINK(LIK, F) takes a likelihood structure LIK and
%    latent values F and returns the values MU of inverse link function.
%    This subfunction is needed when using gp_predprctmu.
%
%     See also
%     LIK_POISSON_LL, LIK_POISSON_PREDY

 n  = size(f, 1);
 indClass = 1:size(z,2)==lik.classVariables;
 zi = z(:, indClass);
 z  = z(:, ~indClass);

 indj = unique(zi);
 nind = numel(indj);

 if n ~= size(zi,1)
     error('row-length of f and z are different')
 end

 for j = 1:nind
     likj = lik.liks{indj(j)};
     ind = zi==indj(j);
     fj = f(ind,:);
     if isempty(z)
         zj = z;
     else
         zj = z(ind);
     end

     mu(ind,:) = likj.fh.invlink(likj, fj, zj);
 end

end

function reclik = lik_liks_recappend(reclik, ri, lik)
% RECAPPEND Append the parameters to the record
%
%  Description:
%    RECLIK = LIK_LIKS_RECAPPEND(RECLIK, RI, LIK) takes a
%    likelihood record structure RECLIK, record index RI and
%    likelihood structure LIK with the current MCMC samples of
%    the parameters. Returns RECLIK which contains all the old
%    samples and the current samples from LIK. This subfunction
%    is needed when using MCMC sampling (gp_mc).
%
%  See also:
%    GP_MC

 if nargin == 2
     % Initialize the record
     reclik.type = 'Liks';

     % Initialize parameters
     nliks = length(ri.liks);
     for i = 1:nliks
         lik_i = ri.liks{i};
         reclik.liks{i} = lik_i.fh.recappend([], ri.liks{i});
     end

     % Set the function handles
     reclik.fh.pak = @lik_liks_pak;
     reclik.fh.unpak = @lik_liks_unpak;
     reclik.fh.lp = @lik_liks_lp;
     reclik.fh.lpg = @lik_liks_lpg;
     reclik.fh.ll = @lik_liks_ll;
     reclik.fh.llg = @lik_liks_llg;
     reclik.fh.llg2 = @lik_liks_llg2;
     reclik.fh.llg3 = @lik_liks_llg3;
     reclik.fh.tiltedMoments = @lik_liks_tiltedMoments;
     reclik.fh.siteDeriv = @lik_liks_siteDeriv;
     reclik.fh.predy = @lik_liks_predy;
     reclik.fh.recappend = @lik_liks_recappend;

     if isfield(ri, 'classVariables')
         reclik.classVariables = ri.classVariables;
         reclik.nliks = ri.nliks;
     end

 else
     % Append to the record
     % Loop over all of the likelihood functions
     nliks = length(lik.liks);
     for i = 1:nliks;
         lik_i = lik.liks{i};
         reclik.liks{i} = lik_i.fh.recappend(reclik.liks{i}, ri, lik_i);
     end

 end
end


%   AUTHORSHIP
%   Primary Developer: Stephen Meehan <swmeehan@stanford.edu>
%   Math Lead & Secondary Developer:  Connor Meehan <connor.gw.meehan@gmail.com>
%   Bioinformatics Lead:  Wayne Moore <wmoore@stanford.edu>
%   Provided by the Herzenberg Lab at Stanford University
%   License: BSD 3 clause
%

classdef UMAP_extra_results < handle
    properties
        supervisorMatchedLabels;
                        %vector of labels matched from a supervised template
                        % 1 value per row of input data matrix
        fig;            % main figure with UMAP output plot
        qft;            % instance of qf tree object for input data.
                        % The fig property contains the view of the tree.
        qftSupervisors; % instance of qf tree object for supervisor data.
                        % The fig property
                        % contains the view of the tree.
        qfd={};         % array qf QFTable instances.
                        % The function getAverages summarizes the result.
                        % Relevant figure properties are fig for table view,
                        % qHistFig for view of dismilarity score histogram
                        % fHistFig for view of f measure histogram
       matchHtmlHead1;
       matchHtmlHead2;
       matchHtmlHead3;
       matchHtmlBody;
       matchCsvHead;
       matchCsvBody;
       falsePosNegFile;
       falsePosNegHead;
       falsePosNegBody='';
       app;
       htmlFile;
       csvFile;
       args;
    end

    methods

        function closeMatchFigs(this)
            N=length(this.qfd);
            for i=1:N
                this.qfd{i}.closeFigs;
            end
        end

        function closeTreeFigs(this)
            if ~isempty(this.qft)
                Gui.CloseFig(this.qft.fig);
            end
            if ~isempty(this.qftSupervisors)
                Gui.CloseFig(this.qftSupervisors.fig);
            end
        end

        function avgs=getMatchAverages(this)
            N=length(this.qfd);
            avgs=[];
            for i=1:N
                qf=this.qfd{i};
                [medianDissimilarity, meanDissimilarity, ...
                    medianOverlap, meanOverlap]=qf.getAverages;
                avgs(end+1,:)=[medianDissimilarity meanDissimilarity...
                    medianOverlap meanOverlap];
            end
        end

        function fig=seeFalsePosNeg(this)
            if ~isempty(this.falsePosNegFile) && ~isempty(this.falsePosNegHead)
                File.SaveTextFile(this.falsePosNegFile, ...
                    [this.falsePosNegHead this.falsePosNegBody])
                [fig, that]=FalsePositiveNegative.Plot([0 1], ...
                    this.falsePosNegFile);
                that.fcnMoreHtml=@()getFalsePosNegMatrixHtml(this);
            else
                fig=[];
            end
        end

        function saveMatchFiles(this, h1)
            if nargin<2
                h1='';
            end
            if ~isempty(this.csvFile) && ~isempty(this.matchCsvHead)
                File.SaveTextFile(this.csvFile, [this.matchCsvHead ...
                    this.matchCsvBody])
            end
            if ~isempty(this.falsePosNegFile) && ~isempty(this.falsePosNegHead)
                File.SaveTextFile(this.falsePosNegFile, ...
                    [this.falsePosNegHead this.falsePosNegBody])
            end
            if ~isempty(this.htmlFile) && ~isempty(this.matchHtmlHead1)
                File.SaveTextFile(this.htmlFile, this.getMatchHtml(h1));
            end
        end

        function seeMatches(this, how, h1)
            if nargin<3
                h1='';
            end
            if how==-1
                msg(this.getMatchHtml(h1), 0, 'east++', ['Matches: '...
                    this.describeRedution ' reduction'], 'none')
            elseif how==1
                Html.BrowseString(this.getMatchHtml(h1));
            elseif how==2
                Html.BrowseFile(this.htmlFile);
            end
        end

        function this=UMAP_extra_results()
            this.app=BasicMap.Global;
        end

        function doMatchOutput(this, D)
            if ~isempty(this.qfd)
                this.doMatchHtmlHead(D);
                this.doMatchHtmlBody;
                this.doMatchCsv;
                this.doFalsePosNeg;
            end
        end

        function htmls=getFalsePosNegMatrixHtml(this)
            args_=this.args;
            qfds=this.qfd;
            N=length(qfds);
            if N<1 || isempty(find(args_.match_scenarios==4, 1))
                return;
            end
            reduction=args_.reduction;
            if ~isempty(args_.training_set)
                trainingSet=args_.training_set;
            elseif ischar(args_.template_file)
                [~,fn]=fileparts(args_.template_file);
                trainingSet=fn;
            else
                trainingSet='';
            end
            if ~isempty(args_.test_set)
                testSet=args_.test_set;
            elseif ischar(args_.csv_file_or_data)
                [sampleFldr,fn]=fileparts(args_.csv_file_or_data);
                testSet=fn;
            else
                testSet='';
            end
            if ~isempty(args_.sample_set)
                sampleSet=args_.sample_set;
            elseif exist('sampleFldr', 'var')
                [~, sampleSet]=fileparts(sampleFldr);
            else
                sampleSet='';
            end
            htmls=cell(1,N);
            for i=1:N
                qt=qfds{i};
                N2=length(qt.qf.falsePosNegs);
                if N2>0
                    mt=qt.context.matchType;
                    cd=qt.context.clusterDetail;
                    cd=StringArray.IndexOf(Density.DETAILS, cd);
                    htmls{i}=FalsePositiveNegative.MatrixHtml(qt.qf);
                end
            end
        end

        function doFalsePosNeg(this, doPlotNow)
            args_=this.args;
            qfds=this.qfd;
            N=length(qfds);
            if N<1 || isempty(find(args_.match_scenarios==4, 1))
                return;
            end
            fullBody=this.falsePosNegBody;
            this.falsePosNegFile=[UMAP_extra_results.FileName(...
                args_, 'falsePosNeg') '.txt'];
            reduction=args_.reduction;
            if ~isempty(args_.training_set)
                trainingSet=args_.training_set;
            elseif ischar(args_.template_file)
                [~,fn]=fileparts(args_.template_file);
                trainingSet=fn;
            else
                trainingSet='';
            end
            if ~isempty(args_.test_set)
                testSet=args_.test_set;
            elseif ischar(args_.csv_file_or_data)
                [sampleFldr,fn]=fileparts(args_.csv_file_or_data);
                testSet=fn;
            else
                testSet='';
            end
            if ~isempty(args_.sample_set)
                sampleSet=args_.sample_set;
            elseif exist('sampleFldr', 'var')
                [~, sampleSet]=fileparts(sampleFldr);
            else
                sampleSet='';
            end
            for i=1:N
                qt=qfds{i};
                N2=length(qt.qf.falsePosNegs);
                if N2>0
                    mt=qt.context.matchType;
                    cd=qt.context.clusterDetail;
                    cd=StringArray.IndexOf(Density.DETAILS, cd);
                    [body, notFound]=FalsePositiveNegative.TabRows(...
                        qt.qf.falsePosNegs, reduction, sampleSet, ...
                        trainingSet, testSet, args_.n_neighbors, ...
                        args_.hiD, args_.n_components, mt, cd);
                    if ~isempty(notFound)
                        body=[body newline notFound];
                    end
                    fullBody=[fullBody body newline];
                end
            end
            this.falsePosNegHead=FalsePositiveNegative.TabHead;
            this.falsePosNegBody=fullBody;
            if nargin>1 && doPlotNow
                this.seeFalsePosNeg;
            end
        end

        function html=getMatchHtml(this, h1)
            if nargin<2
                h1='';
            end
            html=['' h1 '

' ...
                '
' this.matchHtmlHead1 '
' ...
                '
' this.matchHtmlHead2 '
' ...
                '
' this.matchHtmlHead3 '

'...
                '
' this.matchHtmlBody '
'...
                '
'];
        end

        function s=describeRedution(this)
            s=UmapUtil.GetReductionLongText(this.args.reductionType);
        end

        function records=getFalsePosNeg(this, verbose)
            N=length(this.qfd);
            records={};
            for i=1:N
                qf=this.qfd{i};
                N2=length(qf.qf.falsePosNegs);
                if N2>0
                    if nargin>1 && verbose
                        for j=1:N2
                            record=qf.qf.falsePosNegs{j};
                            fprintf(['#%d "%s"; false pos=%s '...
                                'false neg=%s; match 1 x %d\n'], ...
                                j, record.trainingClass, ...
                                String.encodePercent(record.falsePos, ...
                                record.testSize, 2), ...
                                String.encodePercent(record.falseNeg, ...
                                record.trainingSize, 2), ...
                                length(record.testIds));
                        end
                    end
                    records=[records qf.qf.falsePosNegs];
                end
            end
        end
    end

    methods(Access=private)
        function doMatchHtmlHead(this, D)
            args_=this.args;
            nMatchTypes=length(args_.match_supervisors);
            nMatchScenarios=length(args_.match_scenarios);
            if any(args_.match_scenarios==1)
                nUstMatches=nMatchScenarios-1;
            else
                nUstMatches=nMatchScenarios;
            end
            this.htmlFile=[UMAP_extra_results.FileName(args_) '.html'] ;
            colspan=['colspan="' num2str(nUstMatches*3) '"'];
            if isempty(args_.description)
                htmlDsc='	';
            else
                htmlDsc='Context	';
            end
            sm1=this.app.smallStart;
            sm2=this.app.smallEnd;
            html1='';
            html2='';
            html3='';
            has1=false;
            cluDtls=args_.cluster_detail;
            nCluDtls=length(cluDtls);
            if length(args_.ust_test_components)>1
                loD=[];
            else
                loD=args_.n_components;
            end
            for c=1:nCluDtls
                for i=1:nMatchTypes
                    matchType=args_.match_supervisors(i);
                    if c>1
                        if matchType>=3 % nearest neighbor no clustering
                            continue;
                        end
                    end
                    mt=UmapUtil.GetMatchTypeLongText(matchType, ...
                        args_.reductionType, loD, D);
                    if matchType<3
                        mt=[mt ' ' cluDtls{c}];
                    end
                    html1=[html1 '' mt '	'];
                    for j=1:nMatchScenarios
                        scenario=args_.match_scenarios(j);
                        sc=UmapUtil.GetMatchScenarioText(scenario, args_.reductionType) ;
                        if scenario==1
                            if ~has1
                                has1=true;
                                html1_1=['Prior
'...
                                    sm1 'classifications' sm2 '	' ];
                                html2_1=['' sc '
' ...
                                    sm1 'Dissimilarity' sm2 '	'];
                                html3_1='Unmatched	Median	Mean	';
                            end
                        else
                            if scenario==4
                                htmlStat=['
' sm1 'Overlap' sm2];
                            else
                                htmlStat=['
' sm1 'Dissimilarity' sm2];
                            end
                            html2=[html2 '' sc htmlStat '	' ];
                            html3=[html3 'Unmatched	Median	Mean	'];
                        end
                    end
                end
            end
            if has1
                if nUstMatches>0
                    this.matchHtmlHead1=[htmlDsc html1_1  html1];
                    this.matchHtmlHead2=['	' html2_1 html2];
                    this.matchHtmlHead3=['	' html3_1 html3];
                else
                    this.matchHtmlHead1=[htmlDsc html1_1];
                    this.matchHtmlHead2=['	' html2_1];
                    this.matchHtmlHead3=['	' html3_1];
                end
            else
                this.matchHtmlHead1=[htmlDsc html1];
                this.matchHtmlHead2=['	'  html2];
                this.matchHtmlHead3=['	' html3];
            end
        end

        function doMatchHtmlBody(this)
            args_=this.args;
            qfds=this.qfd;
            dsc=args_.description;
            td='';
            td_='	';
            N_=length(qfds);
            htmlDsc=['' dsc td_];
            html='';
            mdn=zeros(1, N_);
            mn=zeros(1,N_);
            adjMdn=zeros(1, N_);
            adjMn=zeros(1,N_);
            matchRate=zeros(1,N_);
            matches=cell(1, N_);
            scenarios=zeros(1,N_);
            isDis=true(1, N_);
            for i=1:N_
                qf=qfds{i};
                matchStrategy=qf.context.matchStrategy;
                [tUnmatched, tN, sUnmatched, sN]=qf.getMatchCounts;
                matches{i}=sprintf('%d/%d, %d/%d', tUnmatched, tN,...
                    sUnmatched, sN);
                if matchStrategy==1
                    scenarios(i)=qf.context.matchScenario;
                    [~,mdn(i), mn(i)]=qf.getData(true);
                else
                    scenarios(i)=4;
                    [~,mdn(i), mn(i)]=qf.getData(false);
                    isDis(i)=false;
                end
                tM=tN-tUnmatched;
                sM=sN-sUnmatched;
                matchedSubsetCnt=tM+sM;
                subsetCnt=tN+sN;

                if tUnmatched>0 || sUnmatched>0
                    if matchStrategy==1
                        addDs=(tUnmatched+sUnmatched)*100;
                        adjMdn(i)=(matchedSubsetCnt*mdn(i)+addDs)/subsetCnt;
                        adjMn(i)=(matchedSubsetCnt*mn(i)+addDs)/subsetCnt;
                    else
                        adjMdn(i)=matchedSubsetCnt*mdn(i)/subsetCnt;
                        adjMn(i)=matchedSubsetCnt*mn(i)/subsetCnt;
                    end
                else
                    adjMdn(i)=mdn(i);
                    adjMn(i)=mn(i);
                end
                matchRate(i)=matchedSubsetCnt/subsetCnt;
            end
            usc=unique(scenarios);
            nSc=length(usc);
            bestMedian=zeros(1, 4);
            bestMean=zeros(1, 4);
            bestMatches=zeros(1,4);
            worstMatches=zeros(1,4);
            for i=1:nSc
                u=usc(i);
                if u==4
                    bestMedian(u)=max(adjMdn(scenarios==u));
                    bestMean(u)=max(adjMn(scenarios==u));
                else
                    bestMedian(u)=min(adjMdn(scenarios==u));
                    bestMean(u)=min(adjMn(scenarios==u));
                end
                bestMatches(u)=max(matchRate(scenarios==u));
                worstMatches(u)=min(matchRate(scenarios==u));
            end
            has1=false;
            for i=1:N_
                scenario=scenarios(i);
                sMdn=String.encodeRounded(mdn(i), 1, true);
                sMn=String.encodeRounded(mn(i), 1, true);
                match=matches{i};
                ms1='';
                ms2='';

                if scenario>1
                    if matchRate(i)==bestMatches(scenario)
                        ms1='';
                        ms2='';
                    elseif matchRate(i)==worstMatches(scenario)
                        ms1='';
                        ms2='';
                    end
                end
                if scenario>1 && adjMdn(i)==bestMedian(scenario)
                    s1='';
                    s2='';
                else
                    s1='';
                    s2='';
                end
                if scenario==1
                    html1=[td ms1 match ms2 td_ td s1 sMdn  s2 td_];
                else
                    html=[html td ms1 match ms2 td_ td s1 sMdn  s2 td_];
                end
                if scenario>1 && adjMn(i)==bestMean(scenario)
                    s1='';
                    s2='';
                else
                    s1='';
                    s2='';
                end
                if scenario==1
                    has1=true;
                    html_1=[html1 td s1 sMn s2 td_ ];
                else
                    html=[html td s1 sMn s2 td_ ];
                end
            end
            if has1
                html=[htmlDsc html_1 html];
            else
                html=[htmlDsc html];
            end
            this.matchHtmlBody=html;
        end

        function doMatchCsv(this)
            args_=this.args;
            qfds=this.qfd;
            N=length(qfds);
            if N>0
                this.csvFile=[UMAP_extra_results.FileName(args_) '.csv'] ;
                lf=newline;
                this.matchCsvHead=[ StringArray.toString(fieldnames(...
                    qfds{1}.context), ',') 'trainingUnmatched,'...
                    'trainingSubsets,testUnMatched,testSubsets,'...
                    'median,mean' lf];
                csv='';
                for i=1:N
                    qf=qfds{i};
                    [tUnmatched, tN, sUnmatched, sN]=qf.getMatchCounts;

                    if qf.context.matchStrategy==1
                        [~,mdn, mn]=qf.getData(true);
                    else
                        [~,mdn, mn]=qf.getData(false);
                    end
                    csv=[csv String.toString(qf.context) ...
                        num2str(tUnmatched) ',' num2str(tN) ',' ...
                        num2str(sUnmatched) ',' num2str(sN) ',' ...
                        num2str(mdn) ',' num2str(mn) ',' lf];
                end
                this.matchCsvBody=csv;
            end
        end
    end

    methods(Static)
        function file=FileName(args, prefix)
            if nargin<2
                prefix='match';
            end
            if isfield(args, [prefix '_file'])
                fn=getfield(args, [prefix '_file']);
            else
                fn='';
            end
            if isempty(fn)
                strMatchTypes=strrep(strrep(num2str(...
                    args.match_supervisors), ' ', '_'), '__', '_');
                strMatchScenarios=strrep(strrep(num2str(...
                    args.match_scenarios), ' ', '_'), '__', '_');
                fn=[prefix '_' strMatchTypes...
                    '_for_' strMatchScenarios ];
            end
            file=fullfile(args.result_folder, fn);
            File.mkDir(args.result_folder);
        end
    end
end


function testing(video)

disp(video);

previousMethod = 'MSCNN'; % BasicCNN or MSCNN

load(fullfile([previousMethod 'net/'], video, 'net-epoch-20'));
net.layers{end} = struct('name', 'data_hat_sigmoid', ...
    'type', 'sigmoid');
net = vl_simplenn_move(net,'gpu');

load meanPixel;
meanPixel(:,:,4) =0;

half_size = 15;

imgDir = ['../SBMIDataset/' video '/input'];
resDir = fullfile([previousMethod '-result'], video);

grayDir = ['../' previousMethod '/result/', video];

mkdir(resDir);
images = [dir([imgDir '/*.jpg']); dir([imgDir '/*.png'])];
grayimages = dir(fullfile(grayDir, '*.png'));

for kk = 1 : numel(images)
    %fprintf('%d\n', kk);
    imagename = images(kk).name;
    grayname = grayimages(kk).name;
    im = single(imread(fullfile(imgDir, imagename)));
    if size(im,1) > 400 || size(im,2) > 400
        im = imresize(im, 0.5, 'nearest');
    end

    im(:,:,4) = single(imread(fullfile(grayDir, grayname)));

    im_large = padarray(im, [half_size, half_size], 'symmetric');
    im_large = bsxfun(@minus, im_large, meanPixel);
    im_large = gpuArray(im_large);

    %     tic;
    A = vl_simplenn(net, im_large);
    B = gather(A(end).x);

    %     toc;

    map_im = uint8(B * 255);
    imwrite(map_im, fullfile(resDir, imagename));
end


function model_wrl = GB_read_vrml_fast_BA(filename)
% BA: I created this for single output as structure

MIMICS_10_KEY = '#coordinates written in 1mm / 10000';
MIMICS_13_KEY = '#coordinates written in 1mm / 0';

fid = fopen(filename, 'r');
if (fid == -1)
    fprintf(1, '\aError: unable to open input IV file %s.\n',filename);
    return,
end;

input = fscanf(fid,'%c');
fclose(fid);

% so now lets find the middle points section
if ~isempty(regexpi(input,'(.*)texCoord(.*)')) % Bardiya Added this, in case the model has texture in it
    tokens = regexpi(input,'(.*)point\s+(.*)point\s+\[([^\]]*)\](.*)coordIndex\s+\[([\d\s\,\n\r\.-]*)\](.*)','tokens');
    %now lets get the points
    last_ind = strfind(tokens{1}{2},']');
    pts = sscanf(tokens{1}{2}(2:last_ind-1),'%f %f %f,',[3 inf])';
    connects = sscanf(tokens{1}{5},'%d, %d, %d, %d,',[4 inf])';
else
    tokens = regexpi(input,'(.*)point\s+\[([^\]]*)\](.*)coordIndex\s+\[([\d\s\,\n\r\.-]*)\](.*)','tokens');
    %now lets get the points
    pts = sscanf(tokens{1}{2},'%f %f %f,',[3 inf])';
    connects = sscanf(tokens{1}{4},'%d, %d, %d, %d,',[4 inf])';
end

% tokens = regexpi(input,'(.*)texCoord(.*)');

%check for the way mimics 10, outputs pts
if (isempty(pts)),
    tok = regexp(tokens{1}{2},'^[\s]*#[^\r\n]*(.*)','tokens');
    pts = sscanf(tok{1}{1},'%f %f %f,',[3 inf])';
end;

%check for alternate format, with no commas between the numbers, just at
%the end of the row
if (size(connects,1)==1 && size(connects,2)==1),
    connects = sscanf(tokens{1}{4},'%d %d %d %d',[4 inf])';
end;

%% Look for scale
scale = [1 1 1];

%check in headers
for i=[1 3 5],
    scaleToken = regexpi(tokens{1}{i} ,'scale\s+([\d\.]+)\s+([\d\.]+)\s+([\d\.]+)','tokens');
    if (size(scaleToken,1)>0),
        scale = str2double(scaleToken{1,1});
    end;
end;

%if our scale is not exactly [1 1 1]
if (sum(scale~=1)>0),
    for i=1:3,
        pts(:,i) = pts(:,i)*scale(i);
    end;
end;

% check for the existance of the mimics 10 or 13 key, if so, the output was
% in m, and must be converted to mm
if (~isempty(strfind(input,MIMICS_10_KEY)) || ~isempty(strfind(input,MIMICS_13_KEY)))
    pts = pts .* 1000;
end;

%% BA Output
if abs(mean(mean(abs(pts)))) < 0.5
    disp('Converting Units: m to mm');
    pts = pts.*1e3;
end

model_wrl.pts = pts;
model_wrl.conn = connects;


function [powerterms_MR,powerterms_RZF,powerterms_MMMSE] = functionComputeULPowerLevels_impairments(H,Hhat,C,nbrOfRealizations,M,K,L,p,f,kappatUE,kapparBS)
%Compute and categorize the UL signal power for different receive combining
%schemes, under hardware impairments.
%
%INPUT:
%H                 = M x nbrOfRealizations x K x L x L matrix with the
%                    exact channel realizations
%Hhat              = M x nbrOfRealizations x K x L x L matrix with the MMSE
%                    channel estimates
%C                 = M x M x K x L x L matrix with estimation error
%                    correlation matrices when using MMSE estimation.
%nbrOfRealizations = Number of channel realizations
%M                 = Number of antennas per BS
%K                 = Number of UEs per cell
%L                 = Number of BSs and cells
%p                 = Uplink transmit power per UE (same for everyone)
%f                 = Pilot reuse factor
%kappatUE          = Hardware quality of the UEs' transmitters
%kapparBS          = Hardware quality of the BSs' receivers
%
%OUTPUT:
%powerterms_MR    = 6 x K x L matrix with signal and interference powers
%                   for each of the UEs with MR combining.
%                   powerterms_MR(:,k,l) is the vector for UE k in cell l,
%                   where the first element is the average desired signal
%                   power, the second element is the interference from UEs
%                   having the same pilot, the third term is the
%                   interference from UEs having different pilots, the
%                   fourth term is the transmitter distortion from other
%                   UEs, the fifth term is the receiver distortion from all
%                   UEs, and the last term is the self-distortion/interference
%powerterms_RZF   = Same as powerterms_MR but with RZF combining
%powerterms_MMMSE = Same as powerterms_MR but with M-MMSE combining
%
%
%This Matlab function was developed to generate simulation results to:
%
%Emil Bjornson, Jakob Hoydis and Luca Sanguinetti (2017),
%"Massive MIMO Networks: Spectral, Energy, and Hardware Efficiency",
%Foundations and Trends in Signal Processing: Vol. 11, No. 3-4,
%pp. 154-655. DOI: 10.1561/2000000093.
%
%For further information, visit: https://www.massivemimobook.com
%
%This is version 1.0 (Last edited: 2017-11-04)
%
%License: This code is licensed under the GPLv2 license. If you in any way
%use this code for research that results in publications, please cite our
%monograph as described above.

%Store identity matrices of different sizes
eyeK = eye(K);
eyeM = eye(M);

%Generate pilot pattern
if f == 1

    pilotPattern = ones(L,1);

elseif f == 2 %Only works in the running example with its 16 BSs

    pilotPattern = kron(ones(2,1),[1; 2; 1; 2; 2; 1; 2; 1]);

elseif f == 4 %Only works in the running example with its 16 BSs

    pilotPattern = kron(ones(2,1),[1; 2; 1; 2; 3; 4; 3; 4]);

elseif f == 16 %Only works in the running example with its 16 BSs

    pilotPattern = (1:L)';

end

%Compute sum of all estimation error correlation matrices at every BS
C_totM = reshape(p*sum(sum(C,3),4),[M M L]);

%Prepare to store simulation results for the signal gains
signal_MR = zeros(K,L);
signal_RZF = zeros(K,L);
signal_MMMSE = zeros(K,L);

%Prepare to store simulation results for the norms of combining vectors
vectornorm_MR = zeros(K,L);
vectornorm_RZF = zeros(K,L);
vectornorm_MMMSE = zeros(K,L);

%Prepare to store simulation results for the sum of interference powers
interference_MR = zeros(K,L);
interference_RZF = zeros(K,L);
interference_MMMSE = zeros(K,L);

%Prepare to store simulation results for the sum of interference powers
%from UEs having the same pilot signals, including the user itself
reuseinterf_MR = zeros(K,L);
reuseinterf_RZF = zeros(K,L);
reuseinterf_MMMSE = zeros(K,L);

%Prepare to store simulation results for the self-interference power
selfinterf_MR = zeros(K,L);
selfinterf_RZF = zeros(K,L);
selfinterf_MMMSE = zeros(K,L);

%Prepare to store simulation results for the sum of receiver distortion
receiverdist_MR = zeros(K,L);
receiverdist_RZF = zeros(K,L);
receiverdist_MMMSE = zeros(K,L);

%% Go through all channel realizations
for n = 1:nbrOfRealizations

    %Go through all cells
    for j = 1:L

        %Extract channel realizations from all UEs to BS j
        Hallj = reshape(H(:,n,:,:,j),[M K*L]);

        %Extract channel estimate realizations from all UEs to BS j
        Hhatallj = reshape(Hhat(:,n,:,:,j),[M K*L]);

        %Extract cells that use same pilots as cell j
        groupMembers = find(pilotPattern==pilotPattern(j))';

        %Compute three different combining schemes
        V_MR = Hhatallj(:,K*(j-1)+1:K*j);
        V_RZF = p*V_MR/(p*(V_MR'*V_MR)+eyeK);
        V_MMMSE = p*(p*(Hhatallj*Hhatallj')+C_totM(:,:,j)+eyeM)\V_MR;

        %Go through all UEs in cell j
        for k = 1:K

            %Extract channel realizations from UEs that cause pilot
            %contamination to UE k in cell j
            HjkPC = reshape(H(:,n,k,groupMembers,j),[M length(groupMembers)]);

            %Extract channel from BS j to its k:th UE
            Hjk = H(:,n,k,j,j);

            %%MR combining
            w = V_MR(:,k)/norm(V_MR(:,k))^2; %Extract combining vector
            wrep = repmat(w,[1 K*L]);

            %Use Monte Carlo simulations to compute the expectations that
            %appear in the six different components in Section 6.3.3
            signal_MR(k,j) = signal_MR(k,j) + (w'*Hjk)/nbrOfRealizations;
            vectornorm_MR(k,j) = vectornorm_MR(k,j) + norm(w).^2/nbrOfRealizations;
            interference_MR(k,j) = interference_MR(k,j) + p*sum(abs(w'*Hallj).^2)/nbrOfRealizations;
            receiverdist_MR(k,j) = receiverdist_MR(k,j) + p*sum(sum(abs(wrep.*Hallj).^2,1))/nbrOfRealizations;
            reuseinterf_MR(k,j) = reuseinterf_MR(k,j) + p*sum(abs(w'*HjkPC).^2)/nbrOfRealizations;
            selfinterf_MR(k,j) = selfinterf_MR(k,j) + p*sum(abs(w'*Hjk).^2)/nbrOfRealizations;

            %%RZF combining
            w = V_RZF(:,k); %Extract combining vector
            wrep = repmat(w,[1 K*L]);

            %Use Monte Carlo simulations to compute the expectations that
            %appear in the six different components in Section 6.3.3
            signal_RZF(k,j) = signal_RZF(k,j) + (w'*Hjk)/nbrOfRealizations;
            vectornorm_RZF(k,j) = vectornorm_RZF(k,j) + norm(w).^2/nbrOfRealizations;
            interference_RZF(k,j) = interference_RZF(k,j) + p*sum(abs(w'*Hallj).^2)/nbrOfRealizations;
            receiverdist_RZF(k,j) = receiverdist_RZF(k,j) + p*sum(sum(abs(wrep.*Hallj).^2,1))/nbrOfRealizations;
            reuseinterf_RZF(k,j) = reuseinterf_RZF(k,j) + p*sum(abs(w'*HjkPC).^2)/nbrOfRealizations;
            selfinterf_RZF(k,j) = selfinterf_RZF(k,j) + p*sum(abs(w'*Hjk).^2)/nbrOfRealizations;

            %%MMMSE combining
            w = V_MMMSE(:,k); %Extract combining vector
            wrep = repmat(w,[1 K*L]);

            %Use Monte Carlo simulations to compute the expectations that
            %appear in the six different components in Section 6.3.3
            signal_MMMSE(k,j) = signal_MMMSE(k,j) + (w'*Hjk)/nbrOfRealizations;
            vectornorm_MMMSE(k,j) = vectornorm_MMMSE(k,j) + norm(w).^2/nbrOfRealizations;
            interference_MMMSE(k,j) = interference_MMMSE(k,j) + p*sum(abs(w'*Hallj).^2)/nbrOfRealizations;
            receiverdist_MMMSE(k,j) = receiverdist_MMMSE(k,j) + p*sum(sum(abs(wrep.*Hallj).^2,1))/nbrOfRealizations;
            reuseinterf_MMMSE(k,j) = reuseinterf_MMMSE(k,j) + p*sum(abs(w'*HjkPC).^2)/nbrOfRealizations;
            selfinterf_MMMSE(k,j) = selfinterf_MMMSE(k,j) + p*sum(abs(w'*Hjk).^2)/nbrOfRealizations;

        end

    end

end

%Set the normalized noise variance
sigma2 = 1;

%Compute the desired signal term, as described in Section 6.3.3
signalpower_MR = kappatUE*kapparBS*mean(mean(p*abs(signal_MR).^2./vectornorm_MR))/sigma2;
signalpower_RZF = kappatUE*kapparBS*mean(mean(p*abs(signal_RZF).^2./vectornorm_RZF))/sigma2;
signalpower_MMMSE = kappatUE*kapparBS*mean(mean(p*abs(signal_MMMSE).^2./vectornorm_MMMSE))/sigma2;

%Compute the interference from UEs having the same pilot, as described in
%Section 6.3.3
reuseinterference_MR = kappatUE*kapparBS*mean(mean((reuseinterf_MR-selfinterf_MR)./vectornorm_MR))/sigma2;
reuseinterference_RZF = kappatUE*kapparBS*mean(mean((reuseinterf_RZF-selfinterf_RZF)./vectornorm_RZF))/sigma2;
reuseinterference_MMMSE = kappatUE*kapparBS*mean(mean((reuseinterf_MMMSE-selfinterf_MMMSE)./vectornorm_MMMSE))/sigma2;

%Compute the interference from UEs having different pilots, as described in
%Section 6.3.3
noreuseinterference_MR = kappatUE*kapparBS*mean(mean((interference_MR-reuseinterf_MR)./vectornorm_MR))/sigma2;
noreuseinterference_RZF = kappatUE*kapparBS*mean(mean((interference_RZF-reuseinterf_RZF)./vectornorm_RZF))/sigma2;
noreuseinterference_MMMSE = kappatUE*kapparBS*mean(mean((interference_MMMSE-reuseinterf_MMMSE)./vectornorm_MMMSE))/sigma2;

%Compute the transmitter distortion from other UEs, as described in
%Section 6.3.3
transmitDistortion_MR = (1-kappatUE)*kapparBS*mean(mean((interference_MR-selfinterf_MR)./vectornorm_MR))/sigma2;
transmitDistortion_RZF = (1-kappatUE)*kapparBS*mean(mean((interference_RZF-selfinterf_RZF)./vectornorm_RZF))/sigma2;
transmitDistortion_MMMSE = (1-kappatUE)*kapparBS*mean(mean((interference_MMMSE-selfinterf_MMMSE)./vectornorm_MMMSE))/sigma2;

%Compute the receiver distortion from all UEs, as described in
%Section 6.3.3
receiverDistortion_MR = (1-kapparBS)*mean(mean(receiverdist_MR./vectornorm_MR))/sigma2;
receiverDistortion_RZF = (1-kapparBS)*mean(mean(receiverdist_RZF./vectornorm_RZF))/sigma2;
receiverDistortion_MMMSE = (1-kapparBS)*mean(mean(receiverdist_MMMSE./vectornorm_MMMSE))/sigma2;

%Compute the self-distortion and self-interference, as described in
%Section 6.3.3
selfinterference_MR = kapparBS*mean(mean((selfinterf_MR-kappatUE*p*abs(signal_MR).^2)./vectornorm_MR))/sigma2;
selfinterference_RZF = kapparBS*mean(mean((selfinterf_RZF-kappatUE*p*abs(signal_RZF).^2)./vectornorm_RZF))/sigma2;
selfinterference_MMMSE = kapparBS*mean(mean((selfinterf_MMMSE-kappatUE*p*abs(signal_MMMSE).^2)./vectornorm_MMMSE))/sigma2;

%Prepare to output the power values
powerterms_MR = [signalpower_MR reuseinterference_MR noreuseinterference_MR transmitDistortion_MR receiverDistortion_MR selfinterference_MR];
powerterms_RZF = [signalpower_RZF reuseinterference_RZF noreuseinterference_RZF transmitDistortion_RZF receiverDistortion_RZF selfinterference_RZF];
powerterms_MMMSE = [signalpower_MMMSE reuseinterference_MMMSE noreuseinterference_MMMSE transmitDistortion_MMMSE receiverDistortion_MMMSE selfinterference_MMMSE];


function [ cf_out ] = MotorImagery_pseudoOnline( eeg, eegFb, online )
%MOTORIMAGERY_PSEUDOONLINE Summary of this function goes here
%   Detailed explanation goes here
if ~isfield(online,'train'); error('training module is not exist'); end
if ~isfield(online,'apply'); error('applying module is not exist'); end
if ~isfield(online,'option'); disp('applying module is not exist');
    opt={
        'windowSize', '1000' % 1s
        'paradigm', 'MotorImagery'
        'Feedback','off'
        }; % default setting
    opt=opt_cellToStruct(online.option{:});
else
    opt=opt_cellToStruct(online.option{:});
end
if ~isfield(opt,'ite')  %iteration in while loop
    opt.ite='1';
end

in=eeg; %training
if isfield(online,'train')
    for k=1:length(online.train)
        myFun=str2func(online.train{k});
        switch online.train{k}
            case 'func_csp'
                [out CSP_W, CSP_D]= feval(myFun, in, online.train{k,2},0);
            case 'func_featureExtraction'
                out=feval(myFun, in, online.train{k,2},0);
            case 'classifier_trainClassifier'
                CF_PARAM=feval(myFun, in, online.train{k,2},0);
            otherwise
                out=feval(myFun, in, online.train{k,2},0);
        end
        in=out;
    end
end

time=func_getTimeMarker(eegFb, opt);
cf_out=zeros(1,time.ite);
% eegFb.x=eegFb.cnt;  eegFb=rmfield(eegFb, 'cnt'); %% change dat.cnt to dat.x
run=true;
while run,
%     str2num(opt.ite)
    [fbData]=func_getData(eegFb, time, opt); %opt for iteration++
    in=fbData;
    if isfield(online,'apply')
        for k=1:length(online.apply)
            myFun=str2func(online.apply{k});
            switch online.apply{k}
                case 'func_projection'
                    [out]=feval(myFun, in, CSP_W);
                case 'func_featureExtraction'
                    [out]=feval(myFun, in, online.apply{k,2},0);
                case 'classifier_applyClassifier'
                    [out]=feval(myFun, in, CF_PARAM,0);
                otherwise
                    out=feval(myFun, in, online.apply{k,2},0);
            end
            in=out;
        end
        cf_out(str2num(opt.ite))=in;
        if strcmp(opt.Feedback,'on')
        end
    else
        waring('online.apply is not exist');
    end
    if str2num(opt.ite) == time.ite
        run=false;
    end
    opt.ite=func_countInc(opt.ite);
end
end


function [FM, xf] = ft_preproc_online_filter_apply(FM, x)

% function [FM, xf] = ft_preproc_online_filter_apply(FM, x)
%
% Passes signal x (channels times samples) through the filter,
% returns updated filter model (delay states) and filtered signal.
%
% See also FT_PREPROC_ONLINE_FILTER_INIT

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

[dimX, numX] = size(x);

if dimX > numX
  % explicit algorithm - faster for many channels, 1 sample (=fMRI)
  xf = zeros(size(x));

  for k=1:numX;
    z_old = FM.z;
    z0 = x(:,k) - z_old*FM.A2;
    xf(:,k) = z_old * FM.B2 + z0*FM.B1;
    FM.z(:,2:end) = z_old(:,1:end-1);
    FM.z(:,1) = z0;
  end
else
  % use built-in MATLAB stuff - faster for many samples, few channels
  [xf, z] = filter(FM.B, FM.A, x, FM.z',2);
  FM.z = z';
end


function spm_bms_display_ROI (BMS,mask,method)
% display results from BMS in a region of interest (ROI)
% FORMAT spm_bms_display_ROI (BMS,mask,method)
%
% Input:
% BMS    - BMS.mat file
% mask   - region of interest image
% method - inference method (FFX or RFX)
%__________________________________________________________________________
% Copyright (C) 2009-2011 Wellcome Trust Centre for Neuroimaging

% Maria Joao Rosa
% $Id: spm_bms_display_ROI.m 5219 2013-01-29 17:07:07Z spm $

% Find graphics window
% -------------------------------------------------------------------------
Fgraph = spm_figure('GetWin','Graphics');

% Input
% -------------------------------------------------------------------------
if nargin<1
    BMS    = spm_select(1,'^BMS.mat$','select BMS.mat files');
end
if nargin<2
    mask   = spm_select(1,'image','select ROI file');
end
if nargin<3
    method = spm_input('Inference method',+1,'b','FFX|RFX',['ffx';'rfx']);
end

mask_image = spm_vol(mask);         % Mask image Vol

% Nb. of subjects and models
% -------------------------------------------------------------------------
if isfield(BMS.map,method)
   switch method
       case 'ffx'
            data   = BMS.map.ffx.data;
       case 'rfx'
            data   = BMS.map.rfx.data;
   end
else
  msgbox(sprintf('Error: no %s analysis in current BMS.mat!',method))
  return
end

nsubjs    = size(data,2);
nmodels   = size(data{1}(1).mod_map,1);
nsess     = size(data{1},2);

% Sort out log-evidence images dimensions
% -------------------------------------------------------------------------
Vol_models(1,1) = spm_vol(data{1}.mod_map(1));

first_vol       = Vol_models(1,1);
M               = first_vol{1}.mat;
DIM             = first_vol{1}.dim(1:3)';

xdim            = DIM(1);
ydim            = DIM(2);
zdim            = DIM(3);
[xords,yords]   = ndgrid(1:xdim,1:ydim);
xords           = xords(:)';
yords           = yords(:)';
I               = 1:xdim*ydim;
zords_init      = ones(1,xdim*ydim);

% Loop through data
% -------------------------------------------------------------------------
for i = 1:nmodels,
    for s = 1:nsubjs,
        for se = 1:nsess,
             Vol_models(s,i,se) = spm_vol(data{s}(se).mod_map(i));
        end
    end
end

log_ev_roi = zeros(nsubjs,nmodels);
nvox_total = 0;

% Loop through image slices
% -------------------------------------------------------------------------
for z = 1:zdim,

    j = NaN(xdim,ydim);                         % Init. image values

    zords   = z*zords_init;                     % Slice z
    xyz     = [xords(I); yords(I); zords(I)];   % Slice coordinates
    nVox    = size(xyz,2);                      % Nb. of voxels per slice

    % Voxels inside mask
    mask_xyz  = mask_image.mat\M*[xyz(:,1:nVox);ones(1,nVox)];
    gamma     = spm_get_data(mask_image,mask_xyz);
    b         = find(gamma>0.5);            % Voxels in the mask

    z_models        = NaN(nsubjs,nmodels,nVox);       % Data
    z_models(1,1,:) = spm_get_data(first_vol{1},xyz); % Data: all subs/mods
    non_nan         = find(~isnan(z_models(1,1,:)));  % Voxels ~NaN

    % Find voxels ~NaN and sum sessions
    % ---------------------------------------------------------------------
    for s = 1:nsubjs,
        for k = 1:nmodels,
                sum_tmp_data    = [];
            for ns = 1:nsess,
                tmp_data        = Vol_models(s,k,ns);
                sum_tmp_data    = [sum_tmp_data; spm_get_data(tmp_data{1},xyz)];
            end
                z_models(s,k,:) = sum(sum_tmp_data,1);
                non_nani        = find(~isnan(z_models(s,k,:)));
                non_nan         = intersect(non_nan,non_nani);
        end
    end

    % Voxels to be analysed
    non_nan = intersect(non_nan,b);
    Nvoxels = length(non_nan);

    if Nvoxels > 0

        nvox_total = nvox_total + Nvoxels;
        % Do BMS in all voxels of slice z
        for n = 1:Nvoxels,
            log_ev_tmp = z_models(:,:,non_nan(n));
            % Group BMS
            log_ev_roi = log_ev_roi + log_ev_tmp;

        end
    end
end % Loop over slices

% Method
% -------------------------------------------------------------------------
switch method

    % Fixed Effects
    % ---------------------------------------------------------------------
    case 'ffx',

        F    = sum(log_ev_roi) - min(log_ev_roi);
        i    = F < (max(F) - 32);
        P    = F;
        P(i) = max(F) - 32;
        P    = P - min(P);
        P    = exp(P);
        P    = P/sum(P);

        if  isfield(BMS.map,'ffx')

            % Bar plot
            figure(Fgraph);
            spm_results_ui('Clear',Fgraph);

            hvox   = axes('Position',[0.25 0.15 0.5 0.25],'Parent',...
                Fgraph,'Visible','off');

            bar(1:nmodels,P)
            set(gca,'XTick',1:nmodels)
            set(gca,'XTickLabel',1:nmodels)
            set(gca,'YLim',[0 1])
            ylabel('Posterior Model Probability','Fontsize',12)
            xlabel('Models','Fontsize',12)
            title({'Fixed-effects BMS';''},...
                'Fontsize',12);
            axis square
            grid on

            return

        else

            msgbox('Error: no FFX analysis in current BMS.mat!')
            return

        end

    % Random Effects
    % ---------------------------------------------------------------------
    case 'rfx',

        nsamps           = 1e3;
        [alpha,exp_r,xp] = spm_BMS(log_ev_roi,nsamps,0,0,1);

        if  isfield(BMS.map,'rfx')

            % Bar plots
            figure(Fgraph);
            spm_results_ui('Clear',Fgraph);

            hvox   = axes('Position',[0.55 0.18 0.30 0.20],'Parent',...
                    Fgraph,'Visible','off');

            bar(1:nmodels,xp)
            set(gca,'XTick',1:nmodels)
            set(gca,'XTickLabel',1:nmodels)
            set(gca,'YLim',[0 1])
            ylabel('Exceedance Probability','Fontsize',12)
            xlabel('Models','Fontsize',12)
            title({'Random-effects BMS';''},'Fontsize',12)
            axis square
            grid on

            hvox   = axes('Position',[0.16 0.18 0.30 0.20],'Parent',...
                    Fgraph,'Visible','off');

            bar(1:nmodels,exp_r)
            set(gca,'XTick',1:nmodels)
            set(gca,'XTickLabel',1:nmodels)
            set(gca,'YLim',[0 1])
            ylabel('Expected Posterior Probability','Fontsize',12)
            xlabel('Models','Fontsize',12)
            title({'Random-effects BMS';''},'Fontsize',12)
            axis square
            grid on

            return

        else

            msgbox('Error: no RFX analysis in current BMS.mat!')
            return

        end

end


function x = p19_start ( option, nvar )

%*****************************************************************************80
%
%% P19_START returns a starting point for problem 19.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer OPTION, the option index.
%
%    Input, integer NVAR, the number of variables.
%
%    Output, real X(NVAR), the starting point.
%
  x = [ ...
      0.00218216, ...
      0.03171126, ...
      0.00010562, ...
      0.48301846, ...
      0.48298250, ...
      0.41554567, ...
      0.14949595, ...
      0.43425476, ...
      0.00018983, ...
      0.00051379, ...
    207.02239583, ...
     22.97760417, ...
      1.00000000 ]';

  return
end


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

%EXTRACT_SST: Extract event SST (Start/Stop Times) between t1 and t2
%
%USAGE: sub_sst = extract_sst(sst,t1,t2,edge_mode)
%
%INPUTS: sst - Event Start/Stop Times [Nx2 array of numeric time values]
%        t1  - time value, extract 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('EXTRACT_SST: Too few input arguments')
elseif nargin > 4
   error('EXTRACT_SST: Too many input arguments')
end

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

%%
function sub_sst = EXTRACT_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 = [t1 sst(N1,2)];
   elseif strcmpi(edge_mode,'delete')
      first = [];
   elseif strcmpi(edge_mode,'keep')
      first = sst(N1,:);
   end
elseif P1 == 0
   first = sst(N1,:);
end

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

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