function [d,BMA,PEBs] = spm_dcm_bdc(GCMs,field,M,ynames,models,noplot)
% Compare datasets using DCM and PEB (Bayesian data comparison)
%
% Performs the following procedure:
%
% 1. Identifies the optimum reduced model (PEB) collapsed over datasets.
% 2. For each dataset, creates reduced GCMs based on the optimum model
%    above and estimates a per-dataset PEB model.
% 3. Computes a series of measures on each dataset's PEB model
%
% Inputs:
%
% GCMs   - {1 x ny} cell array of filenames, each of which is a GCM file.
% field  - {1 x nf} cell array of field names, e.g. {'A','B'}
% M      - (Optional) struct for configuring PEB. See spm_dcm_peb.m .
% M.gamma- (Optional) prior variance for switched off parameters when
%          automatically forming a model space for KL-over-models.
% M.bmr  - (Optional) if true, searches for an optimal model across all
%          datasets before performing BDC. If false, all parameters from
%          the DCM are included. [default: true];
% ynames - (Optional) {1 x ny} cell array of names for each dataset
% models - (Optional) model space to use for computing the information gain
%          over models. Accepts a nested cell array of parameter names, or
%          a binary matrix (models x parameters) with which parameters
%          to switch on or off in each model.
% noplot - (Optional) if true, does not show plots.
%
% ny = number of datasets, nf = number of DCM fields, nm = number of models
%
% Returns:
%
% d.precisions - [np x ny] Precision of each DCM parameter in each dataset
% d.dcm_negent - [1 x ny]  Negative entropy (certainty) of DCM parameters
% d.rfx_negent - [1 x ny]  Negative entropy (certainty) of the estimated
%                          between-subject variability
% d.complexity - [1 x ny]  Number of effective parameters in the model
% d.model_F    - [nm x ny] Free energy of each candidate model
% d.model_P    - [nm x ny] Posterior probability of each candidate model
% d.model_KL   - [1 x ny]  Ability to disriminate between similar models
%
% BMA        - Bayesian model average across all datasets
% PEBs       - [1 x ny] PEB for each dataset
%__________________________________________________________________________
% Copyright (C) 2018 Wellcome Trust Centre for Neuroimaging

% Peter Zeidman & Samira Kazan
% $Id: spm_dcm_bdc.m 7495 2018-11-22 15:52:07Z peter $

if nargin < 5
    models = [];
end

if nargin < 6
    noplot = false;
end

% Load and concatenate models across datasets
% -------------------------------------------------------------------------
GCM = {};
for i = 1:length(GCMs)
    if ischar(GCMs{i})
        gcm = load(GCMs{i});
        gcm = gcm.GCM;
    else
        gcm = GCMs{i};
    end

    GCM = [GCM; gcm(:,1)];
end

ns = size(gcm,1);   % Number of subjects
ny = length(GCMs);  % Number of datasets
nm = ns*ny;         % Number of DCMs

% Set defaults
% -------------------------------------------------------------------------
if nargin < 2 || isempty(field), field = {'B'}; end
if nargin < 3, M = []; end
if nargin < 4 || isempty(ynames)
    ynames = cell(1,ny);
    for i = 1:ny
        ynames{i} = sprintf('Dataset %d',i);
    end
end

if isempty(M)
    M       = struct();
    M.alpha = 1;
    M.beta  = 16;
    M.hE    = 0;
    M.hC    = 1/16;
    M.Q     = 'single';
    M.X     = ones(nm,1);
end

try
    bmr = M.bmr;
catch
    bmr = true;
end

try
    gamma = M.gamma;
catch
    gamma = 0; % Point null hypothesis
end

% Identify optimum model structure across all datasets
% -------------------------------------------------------------------------
if bmr
    % Perform PEB analysis
    PEB = spm_dcm_peb(GCM,M,field);

    % Prune full model
    BMA = spm_dcm_peb_bmc(PEB);

    % Identify disabled PEB parameters
    is_disabled = find(BMA.Pp < 1/1000);

    % Get indices of disabled parameters
    disabled_pidx = BMA.Pind(is_disabled);
else
    disabled_pidx = [];
    BMA = [];
end

% Estimate PEBs for each dataset using the optimal DCM structure from above
% -------------------------------------------------------------------------

% Update design matrix
M.X = ones(ns,1);

PEBs = {};
for i = 1:ny
    % Load dataset
    GCM = spm_dcm_load(GCMs{i});

    % Disable any parameters which were pruned from the PEB.
    rE = GCM{1}.M.pE;
    rC = GCM{1}.M.pC;
    for j = 1:length(disabled_pidx)
        rC(disabled_pidx(j),disabled_pidx(j)) = 0;
    end

    % Apply priors at DCM level
    GCM = spm_dcm_reduce(GCM, rE, rC);

    % Build PEB
    M.X = ones(size(GCM,1),1);
    PEBs{i} = spm_dcm_peb(GCM,M,field);

end

% Compute measures
% -------------------------------------------------------------------------
d = struct();
d.precisions = [];
d.dcm_negent = [];
d.rfx_negent = [];
d.complexity = [];

for i = 1:ny
    % Certainty about RFX
    d.rfx_negent(i) = -0.5 * spm_logdet(2 * pi * exp(1) * PEBs{i}.Ch);

    % Certainty about parameters
    d.dcm_negent(i) = -0.5 * spm_logdet(2 * pi * exp(1) * PEBs{i}.Cp);

    % Information gain (KL-divergence) over parameters
    qE    = PEBs{i}.Ep;    % Posterior expectations
    pE    = PEBs{i}.M.pE;  % Prior expectations
    qC    = PEBs{i}.Cp;    % Posterior covariance
    pC    = PEBs{i}.M.pC;  % Prior covariance

    d.complexity(i) = spm_kl_normal(qE,qC,pE,pC);
end

% Assess model discrimination
% -------------------------------------------------------------------------

% If no models are provided, enter an automatic mode where difficult to
% distinguish parameters are identified
is_automatic = isempty(models);

% Form a model space K with one row per model and one column per parameter
% where 1 = on and 0 = off.
if isempty(models)
    % Default: each parameter turned off individually
    np = length(PEBs{1}.Pnames);
    K  = ones(np, np);
    for i = 1:np
        K(i,i) = 0;
    end
elseif iscell(models) && ~isempty(models) && iscell(models{1})
    % Nested cell array of included fields
    Pnames = char(PEBs{1}.Pnames);

    K  = [];

    for m = 1:length(models)
        k = any(ismember(Pnames,models{m}),2);
        K(end+1,:) = k';
    end

    % Remove any models where parameters were provided but none was found
    % in the PEB.
    to_remove = ~cellfun(@isempty,models) & ~any(K,2);
    K(to_remove,:) = [];
elseif ismatrix(models)
    % Pre-defined matrix of parameters
    K = models;
else
    error('Unknown model specification');
end

% Calculate evidence for reduced models with each connection switched off
% Fs(m,i) is the free energy of the PEB model with parameter m disabled
% in dataset i.
Fs = []; % models x datasets
for i = 1:ny
    qE = PEBs{i}.Ep;
    qC = PEBs{i}.Cp;
    pE = PEBs{i}.M.pE;
    pC = PEBs{i}.M.pC;

    for m = 1:size(K,1)
        rE = pE;
        rC = pC;
        off = find(K(m,:) == 0);
        rC(off,off) = gamma;

        Fs(m,i) = spm_log_evidence_reduce(qE,qC,pE,pC,rE,rC);
    end
end

if is_automatic
    % Retain nr difficult to discriminate models
    i  = find(mean(Fs,2) > -3);
else
    % Retain them all
    i = 1:size(Fs,1);
end
nr = numel(i);

% Evidence -> probability
p  = spm_softmax(Fs(i,:));

% KL divergence (information gain)
d.model_KL = sum(p.*log(p)) + log(nr);

d.model_F = Fs;
d.model_P = p;

% Get PEB parameter precisions for each dataset
% -------------------------------------------------------------------------
for i = 1:ny
    d.precisions(:,i) = diag(spm_inv(PEBs{i}.Cp));
end

if noplot
    return;
end

% Plot PEB parameters for each dataset
% -------------------------------------------------------------------------
spm_figure('GetWin','Datasets');
rows = max(ceil(ny / 2),3);
cols = 2;

for i = 1:ny
    subplot(rows,cols,i);
    spm_plot_ci(PEBs{i}.Ep,PEBs{i}.Cp);
    title(ynames{i},'FontSize',16);
    xlabel('PEB Parameter','FontSize',12);
    ylabel('Estimate','FontSize',12);
    ylim([-2 2]);
end

% Plot measures
% -------------------------------------------------------------------------
spm_figure('GetWin','Data Comparison');
spm_clf;
rows = 3; cols = 2;

subplot(rows,cols,1:2);
bar(d.precisions);
title('Parameter certainty','FontSize',16);
xlabel('Parameter','FontSize',12); ylabel('Precision','FontSize',12);
legend(ynames,'Location','South','Orientation','horizontal','FontSize',12);

subplot(rows,cols,3);
y = d.dcm_negent - min(d.dcm_negent);
bar(y);
hold on; p = scatter(1:length(y),y); set(p,'visible','off'); hold off
title('Parameter certainty','FontSize',16);
xlabel('Dataset','FontSize',12); ylabel('Relative neg entropy (nats)','FontSize',12);

subplot(rows,cols,4);
y = d.rfx_negent - min(d.rfx_negent);
bar(y);
hold on; p = scatter(1:length(y),y); set(p,'visible','off'); hold off
title('RFX certainty','FontSize',16);
xlabel('Dataset','FontSize',12); ylabel('Relative neg entropy (nats)','FontSize',12);

subplot(rows,cols,5);
y = d.complexity-min(d.complexity);
bar(y);
hold on; p = scatter(1:length(y),y); set(p,'visible','off'); hold off
title('Information gain (parameters)','FontSize',14);
xlabel('Dataset','FontSize',12); ylabel('Relative neg entropy (nats)','FontSize',12);

subplot(rows,cols,6);
y = d.model_KL;
bar(y);
hold on; p = scatter(1:length(y),y); set(p,'visible','off'); hold off
title(sprintf('Information gain (%d models)',nr),'FontSize',14);
xlabel('Dataset','FontSize',12); ylabel('Entropy (nats)','FontSize',12);


function h = m_annotation( varargin )
% M_ANNOTATION Creates an annotation object
%   M_ANNOTATION Generally passes its arguments through to ANNOTATION,
%   bur accepts lon/lat arguments.
%
%   ANNOTATION(ANNOTATIONTYPE) creates a default annotation of type
%   ANNOTATIONTYPE in the current figure.  ANNOTATIONTYPE may be one of the
%   following:
%       'rectangle'
%       'ellipse'
%       'textbox'
%       'line'
%       'arrow'
%       'doublearrow' = two headed arrow
%       'textarrow' = arrow with text at tail end
%
%   ANNOTATION('rectangle',POSITION) creates a rectangle annotation at the
%   position specified in normalized figure units by the vector POSITION
%   ANNOTATION('ellipse',POSITION) creates an ellise annotation at the
%   position specified in normalized figure units by the vector POSITION
%   ANNOTATION('textbox',POSITION) creates a textbox annotation at the
%   position specified in normalized figure units by the vector POSITION
%
%   POSTITION = [LON_LEFT LAT_BOTTOM WIDTH HEIGHT] where WIDTH and HEIGHT
%   are normalized to the size of the axis.
%
%   ANNOTATION('line',LON,LAT) creates a line annotation with endpoints
%   specified in normalized figure coordinates by the vectors LON and LAT
%   ANNOTATION('arrow',LON,LAT) creates an arrow annotation with endpoints
%   specified in normalized figure coordinates by the vectors LON and LAT.
%   LON(1) and LAT(1) specify the position of the tail end of the arrow
%   and LON(2) and LAT(2) specify the position at the tip of the arrow head.
%   ANNOTATION('doublearrow',LON,LAT) creates a doublearrow annotation with
%   endpoints specified in normalized figure coordinates by the vectors LON
%   and LAT.
%   ANNOTATION('textarrow',LON,LAT) creates a textarrow annotation with
%   endpoints specified in normalized figure coordinates by the vectors LON
%   and LAT. LON(1) and LAT(1) specify the position of the tail end of the
%   arrow and LON(2) and LAT(2) specify the position at the tip of the arrow
%   head.
%
%   You should (optionally) call ORIENT first, and then WYSIWYG to see how
%   the printed version will look, because otherwise the location of the
%   annotation may not look right.
%
%   M_ANNOTATION(HANDLE,...) creates the annotation in the  AXES specified
%   by HANDLE (note - ANNOTATION requires a FIGURE handle)
%
%   H=M_ANNOTATION(...) returns a handle to the annotation object
%
%   The arguments to ANNOTATION can be followed by parameter/value pairs to
%   specify additional properties of the annotation object. The X and Y or
%   POSITION arguments to ANNOTATION can be omitted entirely, and all
%   properties specified using parameter/value pairs.
%
%   Examples: rh=annotation('rectangle',[-123 48 .3 .3]);
%             ah=annotation('arrow',[10 30],[-5 10],'Color','r');
%             th=annotation('textarrow',[-50 -30],[-89 -70],'String','ABC');
%

% R. Pawlowicz Nov/2017
%
%

global MAP_PROJECTION MAP_VAR_LIST

% Have to have initialized a map first

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

% Is first argument an axis handle?
if nargin>0 && length(varargin{1})==1 && ishandle(varargin{1})
   if  strcmp(get(varargin{1},'type'),'axes')
      useax=varargin{1};
      varargin(1)=[];
   else
      error(['map: ' mfilename ':invalidAxesHandle'],...
            ' First argument must be an axes handle ');
   end
else
    useax=gca;
end
figH=get(useax,'parent');

annotype=[varargin{1} '   '];

switch lower(annotype(1:5))
   case {'recta','ellip','textb'}
       POS=varargin{2};
       LON=POS(1);
       LAT=POS(2);
       [X,Y]=m_ll2xy(LON,LAT,'clip','off');
       [fX,fY]=axistofig(useax,X,Y,MAP_VAR_LIST.xlims,MAP_VAR_LIST.ylims);
       varargin{2}=[fX fY POS(3) POS(4)];

   case {'line ','arrow','doubl','texta'}
       LON=varargin{2};
       LAT=varargin{3};
       [X,Y]=m_ll2xy(LON,LAT,'clip','off');
       [fX,fY]=axistofig(useax,X,Y,MAP_VAR_LIST.xlims,MAP_VAR_LIST.ylims);
       varargin{2}=fX;
       varargin{3}=fY;
   otherwise  % Just a pass through!
end

h=annotation(figH,varargin{:});

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

if nargout==0
    clear h
end

end

% Transform into normalized FIGURE coordinates
function [fX,fY]=axistofig(useax,X,Y,xlims,ylims)

axun = get(useax,'Units');
set(useax,'Units','normalized');
%%axpos = get(useax,'Position');  % This doesn't work if dataspectratio set
axpos =plotboxpos(useax);         %...but this does the right thing.

fX= (X-xlims(1))/diff(xlims)*axpos(3) + axpos(1);
fY= (Y-ylims(1))/diff(ylims)*axpos(4) + axpos(2);

%% Restore axes units
set(useax,'Units',axun);

end

% The following function came from MATLAB File exchange
% https://www.mathworks.com/matlabcentral/fileexchange/9615-plotboxpos
%
function pos = plotboxpos(h)
%PLOTBOXPOS Returns the position of the plotted axis region
%
% pos = plotboxpos(h)
%
% This function returns the position of the plotted region of an axis,
% which may differ from the actual axis position, depending on the axis
% limits, data aspect ratio, and plot box aspect ratio.  The position is
% returned in the same units as the those used to define the axis itself.
% This function can only be used for a 2D plot.
%
% Input variables:
%
%   h:      axis handle of a 2D axis (if ommitted, current axis is used).
%
% Output variables:
%
%   pos:    four-element position vector, in same units as h

% Copyright 2010 Kelly Kearney

% Check input

if nargin < 1
    h = gca;
end

if ~ishandle(h) || ~strcmp(get(h,'type'), 'axes')
    error('Input must be an axis handle');
end

% Get position of axis in pixels

currunit = get(h, 'units');
set(h, 'units', 'pixels');
axisPos = get(h, 'Position');
set(h, 'Units', currunit);

% Calculate box position based axis limits and aspect ratios

darismanual  = strcmpi(get(h, 'DataAspectRatioMode'),    'manual');
pbarismanual = strcmpi(get(h, 'PlotBoxAspectRatioMode'), 'manual');

if ~darismanual && ~pbarismanual

    pos = axisPos;

else

    xlim = get(h, 'XLim');
    ylim = get(h, 'YLim');

    % Deal with axis limits auto-set via Inf/-Inf use

    if any(isinf([xlim ylim]))
        hc = get(h, 'Children');
        hc(~arrayfun( @(h) isprop(h, 'XData' ) & isprop(h, 'YData' ), hc)) = [];
        xdata = get(hc, 'XData');
        if iscell(xdata)
            xdata = cellfun(@(x) x(:), xdata, 'uni', 0);
            xdata = cat(1, xdata{:});
        end
        ydata = get(hc, 'YData');
        if iscell(ydata)
            ydata = cellfun(@(x) x(:), ydata, 'uni', 0);
            ydata = cat(1, ydata{:});
        end
        isplotted = ~isinf(xdata) & ~isnan(xdata) & ...
                    ~isinf(ydata) & ~isnan(ydata);
        xdata = xdata(isplotted);
        ydata = ydata(isplotted);
        if isempty(xdata)
            xdata = [0 1];
        end
        if isempty(ydata)
            ydata = [0 1];
        end
        if isinf(xlim(1))
            xlim(1) = min(xdata);
        end
        if isinf(xlim(2))
            xlim(2) = max(xdata);
        end
        if isinf(ylim(1))
            ylim(1) = min(ydata);
        end
        if isinf(ylim(2))
            ylim(2) = max(ydata);
        end
    end

    dx = diff(xlim);
    dy = diff(ylim);
    dar = get(h, 'DataAspectRatio');
    pbar = get(h, 'PlotBoxAspectRatio');

    limDarRatio = (dx/dar(1))/(dy/dar(2));
    pbarRatio = pbar(1)/pbar(2);
    axisRatio = axisPos(3)/axisPos(4);

    if darismanual
        if limDarRatio > axisRatio
            pos(1) = axisPos(1);
            pos(3) = axisPos(3);
            pos(4) = axisPos(3)/limDarRatio;
            pos(2) = (axisPos(4) - pos(4))/2 + axisPos(2);
        else
            pos(2) = axisPos(2);
            pos(4) = axisPos(4);
            pos(3) = axisPos(4) * limDarRatio;
            pos(1) = (axisPos(3) - pos(3))/2 + axisPos(1);
        end
    elseif pbarismanual
        if pbarRatio > axisRatio
            pos(1) = axisPos(1);
            pos(3) = axisPos(3);
            pos(4) = axisPos(3)/pbarRatio;
            pos(2) = (axisPos(4) - pos(4))/2 + axisPos(2);
        else
            pos(2) = axisPos(2);
            pos(4) = axisPos(4);
            pos(3) = axisPos(4) * pbarRatio;
            pos(1) = (axisPos(3) - pos(3))/2 + axisPos(1);
        end
    end
end

% Convert plot box position to the units used by the axis

hparent = get(h, 'parent');
hfig = ancestor(hparent, 'figure'); % in case in panel or similar
currax = get(hfig, 'currentaxes');

temp = axes('Units', 'Pixels', 'Position', pos, 'Visible', 'off', 'parent', hparent);
set(temp, 'Units', currunit);
pos = get(temp, 'position');
delete(temp);

set(hfig, 'currentaxes', currax);

end


% SYNTAX:
% mlActAuto = hmrR_PruneChannels(data, probe, mlActMan, tInc, dRange, SNRthresh, SDrange)
%
% UI NAME:
% Prune_Channels
%
% DESCRIPTION:
% Prune channels from the measurement list if their signal is too weak, too
% strong, or their standard deviation is too great. This function
% updates MeasListAct based on whether data 'd' meets these conditions
% as specified by'dRange' and 'SNRthresh'.
%
% INPUTS:
% d - SNIRF object containing time course data (nTpts x nChannels )
% probe - SNIRF object describing the probe - optode positions and wavelengths.
% mlActMan -
% dRange - if mean(d) < dRange(1) or > dRange(2) then it is excluded as an
%      active channel
% SNRthresh - if mean(d)/std(d) < SNRthresh then it is excluded as an
%      active channel
% SDrange - will prune channels with a source-detector separation <
%           SDrange(1) or > SDrange(2)
%
% OUTPUTS:
% mlAct - cell array of all data blocks - each data block is an array
%         of true/false for all channels in the contanining data block
%         specifying active/inactive status. (# of data blocks x # of Channels)
%
% USAGE OPTIONS:
% Prune_Channels: mlActAuto = hmrR_PruneChannels(data, probe, mlActMan, tIncMan, dRange, SNRthresh, SDrange)
%
% PARAMETERS:
% dRange: [1e4, 1e7]
% SNRthresh: 2
% SDrange: [0.0, 45.0]
%
% TO DO:
% consider Conc as well as wavelength data
%
function mlActAuto = hmrR_PruneChannels(data, probe, mlActMan, tIncMan, dRange, SNRthresh, SDrange)

% Init output
mlActAuto = cell(length(data),1);

% Check input args
if nargin<7
    disp( 'USAGE: hmrR_PruneChannels(data, probe, mlActMan, tIncMan, dRange, SNRthresh, SDrange)' )
    return
end
if isempty(tIncMan)
    tIncMan = cell(length(data),1);
end
if isempty(mlActMan)
    mlActMan = cell(length(data),1);
end

for iBlk = 1:length(data)

    d        = data(iBlk).GetDataTimeSeries();
    t        = data(iBlk).GetTime();
    MeasList = data(iBlk).GetMeasList();
    Lambda   = probe.GetWls();
    SrcPos   = probe.GetSrcPos();
    DetPos   = probe.GetDetPos();

    mlActMan{iBlk} = mlAct_Initialize(mlActMan{iBlk}, MeasList);

    if isempty(tIncMan{iBlk})
        tIncMan{iBlk} = ones(length(t),1);
    end
    tInc = tIncMan{iBlk};

    lstInc = find(tInc==1);
    d = d(lstInc,:);

    % check for dRange and SNRthresh
    dmean = mean(d,1);
    dstd = std(d,[],1);

    idxs1 = [];
    idxs2 = [];
    idxs3 = [];
    nLambda = length(Lambda);
    lst1 = find(MeasList(:,4)==1);

    % Start by including all channels
    chanList = ones(size(MeasList,1),1);

    for ii = 1:nLambda
        lst = [];
        rhoSD = [];
        for jj = 1:length(lst1)
            lst(jj) = find(MeasList(:,1)==MeasList(lst1(jj),1) & ...
                           MeasList(:,2)==MeasList(lst1(jj),2) & ...
                           MeasList(:,4)==ii);
            rhoSD(jj) = norm( SrcPos(MeasList(lst1(jj),1),:) - DetPos(MeasList(lst1(jj),2),:) );
        end

        % dRange exclusion criteria
        idxs1 = [idxs1, find(dmean(lst)<=dRange(1) | dmean(lst)>=dRange(2))];

        % SNRthresh exclusion criteria
        idxs2 = [idxs2, find((dmean(lst)./dstd(lst)) <= SNRthresh)];

        % SDrange exclusion criteria
        idxs3 = [idxs3, find(rhoSD<SDrange(1) | rhoSD>SDrange(2))];

        idxsExcl = unique([idxs1(:)', idxs2(:)', idxs3(:)']);

        chanList(lst(idxsExcl)) = 0;
    end

    idxs4 = find(mlActMan{iBlk}(:,3) == 0);

    if ~isempty(idxs1)
        fprintf('hmrR_PruneChannels:  excluded channels [ %s ] based on dRange=[ %s ] at wavelength %d\n', num2str(idxs1(:)'), num2str(dRange), ii);
    end
    if ~isempty(idxs2)
        fprintf('hmrR_PruneChannels:  excluded channels [ %s ] based on SNRthresh=%0.1f at wavelength %d\n', num2str(idxs2(:)'), SNRthresh, ii);
    end
    if ~isempty(idxs3)
        fprintf('hmrR_PruneChannels:  excluded channels [ %s ] based on SDrange=[ %s ] at wavelength %d\n', num2str(idxs3(:)'), num2str(SDrange), ii);
    end
    if ~isempty(idxs4)
        fprintf('hmrR_PruneChannels:  manually excluded channels [ %s ]\n', num2str(idxs4(:)'));
    end

    chanList = chanList(:) & mlActMan{iBlk}(:,3);

    % update MeasListAct
    mlActAuto{iBlk} = mlAct_Initialize(chanList, MeasList);
end


function [imsource, D, C, F] = dfviewexcludepreview(outlier, width, height, dsname)
% For use by DFITTOOL

%   $Revision: 1.1.6.5 $
%   Copyright 2003-2004 The MathWorks, Inc.

tempfigure=figure('units','pixels','position',[0 0 width height], ...
      'handlevisibility','off', ...
      'integerhandle','off', ...
      'visible','off', ...
      'paperpositionmode', 'auto', ...
      'color','w');

NONE='(none)';

% We're excluding based on data in one dataset
ds = find(getdsdb,'name',dsname);
if isempty(ds)
   return
end

% Get data w/o NaNs but with no exclusion rule applied
[ydata, cens, freq] = getincludeddata(ds,[]);
ydata = real(ydata);
if isempty(cens)
   cens = zeros(size(ydata));
end
if isempty(freq)
   freq = ones(size(ydata));
end

% Sort y and carry along the rest
[ydata,i] = sort(ydata);
cens = cens(i);
freq = freq(i);

% Create x and y vectors to plot
n = sum(freq);
x = zeros(n,1);
y = zeros(n,1);
g = zeros(n,1);
j = 1;
x(1:freq(1)) = ydata(1);
y(1:freq(1)) = (1:freq(1))';
g(1:freq(1)) = cens(1);
i = freq(1)+1;
for k=2:length(ydata)
   for j=1:freq(k)
      x(i) = ydata(k);
      g(i) = cens(k);
      if (i>1) && (x(i)==x(i-1))
         y(i) = y(i-1) + 1;
      else
         y(i) = 1;
      end
      i = i+1;
   end
end

o = handle(outlier);
ylo = o.YLow;
if isempty(ylo)
	ylo = -Inf;
else
	ylo = str2double(ylo);
end

yhi = o.YHigh;
if isempty(yhi)
	yhi = Inf;
else
	yhi = str2double(yhi);
end

ylotest = o.YLowLessEqual;
yhitest = o.YLowLessEqual;

xlim = [min(x) max(x)];
xlim = xlim + .05 * [-1 1] * diff(xlim);
ylim = [min(y) max(y)];
ylim = ylim + .05 * [-1 1] * diff(ylim);
if ylim(1) == ylim(2)
    ylim = [0 2];
end
ax=axes('position',[.05 .05 .9 .9], ...
      'parent',tempfigure, ...
      'xtick',[],'ytick',[], ...
      'box','on', ...
      'visible','off', 'XLim',xlim,'YLim',ylim);

if ylotest==0
   inbounds = x>=ylo;
else
   inbounds = x>ylo;
end
if yhitest==0
   inbounds = inbounds & x<=yhi;
else
   inbounds = inbounds & x<yhi;
end

figcolor = get(0,'defaultuicontrolbackgroundcolor');

t = inbounds;
l1 = line('XData',x(t),'YData',y(t),...
          'Color','b','Marker','.','LineStyle','none',...
          'Parent',ax);
t = ~inbounds;
l2 = line('XData',x(t),'YData',y(t),...
          'Color',figcolor/2,'Marker','.','LineStyle','none',...
          'Parent',ax);
alllines = [l1 l2];

gr = [.9 .9 .9];

% Create patches to show the area outside the domain and range

allpatches = [];

if (ylo ~= -Inf)
    xlo = max(ylo,xlim(1));
    xp = [xlim(1) xlo xlo xlim(1)];
    yp = [ylim(1) ylim(1) ylim(2) ylim(2)];
    p1=patch(xp,yp,gr,'LineStyle','none','Parent',ax);
    allpatches(end+1)= p1;
end

if (yhi ~= Inf)
    xhi = min(yhi,xlim(2));
    xp = [xlim(2) xhi xhi xlim(2)];
    yp = [ylim(1) ylim(1) ylim(2) ylim(2)];
    p2=patch(xp,yp,gr,'LineStyle','none','Parent',ax);
    allpatches(end+1)= p2;
end

set(ax,'Child',[alllines allpatches]);

x=hardcopy(tempfigure,'-dzbuffer','-r0');
% give the image a black edge
x(1,:,:)=0; x(end,:,:)=0; x(:,1,:)=0; x(:,end,:)=0;
imsource=im2mis(x);
delete(tempfigure);
[D, C, F] = dfviewdata(ds);


function transpose(x)
%TRANSPOSE is not defined on tensors.
%
%   See also TENSOR, TENSOR/PERMUTE.
%
%MATLAB Tensor Toolbox.
%Copyright 2015, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2015) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

error('Transpose on tensor is not defined');


% Test split for gesture labels, for video chunks data
% run in directory of dtfv_learning
addpath('other');
addpath('../../../toolbox/libsvm/matlab');
load('../dataset_trial/saved_anno.mat');
load('../dataset_trial/frame_rates.mat');

% Build feature Map of easy load of FV feats
FV_path = '../dataset_trial/FVs_chunks';
CNN_path = '../dataset_trial/CNNfeats';

FVfeaMap = FV_feaMap(FV_path);
CNNfeaMap = CNN_feaMap(CNN_path);

gesture_score = cell(1,10);
gesture_acc = cell(1,10);
gesture_pred = cell(1,10);
train_lab = cell(1, 10);
test_lab = cell(1, 10);
gesture_scorei_train = cell(1,10);
num_chunks_train = cell(1,10);
num_chunks_test = cell(1,10);

num_ges = 5;

use_CNN = 1;
for cv = 0:9
    gesture_score{cv+1} = cell(1, num_ges);
    gesture_acc{cv+1} = cell(1, num_ges);
    gesture_pred{cv+1} = cell(1, num_ges);
    train_lab{cv+1} = cell(1, num_ges);
    test_lab{cv+1} = cell(1, num_ges);

    total_posnum_tr = zeros(1,5); % number of total pos for training
    total_negnum_tr = zeros(1,5); % number of total neg for training
    train_au_lab = []; % train facial unit labels
    test_au_lab = [];
    current_i = 1;  % used for accumulating id of each sample
    fprintf('CV: %d\n', cv);

    %% Loading data
    % Train data
    trainfile = ['../Scripts_by_ID/trainVideo',num2str(cv),'.txt'];
    testfile = ['../Scripts_by_ID/testVideo',num2str(cv),'.txt'];
    fid = fopen(trainfile);
    C = textscan(fid, '%s');
    fclose(fid);
    num_v = length(C{1})/2;
    feat_train_CNN = [];
    feat_train_FV = [];
    num_chunks_train{cv+1} = zeros(num_v,1);
    for i = 1:num_v
        [pathstr,name,ext] = fileparts(C{1}{2*i-1});
        disp(name)
        chunk_names = get_chunkname(name);
        num_chunks_train{cv+1}(i) = length(chunk_names);
        for chunk_id = 1: length(chunk_names)
            % check whether is a bad chunk
            if ~bad_chunk(chunk_names{chunk_id})
                eval(sprintf('chunk_label=fea_dict.%s;',chunk_names{chunk_id}));
                chunk_name = chunk_names{chunk_id};
                chunk_label = str2num(chunk_label);
                train_au_lab = [train_au_lab; chunk_label'];  % #sample x #AU (5)
                % get features CNN
                CNN_feats = get_CNNfeats(chunk_name, CNNfeaMap, frame_rates);
                %CNN_feats = mean(CNN_feats, 1);  % 1-by-4096
                % get features FV
                FV_feats = get_FVfeats(chunk_name, FVfeaMap);
                % update step
                feat_train_CNN(current_i,:) = CNN_feats;
                feat_train_FV(current_i,:) = FV_feats;
                current_i = current_i +1;
            end
        end
    end
    disp('train#')
    sum(train_au_lab, 1)

    % Test data
    fid = fopen(testfile);
    C = textscan(fid, '%s');
    fclose(fid);
    num_v = length(C{1})/2;
    feat_test_CNN = [];
    feat_test_FV = [];
    current_i = 1;
    num_chunks_test{cv+1} = zeros(num_v,1);
    for i = 1:num_v
        [pathstr,name,ext] = fileparts(C{1}{2*i-1});
        chunk_names = get_chunkname(name);
        num_chunks_test{cv+1}(i) = length(chunk_names);
        for chunk_id = 1: length(chunk_names)
            % check whether is a bad chunk
            if ~bad_chunk(chunk_names{chunk_id})
                eval(sprintf('chunk_label=fea_dict.%s;',chunk_names{chunk_id}));
                chunk_name = chunk_names{chunk_id};
                chunk_label = str2num(chunk_label);
                test_au_lab = [test_au_lab; chunk_label'];  % #sample x #AU (5)
                % get features CNN
                CNN_feats = get_CNNfeats(chunk_name, CNNfeaMap, frame_rates);
                %CNN_feats = mean(CNN_feats, 1);  % 1-by-4096
                % get features FV
                FV_feats = get_FVfeats(chunk_name, FVfeaMap);
                % update step
                feat_test_CNN(current_i,:) = CNN_feats;
                feat_test_FV(current_i,:) = FV_feats;
                current_i = current_i +1;
            end
        end
    end
    disp('test#')
    sum(test_au_lab, 1)

    %% Training classifiers
    for ges_i = 1:num_ges
        fprintf('CV: %d, ges_id: %d\n', cv, ges_i);
        lab_vec = train_au_lab(:, ges_i);
        if use_CNN == 1
            fea_mat = feat_train_CNN;
        else
            fea_mat = feat_train_FV;
        end
        train_lab{cv+1}{ges_i} = lab_vec;
        model = svmtrain(lab_vec, fea_mat, '-t 0 -q -b 1');
        [pred, acc, prob] = svmpredict(lab_vec,fea_mat, model, '-b 1');
        gesture_score_train{cv+1}{ges_i} = prob(:,2);
        % Test
        lab_vec = test_au_lab(:, ges_i);
        if use_CNN == 1
            fea_mat = feat_test_CNN;
        else
            fea_mat = feat_test_FV;
        end
        [pred, acc, prob] = svmpredict(lab_vec,fea_mat, model, '-b 1');
        pred
        gesture_score{cv+1}{ges_i} = prob(:,2);
        gesture_acc{cv+1}{ges_i} = acc;
        gesture_pred{cv+1}{ges_i} = pred;
        test_lab{cv+1}{ges_i} = lab_vec;
    end
    cv_gesture_score = gesture_score{cv+1};
    %save(['CNN_gesture_score',num2str(cv),'.mat'],'cv_gesture_score');

end
if use_CNN == 1
    appname = 'CNN';
else
    appname = 'FV';
end
save(['total_',appname,'_gesture_score.mat'], 'gesture_score');
save(['total_',appname,'_gesture_pred.mat'], 'gesture_pred');
save(['total_',appname,'ges_results.mat'], 'gesture_score', 'gesture_pred', 'train_lab', 'test_lab','gesture_score_train','num_chunks_train','num_chunks_test');


function calcAllAertsFeatures_HN(pathData,pathText,namePT,nameCT,nameROI,featType)
% -------------------------------------------------------------------------
% function calcAllSeparateTextures_HN(pathData,pathText,namePT,nameCT,nameROI,featType,scale_mat,Ng_mat)
% -------------------------------------------------------------------------
% DESCRIPTION:
% This function computes SEPARATE texture features for all patients, for
% all different combinations of the following texture extraction parameters:
% - Scale: Resolution at which the ROI is isotropically resampled.
% - Ng: Number of gray-levels in the quantization process.
%
% Different extraction parameters are passed as arrays or cells in the
% function in order to test all possible combinations. This function is
% used for SEPARATE scans specifically. See Ref. [1,2] and 'prepareVolume.m'
% for more details.
%
% Texture features are computed for all head and neck (HN) DICOM imaging
% data downloaded from The Cancer Imaging Archive (TCIA) website at:
% <http://dx.doi.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>, and first organized
% in a 'DATA' directory using the function readAllDICOM_HN.m.  Results are
% then saved in a folder 'TEXTURES' in the HN WORKSPACE.
% -------------------------------------------------------------------------
% REFERENCES:
% [1] Vallieres, M. et al. (2015). FDG-PET/CT radiomics models for the
%     early prediction of different tumour outcomes in head and neck cancer.
%     The Journal of Nuclear Medicine, aa(bb), xxx-yyy.
%     doi:
% [2] Vallieres, M. et al. (2015). A radiomics model from joint FDG-PET and
%     MRI texture features for the prediction of lung metastases in soft-tissue
%     sarcomas of the extremities. Physics in Medicine and Biology, 60(14),
%     5471-5496. doi:10.1088/0031-9155/60/14/5471
% -------------------------------------------------------------------------
% INPUTS:
% 1. pathData: Full path to the HN sData files directory.
%              --> Ex: '/myProject/WORKSPACE/DATA'
% 2. pathNonText: Full path to the HN non texture features directory.
%              --> Ex: '/myProject/WORKSPACE/FEATURES/NON_TEXTURES'
% 3. namePT: Cell of strings of all PET sData files to read
%            --> Ex: {'HGJ_001_PT.PTscan.mat';'HGJ_022_PT.PTscan.mat'}
% 4. namePT: Cell of strings of all CT sData files to read
%            --> Ex: {'HGJ_001_CT.CTscan.mat';'HGJ_022_CT.CTscan.mat'}
% 5. nameROI: Cell of strings specifying the ROI names to analyze for the
%             patients defined by "namePT" and "nameCT"
%             --> Ex: {'GTV';'GTV-P'}
% 6. featType: Either 'GTVp' for primary GTV, or 'GTVtot' for primary GTV +
%              nodal GTVs
% 7. scale_mat: Array vector specifying the different 'Scale' values to test.
%               --> Ex: [1,2,3,4,5]
% 8. Ng_mat: Array vector specifying the different 'Ng' values to test.
%            --> Ex: [8,16,32,64]
% -------------------------------------------------------------------------
% AUTHOR(S): Martin Vallieres <mart.vallieres@gmail.com>
% -------------------------------------------------------------------------
% HISTORY:
% - Creation: March 2016
%--------------------------------------------------------------------------
% STATEMENT:
% This file is part of <https://github.com/mvallieres/radiomics/>,
% a package providing MATLAB programming tools for radiomics analysis.
% --> Copyright (C) 2015  Martin Vallieres
%
%    This package 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 package 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 package.  If not, see <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

startpath=pwd;

% INITIALIZATION
scans = {'PT','CT','CTorig'}; nScans = numel(scans); names = {namePT,nameCT,nameCT};
scanTypes = {'PET','CT','CT'};
nPatient = numel(namePT);

% COMPUTATION
fprintf('\n')
for i = 1:nPatient
    for j = 1:nScans
        cd(pathData)
        tStart = tic;
        if strcmp(scans{j},'CTorig')
            fprintf(['\n*********************** COMPUTING AERTS SIGNATURE: %s, ORIGINAL ***********************'],names{j}{i});
        else
            fprintf(['\n*********************** COMPUTING AERTS SIGNATURE: %s, ***********************'],names{j}{i});
        end
        scanType = scanTypes{j};
        load(names{j}{i}) % Variable 'sData' now in MATLAB Workspace;
        spatialRef = sData{2}.scan.volume.spatialRef;
        mask = zeros(size(sData{2}.scan.volume.data));
        [contourVect] = findContours_HN(sData,{nameROI{i}},scanType);
        for c = 1:numel(contourVect)
            temp = zeros(size(sData{2}.scan.volume.data));
            [~,ROImask,bb] = getROI(sData,contourVect(c));
            temp(bb(1,1):bb(1,2),bb(2,1):bb(2,2),bb(3,1):bb(3,2)) = ROImask;
            mask = mask + temp;
        end
        mask(mask > 0) = 1;
        [bb] = computeBoundingBox(mask); a = 0; b = 0; c = 0;
        sizeROI = [bb(1,2)-bb(1,1)+1,bb(2,2)-bb(2,1)+1,bb(3,2)-bb(3,1)+1];
        if mod(sizeROI(1),2)
            a = a + 1;
        end
        if mod(sizeROI(2),2)
            b = b + 1;
        end
        if mod(sizeROI(3),2)
            c = c + 1;
        end
        mask = mask(bb(1,1):bb(1,2)+a,bb(2,1):bb(2,2)+b,bb(3,1):bb(3,2)+c);
        vol = sData{2}.scan.volume.data(bb(1,1):bb(1,2)+a,bb(2,1):bb(2,2)+b,bb(3,1):bb(3,2)+c);
        if strcmp(scanType,'PET')
            [vol] = computeSUVmap(vol,sData{3}(1));
        end
        if strcmp(scans{j},'CTorig')
            [signature] = getAertsSign(vol,mask,spatialRef,scanType); % Calculating the radiomic signature as originially defined by Aerts et al.
            suffix = '_orig';
        else
            [signature] = getAertsSignMod(vol,mask,spatialRef,scanType); % Improved version (dimensionless compactness, 1 GLRLM matrix, GLN normalization)
            suffix = '';
        end
        ind = strfind(names{j}{i},'.'); namePatientScan = names{j}{i}(1:ind(1)-1);
        cd(pathText), save([namePatientScan,'_',featType,'_sign',suffix],'signature')
        time = toc(tStart);
        fprintf('TOTAL TIME: %.2f seconds\n',time)
    end
end

cd(startpath)
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MRiLab auto generated file: DO NOT EDIT!     %
% Generated by MRiLab "DoWriteXML2m" Generator %
% MRiLab Version 1.3                           %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [rfAmp,rfPhase,rfFreq,rfCoil,GzAmp,GyAmp,GxAmp,ADC,Ext,uts,ts,flags]=PSD_AFI
global VCtl
global VVar
CV1=1.5e-3;
CV10=0;
CV11=0;
CV12=0;
CV13=0;
CV14=0;
CV2=2e-3;
CV3=20e-3;
CV4=0;
CV5=0;
CV6=0;
CV7=0;
CV8=0;
CV9=0;
rfAmpAll=[];
rfPhaseAll=[];
rfFreqAll=[];
rfCoilAll=[];
GzAmpAll=[];
GyAmpAll=[];
GxAmpAll=[];
ADCAll=[];
ExtAll=[];
rfTimeAll=[];
GzTimeAll=[];
GyTimeAll=[];
GxTimeAll=[];
ADCTimeAll=[];
ExtTimeAll=[];
SEtAll=[];
uts=[];
ts=[];
flags=[];
if VCtl.PlotSeq == 1
rfAmp=[];
rfPhase=[];
rfFreq=[];
rfCoil=[];
GzAmp=[];
GyAmp=[];
GxAmp=[];
ADC=[];
Ext=[];
Freq=1;
Notes='regular TR section';
AttributeOpt={'on','off'};
Switch=AttributeOpt{1};
TREnd=Inf;
TRStart=1;
tE=VCtl.TR;
tS=0;
if VVar.TRCount<TRStart | VVar.TRCount>TREnd | mod(VVar.TRCount-TRStart,Freq)~=0 | strcmp(Switch,'off')
% do nothing
else
ts = [ts tS tE];
end
ts = [0 max(ts)-min(ts)];
return;
end
%==============Pulses 1==============
rfAmp=[];
rfPhase=[];
rfFreq=[];
rfCoil=[];
GzAmp=[];
GyAmp=[];
GxAmp=[];
ADC=[];
Ext=[];
rfTime=[];
GzTime=[];
GyTime=[];
GxTime=[];
ADCTime=[];
ExtTime=[];
Freq=1;
Notes='regular TR section';
AttributeOpt={'on','off'};
Switch=AttributeOpt{1};
TREnd=Inf;
TRStart=1;
tE=VCtl.TR;
tS=0;
if isempty(tS) | isempty(tE) | (tS>=tE)
error('SE setting is incorrect for Pulses 1!');
end
if VVar.TRCount<TRStart | VVar.TRCount>TREnd | mod(VVar.TRCount-TRStart,Freq)~=0 | strcmp(Switch,'off')
% do nothing
else
%--------------------
AttributeOpt={'on','off'};
p.AnchorTE=AttributeOpt{1};
AttributeOpt={'Non','Hamming','Hanning'};
p.Apod=AttributeOpt{2};
p.CoilID=1;
p.DupSpacing=CV3;
p.Duplicates=2;
p.FA=VCtl.FlipAng;
p.Notes='sinc rf pulse';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.TBP=4;
p.dt=20e-6;
p.rfFreq=0;
p.rfPhase=0;
p.tEnd=0.5e-3;
p.tStart=0.2e-3;
if strcmp(p.Switch,'on')
if strcmp(p.AnchorTE,'on')
switch VCtl.TEAnchor
case 'Start'
VCtl.TEAnchorTime=p.tStart;
case 'Middle'
VCtl.TEAnchorTime=(p.tStart+p.tEnd)/2;
case 'End'
VCtl.TEAnchorTime=p.tEnd;
end
end
[rfAmp1,rfPhase1,rfFreq1,rfCoil1,rfTime1]=rfSinc(p);
if strcmp(VCtl.MultiTransmit,'off')
if VCtl.MasterTxCoil==rfCoil1(1)
rfAmp=[rfAmp rfAmp1];
rfPhase=[rfPhase rfPhase1];
rfFreq=[rfFreq rfFreq1];
rfCoil=[rfCoil rfCoil1];
rfTime=[rfTime rfTime1];
end
else
rfAmp=[rfAmp rfAmp1];
rfPhase=[rfPhase rfPhase1];
rfFreq=[rfFreq rfFreq1];
rfCoil=[rfCoil rfCoil1];
rfTime=[rfTime rfTime1];
end
end
p=[];
%--------------------
p.DupSpacing=CV3;
p.Duplicates=2;
p.Gz1Sign=1;
p.Gz2Sign=0;
p.Notes='cartesian phase';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.t1End=CV2;
p.t1Start=CV1;
p.t2End=VCtl.TE+CV2;
p.t2Start=VCtl.TE+CV1;
p.tRamp=100e-6;
if strcmp(p.Switch,'on')
[GzAmp1,GzTime1]=GzCartesian(p);
GzAmp=[GzAmp GzAmp1];
GzTime=[GzTime GzTime1];
end
p=[];
%--------------------
p.DupSpacing=CV3;
p.Duplicates=2;
p.Gy1Sign=1;
p.Gy2Sign=0;
p.Notes='cartesian phase';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.t1End=CV2;
p.t1Start=CV1;
p.t2End=VCtl.TE+CV2;
p.t2Start=VCtl.TE+CV1;
p.tRamp=100e-6;
if strcmp(p.Switch,'on')
[GyAmp1,GyTime1]=GyCartesian(p);
GyAmp=[GyAmp GyAmp1];
GyTime=[GyTime GyTime1];
end
p=[];
%--------------------
p.DupSpacing=0;
p.Duplicates=1;
p.Gx1Sign=-1;
p.Gx2Sign=1;
p.Gx3Sign=0;
p.Notes='cartesian frequency';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.t1Start=CV1;
p.t2Middle=VCtl.ME_TEs(1);
p.t3Start=VCtl.TE+CV1;
p.tRamp=100e-6;
if strcmp(p.Switch,'on')
[GxAmp1,GxTime1]=GxCartesian(p);
GxAmp=[GxAmp GxAmp1];
GxTime=[GxTime GxTime1];
end
p=[];
%--------------------
p.DupSpacing=0;
p.Duplicates=1;
p.Gx1Sign=-1;
p.Gx2Sign=1;
p.Gx3Sign=0;
p.Notes='cartesian frequency';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.t1Start=CV3+CV1;
p.t2Middle=CV3+VCtl.ME_TEs(2);
p.t3Start=CV3+VCtl.TE+CV1;
p.tRamp=100e-6;
if strcmp(p.Switch,'on')
[GxAmp2,GxTime2]=GxCartesian(p);
GxAmp=[GxAmp GxAmp2];
GxTime=[GxTime GxTime2];
end
p=[];
%--------------------
p.DupSpacing=0;
p.Duplicates=1;
p.Notes='cartesian readout';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.tMiddle=VCtl.ME_TEs(1);
if strcmp(p.Switch,'on')
[ADC1,ADCTime1]=ADCCartesian(p);
ADC=[ADC ADC1];
ADCTime=[ADCTime ADCTime1];
end
p=[];
%--------------------
p.DupSpacing=0;
p.Duplicates=1;
p.Notes='cartesian readout';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.tMiddle=CV3+VCtl.ME_TEs(2);
if strcmp(p.Switch,'on')
[ADC2,ADCTime2]=ADCCartesian(p);
ADC=[ADC ADC2];
ADCTime=[ADCTime ADCTime2];
end
p=[];
%--------------------
p.DupSpacing=0;
p.Duplicates=1;
p.Ext=5;
p.Notes='calculate remaining scan time';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.tStart=0;
if strcmp(p.Switch,'on')
[Ext1,ExtTime1]=ExtBit(p);
Ext=[Ext Ext1];
ExtTime=[ExtTime ExtTime1];
end
p=[];
%--------------------
p.DupSpacing=CV3;
p.Duplicates=2;
p.Ext=1;
p.Notes='reset K space location';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.tStart=CV1*9/10;
if strcmp(p.Switch,'on')
[Ext2,ExtTime2]=ExtBit(p);
Ext=[Ext Ext2];
ExtTime=[ExtTime ExtTime2];
end
p=[];
%--------------------
p.DupSpacing=0;
p.Duplicates=1;
p.Ext=6;
p.Notes='dephase Mxy';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.tStart=CV3*(9/10);
if strcmp(p.Switch,'on')
[Ext3,ExtTime3]=ExtBit(p);
Ext=[Ext Ext3];
ExtTime=[ExtTime ExtTime3];
end
p=[];
%--------------------
p.DupSpacing=0;
p.Duplicates=1;
p.Ext=6;
p.Notes='dephase Mxy';
AttributeOpt={'on','off'};
p.Switch=AttributeOpt{1};
p.tStart=VCtl.TR*(9/10);
if strcmp(p.Switch,'on')
[Ext4,ExtTime4]=ExtBit(p);
Ext=[Ext Ext4];
ExtTime=[ExtTime ExtTime4];
end
p=[];
%--------------------
SEt=[tS tE];
rfAmp(rfTime<0 | rfTime>SEt(2)-SEt(1)) = [];
rfPhase(rfTime<0 | rfTime>SEt(2)-SEt(1)) = [];
rfFreq(rfTime<0 | rfTime>SEt(2)-SEt(1)) = [];
rfCoil(rfTime<0 | rfTime>SEt(2)-SEt(1)) = [];
GzAmp(GzTime<0 | GzTime>SEt(2)-SEt(1)) = [];
GyAmp(GyTime<0 | GyTime>SEt(2)-SEt(1)) = [];
GxAmp(GxTime<0 | GxTime>SEt(2)-SEt(1)) = [];
ADC(ADCTime<0 | ADCTime>SEt(2)-SEt(1)) = [];
Ext(ExtTime<0 | ExtTime>SEt(2)-SEt(1)) = [];
rfTime(rfTime<0 | rfTime>SEt(2)-SEt(1)) = [];
GzTime(GzTime<0 | GzTime>SEt(2)-SEt(1)) = [];
GyTime(GyTime<0 | GyTime>SEt(2)-SEt(1)) = [];
GxTime(GxTime<0 | GxTime>SEt(2)-SEt(1)) = [];
ADCTime(ADCTime<0 | ADCTime>SEt(2)-SEt(1)) = [];
ExtTime(ExtTime<0 | ExtTime>SEt(2)-SEt(1)) = [];
rfAmp(abs(rfAmp)<eps) = 0;
rfTime = rfTime + SEt(1);
GzTime = GzTime + SEt(1);
GyTime = GyTime + SEt(1);
GxTime = GxTime + SEt(1);
ADCTime = ADCTime + SEt(1);
ExtTime = ExtTime + SEt(1);
rfAmpAll=[rfAmpAll rfAmp];
rfPhaseAll=[rfPhaseAll rfPhase];
rfFreqAll=[rfFreqAll rfFreq];
rfCoilAll=[rfCoilAll rfCoil];
GzAmpAll=[GzAmpAll GzAmp];
GyAmpAll=[GyAmpAll GyAmp];
GxAmpAll=[GxAmpAll GxAmp];
ADCAll=[ADCAll ADC];
ExtAll=[ExtAll Ext];
rfTimeAll=[rfTimeAll rfTime];
GzTimeAll=[GzTimeAll GzTime];
GyTimeAll=[GyTimeAll GyTime];
GxTimeAll=[GxTimeAll GxTime];
ADCTimeAll=[ADCTimeAll ADCTime];
ExtTimeAll=[ExtTimeAll ExtTime];
SEtAll=[SEtAll SEt];
end
%====================================
if isempty(rfTimeAll)
error('rf sequence line can not be empty! Master Tx coil element must be used.');
end
if isempty(GzTimeAll)
error('GzSS sequence line can not be empty!');
end
if isempty(GyTimeAll)
error('GyPE sequence line can not be empty!');
end
if isempty(GxTimeAll)
error('GxR sequence line can not be empty!');
end
if isempty(ADCTimeAll)
error('ADC sequence line can not be empty!');
end
if isempty(ExtTimeAll)
error('Ext sequence line can not be empty!');
end
SEflag=repmat([0 0 0 0 0 0]',[1 2]);
rfflag=repmat([1 0 0 0 0 0]',[1 max(size(rfTimeAll))]);
Gzflag=repmat([0 1 0 0 0 0]',[1 max(size(GzTimeAll))]);
Gyflag=repmat([0 0 1 0 0 0]',[1 max(size(GyTimeAll))]);
Gxflag=repmat([0 0 0 1 0 0]',[1 max(size(GxTimeAll))]);
ADCflag=repmat([0 0 0 0 1 0]',[1 max(size(ADCTimeAll))]);
Extflag=repmat([0 0 0 0 0 1]',[1 max(size(ExtTimeAll))]);
ts=[[min(SEtAll) max(SEtAll)] rfTimeAll GzTimeAll GyTimeAll GxTimeAll ADCTimeAll ExtTimeAll]-min(SEtAll);
flags=[SEflag rfflag Gzflag Gyflag Gxflag ADCflag Extflag];
[ts,ind]=sort(ts);
uts=unique(ts);
flags=flags(:,ind);
[rfTime,ind]=sort(rfTimeAll-min(SEtAll));
rfAmp=rfAmpAll(:,ind);
rfPhase=rfPhaseAll(:,ind);
rfFreq=rfFreqAll(:,ind);
rfCoil=rfCoilAll(:,ind);
[GzTime,ind]=sort(GzTimeAll-min(SEtAll));
GzAmp=GzAmpAll(:,ind);
[GyTime,ind]=sort(GyTimeAll-min(SEtAll));
GyAmp=GyAmpAll(:,ind);
[GxTime,ind]=sort(GxTimeAll-min(SEtAll));
GxAmp=GxAmpAll(:,ind);
[ADCTime,ind]=sort(ADCTimeAll-min(SEtAll));
ADC=ADCAll(:,ind);
[ExtTime,ind]=sort(ExtTimeAll-min(SEtAll));
Ext=ExtAll(:,ind);
rfAmp(1) = 0;
rfPhase(1) = 0;
rfFreq(1) = 0;
GzAmp(1) = 0;
GyAmp(1) = 0;
GxAmp(1) = 0;
ADC(1) = 0;
Ext(1) = 0;
rfAmp(end) = 0;
rfPhase(end) = 0;
rfFreq(end) = 0;
GzAmp(end) = 0;
GyAmp(end) = 0;
GxAmp(end) = 0;
ADC(end) = 0;
Ext(end) = 0;
end


classdef prtRvMvb < prtRv & prtRvMemebershipModel
    % prtRvMvv  Multivariate binary random variable
    %
    %   RV = prtRvMvv creates a prtRvMvv object with empty probability
    %   vector. The probability vector must be set either directly, or by
    %   calling the MLE method.
    %
    %   RV = prtRvMvn(PROPERTY1, VALUE1,...) creates a prtRvMvb object RV
    %   with properties as specified by PROPERTY/VALUE pairs.
    %
    %   A prtRvMvb object inherits all properties from the prtRv class. In
    %   addition, it has the following properties:
    %
    %   probabilities - 1 x nDimensions vector with values between 0 and 1
    %                   specifying the probability of each dimension taking
    %                   the value true.
    %
    %  Example:
    %
    %   See also: prtRv, prtRvGmm, prtRvMultinomial, prtRvUniform,
    %   prtRvUniformImproper, prtRvVq, prtRvDiscrete

    properties (SetAccess = private)
        name = 'Multi-Variate Binary';
        nameAbbreviation = 'RVMVB';
    end

    properties (SetAccess = protected)
        isSupervised = false;
        isCrossValidateValid = true;
    end

    properties (Dependent)
        probabilities
    end
    properties (Dependent, SetAccess = 'private')
        logProbabilities
        logOneMinusProbabilities
    end
    properties (Hidden, Dependent)
        minProbability
        maxProbability
    end
    properties (Hidden, SetAccess='private', GetAccess='private')
        minProbabilityDepHelper = 0;
        maxProbabilityDepHelper = 1;
        probabilitiesDepHelper
    end

    properties (Hidden = true, Dependent = true)
        nDimensions
    end

    methods
        function R = prtRvMvb(varargin)
            R.name = 'Multi-Variate Binary';
            R = constructorInputParse(R,varargin{:});
        end

        function R = mle(R,X)
           % MLE Compute the maximum likelihood estimate
            %
            % RV = RV.mle(X) computes the maximum likelihood estimate based
            % the data X. X should be nObservations x nDimensions.

            X = R.dataInputParse(X); % Basic error checking etc

            R = weightedMle(R,X,ones(size(X,1),1));
        end

        function vals = pdf(R,X)
            % PDF Output the pdf of the random variable evaluated at the points specified
            %
            % pdf = RV.pdf(X) returns  the pdf of the prtRv
            % object evaluated at X. X must be an N x nDims matrix, where
            % N is the number of locations to evaluate the pdf, and nDims
            % is the same as the number of dimensions, nDimensions, of the
            % prtRv object RV.

            [isValid, reasonStr] = R.isValid;
            assert(isValid,'PDF cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);

            X = R.dataInputParse(X); % Basic error checking etc
            assert(size(X,2) == R.nDimensions,'Data, RV dimensionality missmatch. Input data, X, has dimensionality %d and this RV has dimensionality %d.', size(X,2), R.nDimensions)
            assert((isnumeric(X) || islogical(X)) && ndims(X)==2,'X must be a 2D numeric or logical array.');

            vals = prod(bsxfun(@times,X,R.probabilities) + bsxfun(@times,~X,1-R.probabilities),2);
        end

        function vals = logPdf(R,X)
            % LOGPDF Output the log pdf of the random variable evaluated at the points specified
            %
            % logpdf = RV.logpdf(X) returns the logarithm of value of the
            % pdf of the prtRv object evaluated at X. X must be an N x
            % nDims matrix, where N is the number of locations to evaluate
            % the pdf, and nDims is the same as the number of dimensions,
            % nDimensions, of the prtRv object RV.

            [isValid, reasonStr] = R.isValid;
            assert(isValid,'LOGPDF cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);

            X = R.dataInputParse(X); % Basic error checking etc
            assert(size(X,2) == R.nDimensions,'Data, RV dimensionality missmatch. Input data, X, has dimensionality %d and this RV has dimensionality %d.', size(X,2), R.nDimensions)
            assert((isnumeric(X) || islogical(X)) && ndims(X)==2,'X must be a 2D numeric or logical array.');

            term1 = bsxfun(@times,X,R.logProbabilities); term1(isnan(term1)) = 0; %false*-inf = NaN;
            term2 = bsxfun(@times,~X,R.logOneMinusProbabilities); term2(isnan(term2)) = 0; %false*-inf = NaN;
            vals = sum(term1 + term2,2);
        end

        function vals = draw(R,N)
            % DRAW  Draw random samples from the distribution described by the prtRv object
            %
            % VAL = RV.draw(N) generates N random samples drawn from the
            % distribution described by the prtRv object RV. VAL will be a
            % N x nDimensions vector, where nDimensions is the number of
            % dimensions of RV.

            assert(numel(N)==1 && N==floor(N) && N > 0,'N must be a positive integer scalar.')
            [isValid, reasonStr] = R.isValid;
            assert(isValid,'DRAW cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);

            vals = bsxfun(@ge , rand(N,R.nDimensions), R.probabilities);
        end
    end

    methods (Hidden=true)
        function [val, reasonStr] = isValid(R)

            if numel(R) > 1
                val = false(size(R));
                for iR = 1:numel(R)
                    [val(iR), reasonStr] = isValid(R(iR));
                end
                return
            end

            val = ~isempty(R.probabilities);

            if val
                reasonStr = '';
            else
                reasonStr = 'because probabilities has not been set';
            end
        end

        function R = weightedMle(R,X,weights)

            assert(numel(weights)==size(X,1),'The number of weights must mach the number of observations.');

            if ~islogical(X)
                assert(isnumeric(X) && all(all(X >= 0 & X<=1)),'prt:prtRvMvb:mle','input data to prtRvMvb.mle must contain values between 0 and 1')
            end

            weights = weights(:);

            R.probabilities = sum(bsxfun(@times,X,weights))/sum(weights);

        end

        function initMembershipMat = initializeMixtureMembership(Rs,X)

            learningInitialMembershipFactor = 0.9;

            [classMeans,kmMembership] = prtUtilKmeans(X,length(Rs),'handleEmptyClusters','random','distanceMetricFn',@prtDistanceHamming,'maxIterations',100,'logicalMeans',true); %#ok<ASGLU>

            initMembershipMat = zeros(size(X,1),length(Rs));
            for iComp = 1:length(Rs)
                initMembershipMat(kmMembership == iComp, iComp) = learningInitialMembershipFactor;
            end
            initMembershipMat(initMembershipMat==0) = (1-learningInitialMembershipFactor)./(length(Rs)-1);

            % We should normalize this just in case the
            % learningInitialMembershipFactor was set poorly
            initMembershipMat = bsxfun(@rdivide,initMembershipMat,sum(initMembershipMat,2));
        end
    end

    % Get methods
    methods
        function val = get.nDimensions(R)
            val = getNumDimensions(R);
        end
        function val = get.probabilities(R)
            val = R.probabilitiesDepHelper;
        end
        function val = get.minProbability(R)
            val = R.minProbabilityDepHelper;
        end
        function val = get.maxProbability(R)
            val = R.maxProbabilityDepHelper;
        end
        function val = get.logProbabilities(R)
            val = log(R.probabilities);
        end
        function val = get.logOneMinusProbabilities(R)
            val = log(1 - R.probabilities);
        end
    end

    methods (Access = 'protected')
        function val = getNumDimensions(R)
            if ~isempty(R.probabilities)
                val = length(R.probabilities);
            else
                val = [];
            end
        end
    end
    % Set Methods
    methods
        function R = set.probabilities(R,val)
            assert((isnumeric(val) || islogical(val)) && isvector(val),'probabilities must be a vector of values between 0 and 1 (inclusively');
            assert(all(val<=1 & val>=0),'prt:prtRvMvb:badProbabilities','probabilities must have values between 0 and 1 (inclusively)')

            val = val(:)';

            val(val>R.maxProbability) = R.maxProbability;
            val(val<R.minProbability) = R.minProbability;

            R.probabilitiesDepHelper = val;
        end

        function R = set.minProbability(R,val)
            assert(prtUtilIsPositiveScalar(val) && val<=1 && val>=0,'minProbability must be a value between 0 and 1 (inclusively)');
            R.minProbabilityDepHelper = val;
        end
        function R = set.maxProbability(R,val)
            assert(prtUtilIsPositiveScalar(val) && val<=1 && val>=0,'maxProbability must be a value between 0 and 1 (inclusively)');
            R.maxProbabilityDepHelper = val;
        end

    end
end


function M = imfiltermtx(F, sz, bndry);
%IMFILTERMTX   N-D image filtering matrix
%   M = IMFILTERMTX(F, SZ[, BNDRY]) returns the image filtering matrix
%   for the matrix F.  SZ gives the size of the array that the filtering
%   (convolution) should be applied to.  The returned matrix M is sparse.
%   If X is of size SZ, then reshape(M * X(:), SZ + size(F) - 1) is the
%   same as imfilter(X, F, BNDRY, 'conv').
%
%   The optional parameter BNDRY controls the boundary handling:
%     * 'replicate':  Input array values outside the bounds of the array
%                     are assumed to equal the nearest array border
%                     value.
%     * 'circular':   Input array values outside the bounds of the array
%                     wrap around to the opposite bound.
%     * '0':          (default) Input array values outside of the bounds
%                     of the array are assumed to be zero.
%
%   See also IMFILTER, MAKE_IMFILTER_MAT.
%
%   Author:  Stefan Roth, Department of Computer Science, TU Darmstadt
%   Contact: sroth@cs.tu-darmstadt.de
%   $Date: 2007-03-27 14:09:11 -0400 (Tue, 27 Mar 2007) $
%   $Revision: 252 $

% Copyright 2004-2007, Brown University, Providence, RI. USA
% Copyright 2007-2010 TU Darmstadt, Darmstadt, Germany.
%
%                          All Rights Reserved
%
% All commercial use of this software, whether direct or indirect, is
% strictly prohibited including, without limitation, incorporation into in
% a commercial product, use in a commercial service, or production of other
% artifacts for commercial purposes.
%
% Permission to use, copy, modify, and distribute this software and its
% documentation for research purposes is hereby granted without fee,
% provided that the above copyright notice appears in all copies and that
% both that copyright notice and this permission notice appear in
% supporting documentation, and that the name of the author and Brown
% University not be used in advertising or publicity pertaining to
% distribution of the software without specific, written prior permission.
%
% For commercial uses contact the Technology Venture Office of Brown University
%
% THE AUTHOR AND BROWN UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO
% THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
% FITNESS FOR ANY PARTICULAR PURPOSE.  IN NO EVENT SHALL THE AUTHOR OR
% BROWN UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
% DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
% PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
% ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
% THIS SOFTWARE.

  % Size of padding for boundary handling
  pad_size = 0.5 * (size(F) - 1);

  % Corners of the original image in the padded image
  corner_lo = 1 + pad_size;
  corner_hi = size(F) + sz - 1 - pad_size;

  % Pixel index of the output image M
  M_idx = zeros(sz + size(F) - 1);
  M_idx(:) = 1:numel(M_idx);

  % Pixel index of the "input" image X
  X_idx = zeros(sz);
  X_idx(:) = 1:numel(X_idx);
  % Pad it to the size of M
  X_idx = [zeros(pad_size(1), sz(2) + size(F, 2) - 1); ...
           zeros(sz(1), pad_size(2)), X_idx, zeros(sz(1), pad_size(2)); ...
           zeros(pad_size(1), sz(2) + size(F, 2) - 1)];

  switch(bndry)
    case 'symmetric'
      error('Not implemented yet!')

    case 'replicate'
      % Replicate pixel values from the edges & corners

      % Fill all 4 corners
      for c = 0:3

        % Position or corner and range of block next to corner
        pos = cell(1, 2);
        rng = cell(1, 2);
        for d = 1:2
          if bitand(c, 2^(d-1))
            pos{d} = corner_hi(d);
            rng{d} = corner_hi(d)+1:size(M_idx, d);
          else
            pos{d} = corner_lo(d);
            rng{d} = 1:corner_lo(d)-1;
          end
        end

        % Get index of corner pixel
        idx = sub2ind(size(M_idx), pos{:});

        % Set entire block to corner pixel index
        M_idx(rng{:}) = idx;

      end

      % Fill all 4 edges
      for d = 1:2
        for c = 0:3

          % I don't quite understand this code anymore, but it appears to
          % work fine :)
          pos = cell(1, 2);
          rng = cell(1, 2);
          for e = 1:2
            if (d == e)
              pos{d} = corner_lo(e):corner_hi(e);
              rng{d} = corner_lo(e):corner_hi(e);
            else
              if bitand(c, 2^(e-1))
                pos{e} = repmat(corner_hi(e), 1, sz(d));
                rng{e} = corner_hi(e)+1:size(M_idx, e);
              else
                pos{e} = repmat(corner_lo(e), 1, sz(d));
                rng{e} = 1:corner_lo(e)-1;
              end
            end
          end

          % Get indices of edge pixels
          idx = sub2ind(size(M_idx), pos{:});

          % Generate fill indices from the nearest edge pixel
          tmp_sz = pad_size;
          tmp_sz(d) = 1;
          tmp2_sz = ones(1, 2);
          tmp2_sz(d) = sz(d);
          M_idx(rng{:}) = repmat(reshape(idx, tmp2_sz), tmp_sz);
        end
      end

      % Convert indices from the output image to the input image
      M_idx = X_idx(M_idx);

    case 'circular'
      % Create padded indices of rows and columns
      r = -pad_size(1)+1:sz(1)+pad_size(1);
      c = -pad_size(2)+1:sz(2)+pad_size(2);

      % Take the modolus to make sure they are in the valid bounds
      r = 1 + mod(r - 1, sz(1));
      c = 1 + mod(c - 1, sz(2));

      M_idx = sub2ind(sz, repmat(r(:), 1, length(c)), ...
                      repmat(c(:)', length(r), 1));

    otherwise
      % Assume all zeros outside of the boundaries
      M = convmtxn(F, sz);
      return;

  end

  % The pixel indices give a mapping of the columns of the padded image
  % to the output image
  col_map = M_idx(:);

  % Get convolution matrix and split the resulting sparse array
  M = make_convn_mat(F, sz + size(F) - 1, 'same');
  [rows, cols, vals] = find(M);

  % Re-assemble the sparse array, but use the column map to accumulate
  % rows appropriately
  M = sparse(rows, col_map(cols), vals, prod(size(F) + sz - 1), prod(sz));


function v = value( x, data )
global cvx___
if nargin == 1,
    data = cvx___.x;
end
nx = size( data, 1 );
nb = size( x.basis_, 1 );
if nx < nb,
    data( end + 1 : nb, : ) = NaN;
elseif nx > nb,
    data( nb + 1 : end, : ) = [];
end
v = cvx_reshape( data.' * x.basis_, x.size_ );
if any( x.size_ == 1 ), v = full( v ); end

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Spherical Harmonic Modeling and Analysis Toolkit (SPHARM-MAT) is a 3D
% shape modeling and analysis toolkit.
% It is a software package developed at Shenlab in Center for Neuroimaging,
% Indiana University (SpharmMat@gmail.com, http://www.iupui.edu/~shenlab/)
% It is available to the scientific community as copyright freeware
% under the terms of the GNU General Public Licence.
%
% Copyright 2009, 2010, ShenLab, Center for Neuroimaging, Indiana University
%
% This file is part of SPHARM-MAT.
%
% SPHARM-MAT 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.
%
% SPHARM-MAT 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 SPHARM-MAT. If not, see <http://www.gnu.org/licenses/>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [vertices, sph_verts, faces, fvec, new_name]=align_CPS_SHREC(filename, confs)
global fact;
global sgm;

gran = confs.GroupAlpha;  % gran = # of alphas to process together
res = [confs.BaseRes confs.HierarchyStep confs.HierarchyDepth confs.Top_K confs.GammaRes];
% base res R + step of hierarchy Hs + depth of hierarchy Hd + top N + 3rd Angle res (gammares)

switch upper(deblank(char(confs.NormalizeSize)))
    case 'YES'
        scale = 1;
    case 'NO'
        scale = 0;
end

% factorial(170) = Inf
for i=0:170
    fact(i+1) = factorial(i);
end

utl_sgm(15);

% Load a template object
load(confs.Template);
[fvec, max_d] = fixed_fvec(fvec,confs.MaxSPHARMDegree,scale);
%tvertices = vertices; tsph_verts=sph_verts; tfvec = fvec;
tfvec = fvec;

load(filename);
[fvec, max_d] = fixed_fvec(fvec,confs.MaxSPHARMDegree,scale);
[path,name,ext] = fileparts(filename);

if ~exist('faces', 'var') | ~exist('vertices', 'var') | ~exist('sph_verts', 'var') | ~exist('fvec', 'var')
    disp('One or more of faces, vertices, spherical vertices, or SPHARM descriptor are missing');
    return;
end

rmsd_org = SPHARM_rmsd(fvec, tfvec);

if rmsd_org > 0

    % create samples in rotation space
    [alpha, beta, gamma] = utl_eas(res); % euler_angle hierarchy

    % initial alignment using ICP
    [fvec_icp, Robj_icp] = match_icp(fvec, tfvec, max_d);
    [fvec_icp, Aprm] = match_param_hie(fvec_icp,tfvec,alpha,beta,gamma,gran,res,max_d);
    [fvec_icp, Robj_icp] = match_cps(fvec_icp, tfvec, max_d);

    % assume that fvec and atlas are roughly aligned in the object space
    [fvec_cps, Robj_cps] = match_cps(fvec, tfvec, max_d);

    rmsd_icp = SPHARM_rmsd(fvec_icp, tfvec);
    rmsd_cps = SPHARM_rmsd(fvec_cps, tfvec);

    disp(sprintf('RMSD: org %0.3f, icp %0.3f, cps %0.3f',rmsd_org,rmsd_icp,rmsd_cps))

    if rmsd_org > min(rmsd_icp,rmsd_cps)
        if rmsd_icp < rmsd_cps
            fvec = fvec_icp;
            Robj = Robj_icp;
        else
            fvec = fvec_cps;
            Robj = Robj_cps;
        end
    end

    % assume that fvec and atlas are roughly aligned in both object and
    % parameter spaces
    for k = 1:5
        rmsd(1) = SPHARM_rmsd(fvec, tfvec);

        % use cps to align objects together first
        [fvec_a, Robj] = match_cps(fvec, tfvec, max_d);
        rmsd(2) = SPHARM_rmsd(fvec_a, tfvec);

        if rmsd(2)<rmsd(1)
            fvec = fvec_a; % update
        end

        % assume aligned in object space, register the parameterization
        [fvec, Aprm] = match_param_hie(fvec,tfvec,alpha,beta,gamma,gran,res,max_d);
        rmsd(3) = SPHARM_rmsd(fvec, tfvec);

        disp(sprintf('Base Res %d, Step %d, Depth %d, Top %d, Gamma %d: RMSD %0.3f => %0.3f => %0.3f',res,rmsd));

        if sum(abs(Aprm(:)))==0
            break;
        end
    end
else
    disp(sprintf('RMSD = %d: Individual (%s) is the same as template (%s)',rmsd_org,filename,confs.Template));
end

new_name = sprintf('%s/%sSHREC_reg.mat',confs.OutDirectory, name(1:end-3));
if exist(new_name,'file')
    prompt = {'Enter new filename:'};
    dlg_title = 'New File Name';
    num_lines = 1;
    def = {new_name};
    answer = inputdlg(prompt,dlg_title,num_lines,def);
    new_name = answer{1};
end
save(new_name, 'fvec');

clear('fact','sgm');

return;


% Run a simulation with modified enzyme kinetics
%
% Author: Jonathan Karr, jkarr@stanford.edu
% Affilitation: Covert Lab, Department of Bioengineering, Stanford University
% Last updated: 1/24/2013
classdef ModifiedMetabolicEnzymeKinetics < edu.stanford.covert.cell.sim.runners.SimulationRunner
    properties
        %Structure containing modified metabolic enzyme kinetics.
        %kCatFor, kCatRev should have units (rxn/enzyme/s).
        %Set kCatFor, kCatRev to NaN to use default value.
        modifiedKinetics = repmat(struct(...
            'reactionWholeCellModelID', '', ...
            'kCatFor', NaN, ...
            'kCatRev', NaN ...
            ), 0, 1);
    end

    methods
        function this = ModifiedMetabolicEnzymeKinetics(varargin)
            this = this@edu.stanford.covert.cell.sim.runners.SimulationRunner(varargin{:});
        end
    end

    methods (Access = protected)
        function modifyNetworkParameters(this, sim)
            %get handles
            met = sim.process('Metabolism');

            %calculate indices of modified reactions
            ids = {this.modifiedKinetics.reactionWholeCellModelID}';
            kCatFor = [this.modifiedKinetics.kCatFor]';
            kCatRev = [this.modifiedKinetics.kCatRev]';

            if numel(unique(ids)) < numel(ids)
                throw(MException('ModifiedMetabolicEnzymeKinetics:invalidReactionList', ...
                    'Modified reaction list cannot contain multiple entries for a given reaction.'));
            end

            idxs = met.reactionIndexs(ids);

            %modify kcats
            met.enzymeBounds(idxs(~isnan(kCatRev)), 1) = kCatRev(~isnan(kCatRev));
            met.enzymeBounds(idxs(~isnan(kCatFor)), 2) = kCatFor(~isnan(kCatFor));
            met.fbaEnzymeBounds(met.fbaReactionIndexs_metabolicConversion, :) = met.enzymeBounds(met.reactionIndexs_fba, :);
        end
    end
end


function [] = fitKnownShapes(shapeModelOpt,statesDir,inferredShapesDir)

%% Setup optimization parameters
params = get_params();
relaxOpt = params.opt.relaxOpt;
lambda = params.opt.lambda;
maxiter = params.opt.testIters;
Sbar = shapeModelOpt.S;
V = shapeModelOpt.V;
N = shapeModelOpt.normals;
tri = shapeModelOpt.tri;
shapePriorInstance = shapeModelOpt.shapePriorInstance;

%% Read file names to fit basis shapes to
fnames = getFileNamesFromDirectory(statesDir,'types',{'.mat'});
fnames = removeFlipNames(fnames);

%% Fit basis shapes
pBar =  TimedProgressBar( length(fnames), 30, ...
    'Fitting Basis shapes: Remaining ', ', Completed ', 'Fitted Basis Shapes in: ' );

parfor i=1:length(fnames)
    optimizeTestShape(fullfile(statesDir,fnames{i}),lambda,Sbar,V,N,tri,...
        shapePriorInstance,maxiter,fullfile(inferredShapesDir,fnames{i}),relaxOpt,params);
    pBar.progress();
end
pBar.stop();

end

%% Helper function to actually do the optimization
function [] = optimizeTestShape(fname,lambda,Sbar,V,N,tri,shapePriorInstance,maxiter,saveFile,relaxOpt,params)
%% PARAMS
stepsize = params.opt.testStepSize;
maxDelta = params.opt.maxDelta(3);

stateFile = fname;
state = load(stateFile);state = state.state;
K = size(V,2);
alpha = zeros(K,1);
numpoints = size(Sbar,1);

if(exist(saveFile,'file'))
    return;
end
%% iterations to learn alpha
initRot = state.cameraRot;
for iter=1:maxiter
    stepScale = 1;
    stepTr = 0.1;
    stepRot = 0.002;
    rotPriorStep = 0.1;

    if(det(state.cameraRot)>1.0001 || det(state.cameraRot)<0.9999)
        q = dcm2quat(state.cameraRot);
        state.cameraRot = quat2dcm(q/norm(q)); %wish I didn't have to do this - but such is life !
    end

    S = Sbar + reshape(V*alpha(:,1),numpoints,3);

    % Visualization
    if(mod(iter,10)==-1)
         vertices = S;
         subplot(2,2,1);
         verticesP = (state.cameraRot*vertices')';
         plot3(verticesP(:,1),verticesP(:,2),verticesP(:,3),'r.');
         axis equal;axis vis3d;view(0,-90);
         %disp(state.cameraRot);
         xlabel('x');ylabel('y');zlabel('z');

         subplot(2,2,2);
         p2 = transform2d(vertices,state.cameraRot,state.cameraScale,state.translation);
         imshow(color_seg(state.mask,state.im)); hold on; axis equal;axis off;axis vis3d;
         plot(p2(:,1),p2(:,2),'r.');

         subplot(2,2,3);
         imagesc(state.im);axis equal;axis off;axis vis3d;
         if(iter > maxiter - 10)
             disp('done');
             pause();close all;
         else
             pause(0.02);
         end
         clf
    end

    %% Image projection of points
    p2d = transform2d(S,state.cameraRot,state.cameraScale,state.translation);
    p2d = round(p2d);

    %% Occlusion Reasoning
    [occGrad,~] = occlusionGradOptimal(S,state,p2d);
    occGrad = lambda(1)*occGrad;

    %% Silhouette Consistency

    if(mod(iter-1,20)==0 || sum(ismember({'scale','translation'},relaxOpt)))
        % Finding projected points
        tree = vl_kdtreebuild(p2d');
    end
    silGrad = lambda(2)*silhouetteGrad(S,state,params, tree,p2d); %we also keep track of how many constraints each point violates
    silGrad = silGrad*500; % because we divide by number of silhouette points

    %% Keypoint Gradient
    if(ismember('kps',relaxOpt) && ~isempty(state.kps))
        kpGrad = lambda(6)*keypointGrad(S,state,params);
    else
        kpGrad = zeros(size(S));
    end

    %% Priors
    gradPriorAlpha = -(lambda(4)*numpoints)*alpha;
    shapePriorGrad = lambda(5)*shapePriorInstance(S);

    %% translation and scale gradients
    gradS2d = occGrad + silGrad + kpGrad;
    gradP3d = state.cameraScale*state.cameraRot*gradS2d';
    gradP2d = gradP3d(1:2,:);
    gradTr = mean(gradP2d,2);
    Sbar2d = bsxfun(@minus,p2d,mean(p2d,1));Sbar2d = Sbar2d';
    gradScale = mean(gradP2d(:).*Sbar2d(:))/state.cameraScale;

    %% Rotation gradients (experimental)
    gradRot = gradP3d*S/numpoints;
    %R = R_0 * expm(delta) = R_0(I+delta)
    gradDelta = state.cameraRot*gradRot;
    gradSkewDelta = (gradDelta-gradDelta')/2;
    deltaPrior = real(logm(state.cameraRot'*initRot));
    deltaPrior(abs(deltaPrior)<eps) = 0;
    normTwist = norm(gradSkewDelta,'fro');

    %% Deformation weight gradients
    gradShapePriorAlpha(:,1) = V'*shapePriorGrad(:);
    gradSilAlpha = V'*silGrad(:);
    gradOcclusionAlpha = V'*occGrad(:);
    gradKeypointAlpha = V'*kpGrad(:);
    gradAlpha = gradOcclusionAlpha + gradPriorAlpha + gradSilAlpha + gradShapePriorAlpha + gradKeypointAlpha; % + gradICPAlpha

    %% Updating transformation parameters
    step = min(maxDelta/max(max(abs(gradAlpha))),stepsize);
    if(iter > maxiter/2)
        alpha = alpha+step*gradAlpha;
    end
    stepScale = min(stepScale,0.02*state.cameraScale/abs(gradScale));
    if(ismember('scale',relaxOpt))
        state.cameraScale = state.cameraScale + gradScale*stepScale;
    end
    stepTr = min(stepTr,2/max(abs(gradTr)));
    if(ismember('translation',relaxOpt))
        state.translation = state.translation + gradTr*stepTr;
    end
    if(ismember('rotation',relaxOpt))
        stepRot = min(stepRot,pi/(50*normTwist));
        %stepRot = min(stepRot,pi/(25*normTwist));
        delta = expm(stepRot*gradSkewDelta + deltaPrior*rotPriorStep);
        if(det(delta) ~= 1)
            %disp('wtf');
	        %keyboard;
            %delta(1,:) = delta(1,:)/norm(delta(1,:));
            %delta(2,:) = delta(2,:)/norm(delta(2,:));
            %delta(3,:) = delta(3,:)/norm(delta(3,:));
        end
        state.cameraRot = state.cameraRot*delta;
    end
end

S = Sbar + reshape(V*alpha,numpoints,3);

%% Saving
state.alpha = alpha;
state.normals = N;
state.tri = tri;
state.S = S;
save(saveFile,'state');

end


% read_rdf() - read RDF-formatted EEG files.
%
% Usage:
%   >> [eeg,ev,header] = read_rdf(filename);
%
% Inputs:
%   filename - EEG data file in RDF format
%
% Outputs:
%   eeg - eeg data (array in size of [chan_no timepoint];
%   ev  - event structure
%      ev.sample_offset[] - event offsets in samples
%                           from the first sample (0)
%      ev.event_code[]    - event codes (integers)
%   header - data structure for header information
%      header.ch_no     - number of channels
%      header.sample_no - number of samples

% Notes:
%
% Authors: Jeng-Ren Duann, CNL/Salk & INC/UCSD, 2002-12-12
%          with help from Andrey Vankov, creator of the RDF file format.

function [eeg,ev,header] = read_rdf(filename)

    if nargin < 1
        help read_rdf;
        return;
    end;

  eeg = [];
  ev = [];
  header = [];

  fp = fopen(filename,'rb','ieee-le');
  if fp == -1,
    disp('read_RDF(): Cannot open data file...!');
    return;
  end

  fseek(fp,6,-1);
  header.ch_no = fread(fp,1,'uint16');

  cnt = 0;
  ev_cnt = 0;
  while(~feof(fp)),
    tag = fread(fp,1,'uint32');
    if length(tag) == 0,
      break;
    end
    if tag == hex2dec('f0aa55'),
      cnt = cnt + 1;
      disp(['block ' num2str(cnt) ' found']);
      % read ch_no and block length
      fseek(fp,2,0);
      ch_no = fread(fp,1,'uint16');
      block_size = power(2,fread(fp,1,'uint16'));
      % read events
      fseek(fp,62,0);
      for i=1:110,
	samp_off = fread(fp,1,'char');
	cond_code = fread(fp,1,'char');
	ev_code = fread(fp,1,'uint16');
	if samp_off ~= 0,
	  ev_cnt = ev_cnt + 1;
	  ev(ev_cnt).sample_offset = samp_off + (cnt-1)*128;
	  ev(ev_cnt).event_code = ev_code;
	end
      end
      data = fread(fp,ch_no*block_size,'int16');
      data = reshape(data,ch_no,block_size);
      eeg = [eeg data];
    end
  end

  fclose(fp);
  header.sample_no = size(eeg,2);


%% SOLAR SYSTEM EXAMPLE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This setup function configures an objectIndex that resembles our solar
% system in their orbital configuration.

% ADD THE PROGRAM PATHS
clear all; close all;
addpath('environment');
addpath('objects');
addpath('scenarios');

fprintf('[SETUP]\tAssembling the solar system example.\n');

%% SIMULATION PARAMETERS
[~, userdir]   = system('echo %USERPROFILE%'); % Get desktop path
sim_outputPath = strcat(userdir,'\desktop\OpenMAS_data');
sim_vebosity   = 1;
sim_warningDistance = 1;
sim_threadPool = 0;
sim_maxDuration = 92*60;
sim_timeStep    =  60;
sim_figureSet = {'fig','gif'};

%% SCENARIO PARAMETERS
sim_plotScenario = 1;
sim_agentOrbit  = 3;
sim_waypointOrbit = 10;
sim_offsetAngle = 0;
sim_agentVelocity = 0;
sim_noiseSigma = 0.0;

%% INITIALISE THE OBJECT SCENARIO
fprintf('[SETUP]\tAssigning object definitions:\n');

objectIndex = getScenario_earthOrbit('plot',sim_plotScenario,'scale',5E3);                 % Generate the earth

%% %%%%%% INITIALISE THE SIMULATION WITH THE OBJECT INDEX %%%%%%%%%%%%%%%%%
[DATA,META] = OMAS_initialise('objects',objectIndex,...
                             'duration',sim_maxDuration,...
                                   'dt',sim_timeStep,...
                              'figures',sim_figureSet,...
                      'warningDistance',sim_warningDistance,...
                            'verbosity',sim_vebosity,...
                           'threadPool',sim_threadPool,...
                           'outputPath',sim_outputPath);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clearvars -except DATA META
load(strcat(META.outputPath,'META.mat'));
load(strcat(META.outputPath,'EVENTS.mat'));


%kkcube 'Output = Input**3'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros kcube.pane file
%
% Parameters:
% InputFile: i1 'Input ', required: 'Input data object'
% OutputFile: o 'Output', required: 'Resulting output data object'
%
% Example: o = kkcube(i1, {'i1','';'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% kcube - Output = Input**3
%
%  DESCRIPTION
% Output = Input*Input*Input
%
% The "Cube" operator returns the cube (value raised to the power of 3)
% of each data
% point in the input data object, \fBInput".
%
% Executing "Cube" runs the program \fIkarith2\fP
% with the -pow flag and -real 3.0 -imag 0.0.
%
%
%  "Data Type " 5
% .cI $DATAMANIP/repos/shared/man/sections/value_type_1input
%
%  "Map Data" 5
% .cI $DATAMANIP/repos/shared/man/sections/map_1input
%
%  "Validity Mask" 5
% .cI $DATAMANIP/repos/shared/man/sections/mask_1input
%
%  "Explicit Location and Time Data" 5
% .cI $DATAMANIP/repos/shared/man/sections/loc_and_time_1input
%
%  "Failure Modes"
% .cI $DATAMANIP/repos/shared/man/sections/fail_1input
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
% DATAMANIP::karith2
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kkcube(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kkcube(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i1', '__input';'o', '__output'};
maxval={0,0};
minval={0,0};
istoggle=[0,0];
was_set=istoggle * 0;
paramtype={'InputFile','OutputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'karith2"  -pow'],Inputs,narglist);


classdef IN1KMOP3 < EvoXBenchProblem
% <multi> <real> <large/none> <expensive/none>

%------------------------------- Reference --------------------------------
% Z. Lu, R. Cheng, Y. Jin, K. C. Tan, and K. Deb, Neural architecture
% search as multiobjective optimization benchmarks: Problem formulation and
% performance assessment, IEEE Transactions on Evolutionary Computation,
% 2023.
%--------------------------------------------------------------------------

    methods
        %% Default settings of the problem
        function Setting(obj)
            config.name = 'resnet';
            config.args.objs = 'err&params&flops';
            config.args.normalized_objectives = false;
            obj.Setting@EvoXBenchProblem(config);
        end
    end
end


function [stack, norm_value] = ReadLDRStack(dir_name, format, bNormalization, bToSingle)
%
%       [stack, norm_value] = ReadLDRStack(dir_name, format, bNormalization, bToSingle)
%
%       This function reads an LDR stack from a directory, dir_name, given
%       an image format.
%
%        Input:
%           -dir_name: the path where the stack is
%           -format: the LDR format of the images that we want to load in
%           the folder dir_name. For example, it can be 'jpg', 'jpeg',
%           'png', 'tiff', 'bmp', etc.
%           -bNormalization: is a flag for normalizing or not the stack in
%           [0, 1].
%           -bToSingle:
%
%        Output:
%           -stack: a stack of LDR images, in floating point (single)
%           format. No normalization is applied.
%           -norm_value:
%
%     This function reads a stack of images from the disk
%
%     Copyright (C) 2011-16  Francesco Banterle
%
%     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/>.
%

if(~exist('bNormalization', 'var'))
    bNormalization = 0;
end

if(~exist('bToSingle', 'var'))
    bToSingle = 1;
end

if(bNormalization)
    bToSingle = 1;
end

norm_value = 1.0;

list = dir([dir_name, '/*.', format]);
n = length(list);

if(n > 0)
    img_info = [];
    name = [dir_name, '/', list(1).name];

    try
        if(exist('imfinfo') == 2)
            img_info = imfinfo(name);
        end
    catch err
        disp(err);

        try
            if(exist('exifread') == 2)
                img_info = exifread(name);

                if(isfield(img_info, 'SamplesPerPixel'))
                    if(img_info.SamplesPerPixel == 3)
                        img_info.ColorType = 'truecolor';
                    end

                    if(img_info.SamplesPerPixel == 1)
                        img_info.ColorType = 'grayscale';
                    end
                else
                    img_info.ColorType = 'truecolor';
                end

                if(isfield(img_info, 'BitsPerSample'))
                    img_info.BitDepth = round(mean(img_info.BitsPerSample));
                else
                    img_info.BitDepth = 8;
                end

                if(isfield(img_info, 'ImageWidth'))
                    img_info.Width = img_info.ImageWidth;
                end

                if(isfield(img_info, 'ImageLength'))
                    img_info.Height = img_info.ImageLength;
                end

                if(isfield(img_info, 'PixelXDimension'))
                    img_info.Width = PixelXDimension;
                end

                if(isfield(img_info, 'PixelYDimension'))
                    img_info.Height = PixelYDimension;
                end
            end
        catch
            disp(err);
        end
    end

    colorChannels = 0;

    norm_value = 255.0;

    if(~isempty(img_info))
        if(isfield(img_info, 'NumberOfSamples'))
            colorChannels = img_info.NumberOfSamples;
        else
            switch img_info.ColorType
                case 'grayscale'
                    colorChannels = 1;

                    switch img_info.BitDepth
                        case 8
                            norm_value = 255.0;
                        case 16
                            norm_value = 65535.0;
                    end

                case 'truecolor'
                    colorChannels = 3;

                    switch img_info.BitDepth
                        case 24
                            norm_value = 255.0;
                        case 48
                            norm_value = 65535.0;
                    end
            end
        end

        if(img_info.Height == 0 || img_info.Width == 0)
            tmp = imread(name);
            [img_info.Height, img_info.Width, n] = size(tmp);
            clear('tmp');
        end

        stack = zeros(img_info.Height, img_info.Width, colorChannels, n, 'single');

        for i=1:n
            disp(list(i).name);
            %read an image, and convert it into floating-point
            img_tmp = imread([dir_name, '/', list(i).name]);

            %store in the stack
            if(bToSingle)
                stack(:,:,:,i) = single(img_tmp);
            else
                stack(:,:,:,i) = img_tmp;
            end
        end

        if(bNormalization)
            stack = stack / norm_value;
        end
    else
        warning('The stack is empty!');
        stack = [];
    end
else
    warning('The stack is empty!');
    stack = [];
end

end


%%
%  Copyright (c) 2014, Facebook, Inc.
%  All rights reserved.
%
%  This source code is licensed under the BSD-style license found in the
%  LICENSE file in the root directory of this source tree. An additional grant
%  of patent rights can be found in the PATENTS file in the same directory.
%
%%
function  [fail_idx, patches] = extract_person_patches(config, hits, dims, ...
    width_zoom, height_zoom,y_offset)
%Cropping people bounds

assert(config.DATASET == config.DATASET_ICCV);
bounds = int32(hits.bounds);
bounds(3:4,:) = bounds(3:4,:) + bounds(1:2,:);
bounds(1,:) = max(1,bounds(1,:));
bounds(2,:) = max(1,bounds(2,:));
patches = zeros([dims 3 hits.size],'uint8');
tic;
parfor i=1:hits.size
    img = load_image(hits.image_id(i),config);
    img = img(bounds(2,i):min(size(img,1),bounds(4,i)), ...
        bounds(1,i):min(size(img,2),bounds(3,i)),:);
    patches(:,:,:,i) = imresize(img, dims);
end
toc;
fail_idx = [];
end