function plotTree(nodes, cats, subTree, figLabelHierarchy)
% plotTree(nodes, cats, subTree, figLabelHierarchy)
%
% Plot a tree using the results of the CocoStuffClasses.getClassHierarchyX() functions.
%
% subTree: (optional) +-1 for left/right sub tree, 0 for the entire tree
% figLabelHierarchy: (optional) handle to a figure
%
% Copyright by Holger Caesar, 2017

% By default we plot the entire tree
if ~exist('subTree', 'var')
    subTree = 0;
end

% Create figure if necessary
if ~exist('figLabelHierarchy', 'var')
    figLabelHierarchy = figure();
end

% Check that tree is binary at the top node
firstChildren = find(nodes == 1);
assert(numel(firstChildren) == 2);

% Get only relevant nodes and cats
if subTree ~= 0
    % Find descendents of the specified startTreeInd node
    sel = false(size(nodes));
    if subTree == -1
        sel(firstChildren(1)) = true;
    elseif subTree == 1
        sel(firstChildren(2)) = true;
    end
    while true
        oldSel = sel;
        sel = sel | ismember(nodes, find(sel));
        if isequal(sel, oldSel)
            break;
        end
    end
    nodes = nodes(sel);
    cats = cats(sel);

    % Remap nodes in 0:x range
    map = false(max(nodes), 1);
    map(unique(nodes)) = true;
    map = cumsum(map)-1;
    nodes = map(nodes);
end

% Plot them
ax = axes('Parent', figLabelHierarchy, 'Units', 'Norm');
axis(ax, 'off');
treeplot(nodes');
moveLeft = 0.08;
if subTree == -1
    set(ax, 'Position', [0-moveLeft,   0, 0.5+moveLeft, 1]);
elseif subTree == 1
    set(ax, 'Position', [0.5-moveLeft, 0, 0.5+moveLeft, 1]);
end
[xs, ys] = treelayout(nodes);

% Set appearance settings and show labels
isLeaf = ys == min(ys);
textInner = text(xs(~isLeaf) + 0.01, ys(~isLeaf) - 0.025, cats(~isLeaf), 'VerticalAlignment', 'Bottom', 'HorizontalAlignment', 'right'); %#ok<NASGU>
textLeaf  = text(xs( isLeaf) - 0.01, ys( isLeaf) - 0.02,  cats( isLeaf), 'VerticalAlignment', 'Bottom', 'HorizontalAlignment', 'left'); %#ok<NASGU>
set(ax, 'XTick', [], 'YTick', [], 'Units', 'Normalized');
ax.XLabel.String = '';
axis off;

% Rotate view
camroll(90);


function test_example_ica_eog

% MEM 8gb
% WALLTIME 00:30:00

%
%% Use independent component analysis (ICA) to remove EOG artifacts
%
%% # Description
%
% This script demonstrates how you can use ICA for cleaning the EOG artifacts from your MEG data. It consists of three steps:
%
% #  decomposition of the MEG data
% #  identifying the components that reflect eye artifacts
% #  removing those components and backprojecting the data
%
%% # Example dataset
%
% You can run the code below on your own data. Alternatively, try with the example MEG dataset _ArtifactMEG.ds_ (available from [ftp://ftp.fieldtriptoolbox.org/pub/fieldtrip/tutorial/ArtifactMEG.zip](ftp://ftp.fieldtriptoolbox.org/pub/fieldtrip/tutorial/ArtifactMEG.zip)). This dataset was acquired continuously with trials of 10 seconds. All figures in this example script are based on these data.
%
% To load this dataset into MATLAB and preprocess with FieldTrip, use:
%
% preprocessing of example dataset
cfg = [];
cfg.dataset            = dccnpath('/home/common/matlab/fieldtrip/data/ftp/test/ctf/ArtifactMEG.ds');
cfg.trialdef.eventtype = 'trial';
cfg = ft_definetrial(cfg);

cfg.channel            = 'MEG';
cfg.continuous         = 'yes';
data = ft_preprocessing(cfg);

% downsample the data to speed up the next step
cfg = [];
cfg.resamplefs = 300;
cfg.detrend    = 'no';
data = ft_resampledata(cfg, data);

%% # ICA decomposition
%
% After reading in the preprocessed data into memory in FieldTrip format, you can continue with decomposing it in independent components.
%
% perform the independent component analysis (i.e., decompose the data)
cfg        = [];
cfg.method = 'runica'; % this is the default and uses the implementation from EEGLAB

comp = ft_componentanalysis(cfg, data);

% % Note that this is a time-consuming step. The output "comp" structure resembles the input raw data structure, i.e. it contains a time course for each component and each trial. Furthermore, it contains the spatial mixing matrix. In principle you can continue analyzing the data on the component level by doing
% %
%   cfg = [];
%   cfg = ...
%   freq = ft_freqanalysis(cfg, comp);
%
% % or
% %
%   cfg = [];
%   cfg = ...
%   timelock = ft_timelockanalysis(cfg, comp);

% but for this example we want to analyze the data eventually on the original channel level and only remove the components that represent the artifacts.
%
%% # Identify the artifacts
%
% plot the components for visual inspection
figure
cfg = [];
cfg.component = 1:20;       % specify the component(s) that should be plotted
cfg.layout    = 'CTF151.lay'; % specify the layout file that should be used for plotting
cfg.comment   = 'no';
ft_topoplotIC(cfg, comp)

% Make sure to plot and inspect all components. Write down the components that contain the eye artifacts. Very important is to know that on subsequent evaluations of the component decomposition result in components that **can have a different order**. That means that component numbers that you write down do not apply to another run of the ICA decomposition on the same data.
%
%
% The spatial topography of the components aids in interpreting whether a component represents activity from the cortex, or non-cortical physiological activity (muscle, eyes, heart) or even non-physiological activity (line noise and other environmental noise). If you are trained in this type of analysis, you can relatively easily spot the components that represent the eye movements: 9, 14 and 10.
%
% Besides the spatial topography you should inspect the time course of the components, which gives additional information on separating the cortical from the non-cortical contributions to the data.
%
% For further inspection of the time course of the components, use:
%
cfg = [];
cfg.layout = 'CTF151.lay'; % specify the layout file that should be used for plotting
cfg.viewmode = 'component';
ft_databrowser(cfg, comp)

% You can browse through the components and the trials. The EOG artifacts can be easily identified in the time course plots, see the figure below for an example.
%
%
%% # Remove the artifacts
%
% remove the bad components and backproject the data
cfg = [];
cfg.component = [9 10 14 24]; % to be removed component(s)
data = ft_rejectcomponent(cfg, comp, data);

% Compare the data before (red trace) and after (blue trace) the EOG removal - for example trial 4, channel MLF1
%


function dist=mrManDist_new(nodeList,edgeList,startNode,dimDist,noval,radius)
% function [dist,pathIndices]=mrManDist_new(nodeList,edgeList,startNode,dimdist,-1,0)
%
% Obsolete, I think (BW)
%
%% ARW 031201
% This is a wrapper to replace mrManDist with the dijkstra routine from Stanford University
% mrManDist seems to be broken in some way. It certainly doesn't work with small floats
% This is the sort of thing you had to do to call mrManDist....
% [nodeList, edgeList]=generateManDistNodes(mesh);
% mesh.dist = mrManDist(nodeList,edgeList,startNode,dimdist,-1,0);
% dimdist is a scale factor for each linear dimension
% -1 is what's returned for a node with no connection to the start node.
% 0 says we're not sending in a list of node distances
% Edgelist is a 2xn list of node pairs
% Nodelist is a list of 3d node positions.

% To call dijkstra we need to make a weighted sparse connection matrix
% With each entry being the distance between the relevent nodes

disp('mrManDist_new is Obsolete. If you think it is necessary, please rename it and fix mrManDist.')
evalin('caller','mfilename')

return;

mesh.connectionMatrix = buildConnectionMatrix(nodeList, edgeList);

% Get rid of all the extra rubbish
mesh.uniqueVertices = nodeList(1:3,:)';

D = find3DNeighbourDists(mesh,dimDist);
dist = dijkstra(D,startNode);
dist = sqrt(dist);

return;


function [F,TimeVector] = in_fread_mne(sFile, ChannelMat, iEpoch, SamplesBounds, iChannels)
% IN_READ_MNE:  Read a block of recordings from a MNE-Python object
%
% USAGE:  [F,TimeVector] = in_fread_mne(sFile, ChannelMat, iEpoch, SamplesBounds, iChannels)
%         [F,TimeVector] = in_fread_mne(sFile, ChannelMat, iEpoch, SamplesBounds)            : Read all the channels

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2019

% Get reference to python object
pyObj = sFile.filename;
% List of channels
if (nargin < 5) || isempty(iChannels)
    picks = 'all';
else
    picks = {ChannelMat.Channel(iChannels).Name};
end
% Times
FileBounds = [bst_py2mat(pyObj.first_samp), bst_py2mat(pyObj.last_samp)];
if (nargin < 4) || isempty(SamplesBounds)
    SamplesBounds = FileBounds;
end

% Raw data
% if ~py.isinstance(pyObj, py.sys.modules{'mne.io'}.BaseRaw) || strcmpi(class(pyObj), 'py.mne.io.fiff.raw.Raw')
if ismethod(pyObj, 'get_data')
    % Call reading function
    res = pyObj.get_data(pyargs('picks', picks, 'start', int32(SamplesBounds(1) - FileBounds(1)), 'stop', int32(SamplesBounds(2) - FileBounds(1) + 1), 'return_times', true));
    F = bst_py2mat(res{1});
    TimeVector = bst_py2mat(res{2}) + sFile.prop.times(1);

% Epoched data
else
    error('todo');
%     % Use data already read
%     if isfield(sFile.header, 'epochData') && ~isempty(sFile.header.epochData)
%         F = permute(sFile.header.epochData(iEpoch,:,:), [2,3,1]);
%         TimeVector = linspace(sFile.epochs(iEpoch).times(1), sFile.epochs(iEpoch).times(2), size(F,2));
%     % Read data from file
%     else
%         [F, TimeVector] = fif_read_evoked(sFile, sfid, iEpoch);
%     end
%     % Specific selection of channels
%     if ~isempty(iChannels)
%         F = F(iChannels, :);
%     end
%     % Specific time selection
%     if ~isempty(SamplesBounds)
%         iTime = SamplesBounds - round(sFile.epochs(iEpoch).times(1) .* sFile.prop.sfreq) + 1;
%         F = F(:, iTime(1):iTime(2));
%         TimeVector = TimeVector(iTime(1):iTime(2));
%     end
end


function [seedinfo,outstate] = ncorr_gui_seedpreview(reference,current,roi,num_region,pos_seed,radius,cutoff_diffnorm,cutoff_iteration,enabled_stepanalysis,subsettrunc,num_img,total_imgs,pos_parent)
% This is a GUI for displaying the seeds before accepting them. Its
% possible the seeds are not correct or do not converge, so I included this
% utility as a check.
%
% Inputs -----------------------------------------------------------------%
%   reference - ncorr_class_img; used for displaying the background
%   image and calculations
%   current -  ncorr_class_img(s); used for displaying the background
%   image and calculations
%   roi - ncorr_class_roi; ROI corresponding to the reference image
%   num_region - integer; number corresponding to the region
%   pos_seed - integer array; 1st column is the x-position of the seed; 2nd
%   is the y-position. Each row corresponds to a thread in ascending order
%   (i.e. the first row is the first thread).
%   radius - integer; radius of subset
%   cutoff_diffnorm - double; cutoff of norm of the difference vector
%   cutoff_iteration - integer; cutoff for number of iterations
%   enabled_stepanalysis - logical; if true, then process as many seeds as
%   possible. If false, process all the seeds.
%   subsettrunc - logical; if true, then enable subset truncation
%   num_img - integer; number of reference image being analyzed
%   total_imgs - integer; total number of images being analyzed
%   pos_parent - integer array; this is the position of the parent figure
%   which determines where to position this figure
%
% Outputs ----------------------------------------------------------------%
%   seedinfo - struct; contains struct('paramvector',{},'num_region',{},'num_thread',{},'computepoints',{})
%   which is information on the location of the seed, the deformation
%   parameters for that seed, the region number, and the thread assigned for
%   computation.
%   outstate - integer; returns either out.cancelled, out.failed, or
%   out.success.
%
% Note that if step analysis is enabled, outstate will return success if at
% least one image is seeded. If no seeds are found, it will return failed.
% However, if step analysis is disabled, outstate will return success only
% if all images are seeded correctly, or else it will return failed.

    % Data ---------------------------------------------------------------%
    % Initialize Outputs
    outstate = out.cancelled;
    seedinfo = struct('paramvector',{},'num_region',{},'num_thread',{},'computepoints',{}); % paramvector = [x y u v du/dx du/dy dv/dx dv/dy corrcoef]
    % Get GUI handles
    handles_gui = init_gui();
    % Run c-tor
    feval(ncorr_util_wrapcallbacktrycatch(@constructor,handles_gui.figure));

    % Callbacks ----------------------------------------------------------%
    function constructor()
        % Calculate seeds. ncorr_alg_seedanalysis will return failed if no
        % images are seeded correctly in the case that step analysis is
        % enabled. If step analysis is disabled, it will return failed if
        % any of the seeds are processed incorrectly.
        [seedinfo_prelim,convergence_prelim,outstate_seeds] = ncorr_alg_seedanalysis(reference, ...
                                                                                current, ...
                                                                                roi, ...
                                                                                num_region, ...
                                                                                pos_seed, ...
                                                                                radius, ...
                                                                                cutoff_diffnorm, ...
                                                                                cutoff_iteration, ...
                                                                                enabled_stepanalysis, ...
                                                                                subsettrunc, ...
                                                                                num_img, ...
                                                                                total_imgs);

        if (outstate_seeds == out.success)
            % NOTE: Seeds are ordered in seedinfo_prelim WRT to thread
            % number when processed by ncorr_alg_seedanalysis (i.e.
            % seedinfo_prelim(i) == thread number i), so this isnt
            % explicitly checked when displaying subsets corresponding
            % to different threads.

            % Check to see if any seeds have a relatively high
            % correlation coefficient and warn the user about it.
            paramvectorcollection = vertcat(seedinfo_prelim.paramvector); % The ninth column is the correlation coefficients
            if (any(paramvectorcollection(:,9) > 0.4))
                h_error = errordlg('High correlation coefficient detected. One of the seed points is possibly incorrect. Proceed with caution.','Error','modal');
                uiwait(h_error);
            end

            % Precompute cirrois
            cirrois = struct('mask',{},'region',{},'boundary',{},'x',{},'y',{},'radius',{});
            for i = 0:size(pos_seed,1)-1
                cirrois(i+1) = roi.get_cirroi(pos_seed(i+1,1),pos_seed(i+1,2),radius,subsettrunc);
            end

            % Precompute the subsets, so they do not need to be
            % recalculated when switching between images/threads.
            % Initialize
            preview_subsets_ref = zeros(cirrois(1).radius*2+1,cirrois(1).radius*2+1,length(cirrois));
            preview_subsets_cur = zeros(cirrois(1).radius*2+1,cirrois(1).radius*2+1,length(cirrois),size(seedinfo_prelim,3));

            % Interpolate
            gs_buffer_ref = reference.get_gs();
            for i = 0:size(seedinfo_prelim,3)-1
                % Getting bcoefficients could be time consuming if a
                % lot of high resolution images are being processed.
                bcoef_buffer_cur = current(i+1).get_bcoef();
                for j = 0:size(seedinfo_prelim,1)-1
                    for k = 0:size(cirrois(j+1).region.noderange,1)-1
                        x_ref = k+(cirrois(j+1).x-cirrois(j+1).radius);
                        for l = 0:2:cirrois(j+1).region.noderange(k+1)-1
                            % Transform x_ref and y_ref and then
                            % interpolate
                            vec_y_ref = (cirrois(j+1).region.nodelist(k+1,l+1):cirrois(j+1).region.nodelist(k+1,l+2))';
                            vec_x_ref = repmat(x_ref,length(vec_y_ref),1);

                            % Fill reference subset - only do this once
                            if (i == 0)
                                preview_subsets_ref(vec_y_ref-(cirrois(j+1).y-cirrois(j+1).radius)+1,k+1,j+1) = gs_buffer_ref(vec_y_ref+1,x_ref+1);
                            end

                            % Transform ref coordinates
                            vec_x_cur = vec_x_ref + seedinfo_prelim(j+1,1,i+1).paramvector(3) + seedinfo_prelim(j+1,1,i+1).paramvector(5)*(vec_x_ref-cirrois(j+1).x) + seedinfo_prelim(j+1,1,i+1).paramvector(6)*(vec_y_ref-cirrois(j+1).y);
                            vec_y_cur = vec_y_ref + seedinfo_prelim(j+1,1,i+1).paramvector(4) + seedinfo_prelim(j+1,1,i+1).paramvector(7)*(vec_x_ref-cirrois(j+1).x) + seedinfo_prelim(j+1,1,i+1).paramvector(8)*(vec_y_ref-cirrois(j+1).y);

                            % Interpolate
                            vec_interp_cur = ncorr_alg_interpqbs([vec_x_cur vec_y_cur],bcoef_buffer_cur,0,0,current(i+1).border_bcoef);

                            % Note that any values interpolated out of
                            % the range of the bcoefficient matrix in
                            % ncorr_alg_interpqbs is set to NaN.
                            % Set these NaNs to zero for display
                            % purposes.
                            vec_interp_cur(isnan(vec_interp_cur)) = 0;

                            % Fill current subset
                            preview_subsets_cur(vec_y_ref-cirrois(j+1).y+cirrois(j+1).radius+1,k+1,j+1,i+1) = vec_interp_cur;
                        end
                    end
                end
            end

            % Set Data
            setappdata(handles_gui.figure,'cirrois',cirrois);
            setappdata(handles_gui.figure,'num_cur',size(seedinfo_prelim,3)-1);
            setappdata(handles_gui.figure,'num_thread',size(pos_seed,1)-1);
            setappdata(handles_gui.figure,'preview_subsets_ref',preview_subsets_ref);
            setappdata(handles_gui.figure,'preview_subsets_cur',preview_subsets_cur);
            setappdata(handles_gui.figure,'seedinfo_prelim',seedinfo_prelim);
            setappdata(handles_gui.figure,'convergence_prelim',convergence_prelim);

            % Update
            update_axes('set');

            % Set Visible
            set(handles_gui.figure,'Visible','on');
        elseif (outstate_seeds == out.failed)
            h_error = errordlg('Seed placement failed; please replace seeds.','Error','modal');
            uiwait(h_error);

            outstate = out.failed;

            % Exit
            close(handles_gui.figure);
        else
            % Analysis was cancelled - exit.
            close(handles_gui.figure);
        end
    end

    function callback_edit_threadnum(hObject,eventdata) %#ok<INUSD>
        % Get data
        num_thread = getappdata(handles_gui.figure,'num_thread');

        num_thread_prelim = str2double(get(handles_gui.edit_threadnum,'string'));
        if (ncorr_util_isintbb(num_thread_prelim,1,size(pos_seed,1),'Thread number') == out.success)
            num_thread = num_thread_prelim-1;
        end

        % Set data
        setappdata(handles_gui.figure,'num_thread',num_thread);

        % Update
        update_axes('set');
    end

    function callback_edit_imgnum(hObject,eventdata) %#ok<INUSD>
        % Get data
        num_cur = getappdata(handles_gui.figure,'num_cur');
        seedinfo_prelim = getappdata(handles_gui.figure,'seedinfo_prelim');

        num_cur_prelim = str2double(get(handles_gui.edit_imgnum,'string'));
        if (ncorr_util_isintbb(num_cur_prelim,1,size(seedinfo_prelim,3),'Current image number') == out.success)
            num_cur = num_cur_prelim-1;
        end

        % Set data
        setappdata(handles_gui.figure,'num_cur',num_cur);

        % Update
        update_axes('set');
    end

    function callback_button_finish(hObject,eventdata) %#ok<INUSD>
        % Get data
        seedinfo_prelim = getappdata(handles_gui.figure,'seedinfo_prelim');

        % Set output
        for i = 0:size(seedinfo_prelim,3)-1
            for j = 0:size(seedinfo_prelim,1)-1
                seedinfo(j+1,1,i+1) = seedinfo_prelim(j+1,1,i+1);
            end
        end
        outstate = out.success;

        % Exit
        close(handles_gui.figure);
    end

    function callback_button_cancel(hObject,eventdata) %#ok<INUSD>
        close(handles_gui.figure);
    end

    function callback_button_left_thread(hObject,eventdata) %#ok<INUSD>
        % Get data
        num_thread = getappdata(handles_gui.figure,'num_thread');

        % Check for overshoot
        if (num_thread > 0)
            num_thread = num_thread-1;
        end

        % Set data
        setappdata(handles_gui.figure,'num_thread',num_thread);

        % Update
        update_axes('set');
    end

    function callback_button_right_thread(hObject,eventdata) %#ok<INUSD>
        % Get data
        num_thread = getappdata(handles_gui.figure,'num_thread');

        % Check for overshoot
        if (num_thread < size(pos_seed,1)-1)
            num_thread = num_thread+1;
        end

        % Set data
        setappdata(handles_gui.figure,'num_thread',num_thread);

        % Update
        update_axes('set');
    end

    function callback_button_left_cur(hObject,eventdata) %#ok<INUSD>
        % Get data
        num_cur = getappdata(handles_gui.figure,'num_cur');

        % Check for overshoot
        if (num_cur > 0)
            num_cur = num_cur-1;
        end

        % Set data
        setappdata(handles_gui.figure,'num_cur',num_cur);

        % Update
        update_axes('set');
    end

    function callback_button_right_cur(hObject,eventdata) %#ok<INUSD>
        % Get data
        num_cur = getappdata(handles_gui.figure,'num_cur');
        seedinfo_prelim = getappdata(handles_gui.figure,'seedinfo_prelim');

        % Check for overshoot
        if (num_cur < size(seedinfo_prelim,3)-1)
            num_cur = num_cur+1;
        end

        % Set data
        setappdata(handles_gui.figure,'num_cur',num_cur);

        % Update
        update_axes('set');
    end

    function update_axes(action)
        % Get data
        num_cur = getappdata(handles_gui.figure,'num_cur');
        num_thread = getappdata(handles_gui.figure,'num_thread');
        preview_subsets_ref = getappdata(handles_gui.figure,'preview_subsets_ref');
        preview_subsets_cur = getappdata(handles_gui.figure,'preview_subsets_cur');
        cirrois = getappdata(handles_gui.figure,'cirrois');
        seedinfo_prelim = getappdata(handles_gui.figure,'seedinfo_prelim');
        convergence_prelim = getappdata(handles_gui.figure,'convergence_prelim');

        if (strcmp(action,'set'))
            gs_buffer_ref = reference.get_gs();
            gs_buffer_cur = current(num_cur+1).get_gs();

            % Paint reference subset and subset locations
            preview_subsetloc_ref = gs_buffer_ref;
            preview_subsetloc_cur = gs_buffer_cur;

            % Iterate over num_thread last so that it highlights this
            % subset over the others
            for i = [0:num_thread-1 num_thread+1:size(pos_seed,1)-1 num_thread]
                for j = 0:size(cirrois(i+1).region.noderange,1)-1
                    x_ref = j+(cirrois(i+1).x-cirrois(i+1).radius);
                    for k = 0:2:cirrois(i+1).region.noderange(j+1)-1
                        for l = cirrois(i+1).region.nodelist(j+1,k+1):cirrois(i+1).region.nodelist(j+1,k+2)
                            y_ref = l;

                            % Fill subset locations
                            if (i == num_thread)
                                % User brighter highlight to indicate this is
                                % the seed corresponding to the current
                                % threads
                                preview_subsetloc_ref(y_ref+1,x_ref+1) = gs_buffer_ref(y_ref+1,x_ref+1)+1.75*reference.max_gs;
                            else
                                % Do regular highlight
                                preview_subsetloc_ref(y_ref+1,x_ref+1) = gs_buffer_ref(y_ref+1,x_ref+1)+reference.max_gs;
                            end

                            % defvector_init(1) = u
                            % defvector_init(2) = v
                            % defvector_init(3) = du_dx
                            % defvector_init(4) = du_dy
                            % defvector_init(5) = dv_dx
                            % defvector_init(6) = dv_dy
                            % y_cur = y_ref + v + dv/dx*deltax + dv/dy*deltay
                            % x_cur = x_ref + u + du/dx*deltax + du/dy*deltay

                            x_cur = x_ref + seedinfo_prelim(i+1,1,num_cur+1).paramvector(3) + seedinfo_prelim(i+1,1,num_cur+1).paramvector(5)*(x_ref-cirrois(i+1).x) + seedinfo_prelim(i+1,1,num_cur+1).paramvector(6)*(y_ref-cirrois(i+1).y);
                            y_cur = y_ref + seedinfo_prelim(i+1,1,num_cur+1).paramvector(4) + seedinfo_prelim(i+1,1,num_cur+1).paramvector(7)*(x_ref-cirrois(i+1).x) + seedinfo_prelim(i+1,1,num_cur+1).paramvector(8)*(y_ref-cirrois(i+1).y);

                            % x_cur and y_cur could be out of bounds, check
                            % before using them
                            if (floor(x_cur) >= 0 && floor(y_cur) >= 0 && ceil(x_cur) < size(gs_buffer_cur,2) && ceil(y_cur) < size(gs_buffer_cur,1))
                                % Fill subset locations. This is a crude
                                % approximation of the current subset. Use both
                                % floor and ceil of transformed locations to
                                % highlight the area of the current subset.
                                if (i == num_thread)
                                    % User brighter highlight to indicate this is
                                    % the seed corresponding to the thread of
                                    % interest
                                    preview_subsetloc_cur(floor(y_cur)+1,floor(x_cur)+1) = gs_buffer_cur(floor(y_cur)+1,floor(x_cur)+1)+1.75*current(num_cur+1).max_gs;
                                    preview_subsetloc_cur(ceil(y_cur)+1,ceil(x_cur)+1) = gs_buffer_cur(ceil(y_cur)+1,ceil(x_cur)+1)+1.75*current(num_cur+1).max_gs;
                                else
                                    % Do regular highlight
                                    preview_subsetloc_cur(floor(y_cur)+1,floor(x_cur)+1) = gs_buffer_cur(floor(y_cur)+1,floor(x_cur)+1)+current(num_cur+1).max_gs;
                                    preview_subsetloc_cur(ceil(y_cur)+1,ceil(x_cur)+1) = gs_buffer_cur(ceil(y_cur)+1,ceil(x_cur)+1)+current(num_cur+1).max_gs;
                                end
                            end
                        end
                    end
                end
            end

            % Set Images
            imshow(preview_subsets_ref(:,:,num_thread+1),[reference.min_gs reference.max_gs],'Parent',handles_gui.axes_refsubset);
            set(handles_gui.axes_refsubset,'Visible','off');
            imshow(preview_subsetloc_ref,[reference.min_gs 2*reference.max_gs],'Parent',handles_gui.axes_refsubsetloc);
            set(handles_gui.axes_refsubsetloc,'Visible','off');

            imshow(preview_subsets_cur(:,:,num_thread+1,num_cur+1),[current(num_cur+1).min_gs current(num_cur+1).max_gs],'Parent',handles_gui.axes_cursubset);
            set(handles_gui.axes_cursubset,'Visible','off');
            imshow(preview_subsetloc_cur,[current(num_cur+1).min_gs 2*current(num_cur+1).max_gs],'Parent',handles_gui.axes_cursubsetloc);
            set(handles_gui.axes_cursubsetloc,'Visible','off');

            % Set Texts
            if (convergence_prelim(num_thread+1,1,num_cur+1).num_iterations < cutoff_iteration)
                set(handles_gui.text_num_iterations_num,'String',num2str(convergence_prelim(num_thread+1,1,num_cur+1).num_iterations,'%6.0f'),'ForegroundColor', 'k');
            else
                set(handles_gui.text_num_iterations_num,'String',[num2str(convergence_prelim(num_thread+1,1,num_cur+1).num_iterations,'%6.0f') ' (Max)' ],'ForegroundColor', 'r');
            end
            set(handles_gui.text_gradnorm_num,'String',num2str(convergence_prelim(num_thread+1,1,num_cur+1).diffnorm));
            set(handles_gui.text_corrcoef_num,'String',num2str(seedinfo_prelim(num_thread+1,1,num_cur+1).paramvector(9)));
            set(handles_gui.text_thread,'String', ['Thread: ' num2str(num_thread+1)]);
            set(handles_gui.text_cur,'String', ['Name: ' current(num_cur+1).name(1:min(end,22))]);
            set(handles_gui.text_ref,'String', ['Name: ' reference.name(1:min(end,22))]);

            % Set buttons
            % Set left/right buttons for current image
            set(handles_gui.edit_imgnum,'String',num2str(num_cur+1));
            if (size(seedinfo_prelim,3) == 1)
                set(handles_gui.button_right_cur,'Enable','off');
                set(handles_gui.button_left_cur,'Enable','off');
                set(handles_gui.edit_imgnum,'Enable','off');
            elseif (num_cur == 0)
                set(handles_gui.button_right_cur,'Enable','on');
                set(handles_gui.button_left_cur,'Enable','off');
                set(handles_gui.edit_imgnum,'Enable','on');
            elseif (num_cur == size(seedinfo_prelim,3)-1)
                set(handles_gui.button_right_cur,'Enable','off');
                set(handles_gui.button_left_cur,'Enable','on');
                set(handles_gui.edit_imgnum,'Enable','on');
            else
                set(handles_gui.button_right_cur,'Enable','on');
                set(handles_gui.button_left_cur,'Enable','on');
                set(handles_gui.edit_imgnum,'Enable','on');
            end

            % Set left/right buttons for thread number
            set(handles_gui.edit_threadnum,'String',num2str(num_thread+1));
            if (size(pos_seed,1) == 1)
                set(handles_gui.button_right_thread,'Enable','off');
                set(handles_gui.button_left_thread,'Enable','off');
                set(handles_gui.edit_threadnum,'Enable','off');
            elseif (num_thread == 0)
                set(handles_gui.button_right_thread,'Enable','on');
                set(handles_gui.button_left_thread,'Enable','off');
                set(handles_gui.edit_threadnum,'Enable','on');
            elseif (num_thread == size(pos_seed,1)-1)
                set(handles_gui.button_right_thread,'Enable','off');
                set(handles_gui.button_left_thread,'Enable','on');
                set(handles_gui.edit_threadnum,'Enable','on');
            else
                set(handles_gui.button_right_thread,'Enable','on');
                set(handles_gui.button_left_thread,'Enable','on');
                set(handles_gui.edit_threadnum,'Enable','on');
            end
        end
    end

    function handles_gui = init_gui()
    % GUI controls -------------------------------------------------------%
        % Figure
        handles_gui.figure = figure( ...
            'Tag', 'figure', ...
            'Units', 'characters', ...
            'Position', ncorr_util_figpos(pos_parent,[56.1 167]), ...
            'Name', 'Seed Preview', ...
            'MenuBar', 'none', ...
            'NumberTitle', 'off', ...
            'Color', get(0,'DefaultUicontrolBackgroundColor'), ...
            'handlevisibility','off', ...
            'DockControls','off', ...
            'WindowStyle','modal', ...
            'Resize','off', ...
            'Visible','off', ...
            'IntegerHandle','off', ...
            'Interruptible','off');

        % Panels
        handles_gui.group_menu = uibuttongroup( ...
            'Parent', handles_gui.figure, ...
            'Tag', 'group_menu', ...
            'Units', 'characters', ...
            'Position', [2 48.7 35 6.7], ...
            'Title', 'Menu', ...
            'Interruptible','off');

        handles_gui.group_ref = uibuttongroup( ...
            'Parent', handles_gui.figure, ...
            'Tag', 'group_reference', ...
            'Units', 'characters', ...
            'Position', [39.0 0.75 62 54.6], ...
            'Title', 'Reference', ...
            'Interruptible','off');

        handles_gui.group_cur = uibuttongroup( ...
            'Parent', handles_gui.figure, ...
            'Tag', 'group_current', ...
            'Units', 'characters', ...
            'Position', [103 0.75 62 54.6], ...
            'Title', 'Current', ...
            'Interruptible','off');

        % Axes
        handles_gui.axes_refsubsetloc = axes( ...
            'Parent', handles_gui.group_ref, ...
            'Tag', 'axes_refsubsetloc', ...
            'Units', 'characters', ...
            'Visible', 'off', ...
            'Position', [2.1 35.7 56.5 17], ...
            'Interruptible','off');

        handles_gui.axes_cursubsetloc = axes( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'axes_cursubsetloc', ...
            'Units', 'characters', ...
            'Visible', 'off', ...
            'Position', [2.1 35.7 56.5 17], ...
            'Interruptible','off');

        handles_gui.axes_refsubset = axes( ...
            'Parent', handles_gui.group_ref, ...
            'Tag', 'axes_refsubset', ...
            'Units', 'characters', ...
            'Visible', 'off', ...
            'Position', [2.1 13.1 56.5 17], ...
            'Interruptible','off');

        handles_gui.axes_cursubset = axes( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'axes_cursubset', ...
            'Units', 'characters', ...
            'Visible', 'off', ...
            'Position', [2.1 13.1 56.5 17], ...
            'Interruptible','off');

        % Static Texts
        handles_gui.text_refsubloc = uicontrol( ...
            'Parent', handles_gui.group_ref, ...
            'Tag', 'text_cur', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [2.1 33.6 56.5 1.2], ...
            'String', 'Location of Reference Subset', ...
            'Interruptible','off');

        handles_gui.text_cursubloc = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'text_cursubloc', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [2.1 33.6 56.5 1.2], ...
            'String', 'Approximate Location of Current Subset', ...
            'Interruptible','off');

        handles_gui.text_refsub = uicontrol( ...
            'Parent', handles_gui.group_ref, ...
            'Tag', 'text_refsub', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [2.1 11.0 56.5 1.2], ...
            'String', 'Reference Subset', ...
            'Interruptible','off');

        handles_gui.text_cursub = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'text_cursub', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [2.1 11.0 56.5 1.2], ...
            'String', 'Transformed Current Subset', ...
            'Interruptible','off');

        handles_gui.text_num_iterations = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'text_num_iterations', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [2.1 8.4 38.5 1.2], ...
            'HorizontalAlignment', 'Left', ...
            'String', '# of Gauss Newton Iterations:', ...
            'Interruptible','off');

        handles_gui.text_gradnorm = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'text_gradnorm', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [2.1 6.6 38.5 1.2], ...
            'HorizontalAlignment', 'Left', ...
            'String', 'Norm of difference vector:', ...
            'Interruptible','off');

        handles_gui.text_corrcoef = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'text_corrcoef', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [2.1 4.8 38.5 1.2], ...
            'HorizontalAlignment', 'Left', ...
            'String', 'Correlation Coefficient:', ...
            'Interruptible','off');

        handles_gui.text_num_iterations_num = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'text_num_iterations_num', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [41.5 8.4 13 1.2], ...
            'HorizontalAlignment', 'Left', ...
            'String', '', ...
            'Interruptible','off');

        handles_gui.text_gradnorm_num = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'text_gradnorm_num', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [41.5 6.6 13 1.2], ...
            'HorizontalAlignment', 'Left', ...
            'String', '', ...
            'Interruptible','off');

        handles_gui.text_corrcoef_num = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'text_corrcoef_num', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [41.5 4.8 13 1.2], ...
            'HorizontalAlignment', 'Left', ...
            'String', '', ...
            'Interruptible','off');

        handles_gui.text_thread = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'text_thread', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [2.1 3.0 56.9 1.2], ...
            'HorizontalAlignment', 'Left', ...
            'String', 'Thread:', ...
            'Interruptible','off');

        handles_gui.text_cur = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'text_cur', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [2.1 1.2 56.9 1.2], ...
            'HorizontalAlignment', 'Left', ...
            'String', 'Name:', ...
            'Interruptible','off');

        handles_gui.text_ref = uicontrol( ...
            'Parent', handles_gui.group_ref, ...
            'Tag', 'text_ref', ...
            'Style', 'text', ...
            'Units', 'characters', ...
            'Position', [2.1 1.2 56.9 1.2], ...
            'HorizontalAlignment', 'Left', ...
            'String', 'Name:', ...
            'Interruptible','off');

        % Edit
        handles_gui.edit_threadnum = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'edit_threadnum', ...
            'Style', 'edit', ...
            'Units', 'characters', ...
            'Position', [44.3 3.1 7 1.2], ...
            'String', '', ...
            'Callback', ncorr_util_wrapcallbacktrycatch(@callback_edit_threadnum,handles_gui.figure), ...
            'Enable', 'off', ...
            'Interruptible','off');

        handles_gui.edit_imgnum = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'edit_imgnum', ...
            'Style', 'edit', ...
            'Units', 'characters', ...
            'Position', [44.3 1.2 7 1.2], ...
            'String', '', ...
            'Callback', ncorr_util_wrapcallbacktrycatch(@callback_edit_imgnum,handles_gui.figure), ...
            'Enable', 'off', ...
            'Interruptible','off');

        % Pushbuttons
        handles_gui.button_finish = uicontrol( ...
            'Parent', handles_gui.group_menu, ...
            'Tag', 'button_finish', ...
            'Style', 'pushbutton', ...
            'Units', 'characters', ...
            'Position', [2.1 3 29.7 1.7], ...
            'String', 'Finish', ...
            'Callback', ncorr_util_wrapcallbacktrycatch(@callback_button_finish,handles_gui.figure), ...
            'Interruptible','off');

        handles_gui.button_cancel = uicontrol( ...
            'Parent', handles_gui.group_menu, ...
            'Tag', 'button_cancel', ...
            'Style', 'pushbutton', ...
            'Units', 'characters', ...
            'Position', [2.1 1 29.7 1.7], ...
            'String', 'Cancel', ...
            'Callback', ncorr_util_wrapcallbacktrycatch(@callback_button_cancel,handles_gui.figure), ...
            'Interruptible','off');

        handles_gui.button_left_thread = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'button_left_thread', ...
            'Style', 'pushbutton', ...
            'Units', 'characters', ...
            'Position', [37.3 2.9 6 1.5], ...
            'String', '<', ...
            'Enable', 'off', ...
            'Callback', ncorr_util_wrapcallbacktrycatch(@callback_button_left_thread,handles_gui.figure), ...
            'Interruptible','off');

        handles_gui.button_right_thread = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'button_right_thread', ...
            'Style', 'pushbutton', ...
            'Units', 'characters', ...
            'Position', [52.3 2.9 6 1.5], ...
            'String', '>', ...
            'Enable', 'off', ...
            'Callback', ncorr_util_wrapcallbacktrycatch(@callback_button_right_thread,handles_gui.figure), ...
            'Interruptible','off');

        handles_gui.button_left_cur = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'button_left_cur', ...
            'Style', 'pushbutton', ...
            'Units', 'characters', ...
            'Position', [37.3 1.1 6 1.5], ...
            'String', '<', ...
            'Enable', 'off', ...
            'Callback', ncorr_util_wrapcallbacktrycatch(@callback_button_left_cur,handles_gui.figure), ...
            'Interruptible','off');

        handles_gui.button_right_cur = uicontrol( ...
            'Parent', handles_gui.group_cur, ...
            'Tag', 'button_right_cur', ...
            'Style', 'pushbutton', ...
            'Units', 'characters', ...
            'Position', [52.3 1.1 6 1.5], ...
            'String', '>', ...
            'Enable', 'off', ...
            'Callback', ncorr_util_wrapcallbacktrycatch(@callback_button_right_cur,handles_gui.figure), ...
            'Interruptible','off');
    end

    % Pause until figure is closed ---------------------------------------%
    waitfor(handles_gui.figure);
end


classdef Net < handle
    %NET  Create and manipulate comprehensive artificial neural networks
    %
    % This module contains:
    %
    % - API for new layers creation, layers are building bricks of neural
    %   networks;
    % - set of built-in most-useful Layers;
    % - API to constuct and modify comprehensive neural networks from layers;
    % - functionality for loading serialized networks models from different
    %   frameworks.
    %
    % Functionality of this module is designed only for forward pass
    % computations (i. e. network testing). A network training is in principle
    % not supported.
    %
    % [Wiki](https://github.com/opencv/opencv/wiki/Deep-Learning-in-OpenCV)
    %
    % ## Net class
    % Neural network is presented as directed acyclic graph (DAG), where
    % vertices are Layer instances, and edges specify relationships between
    % layers inputs and outputs.
    %
    % Each network layer has unique integer id and unique string name inside
    % its network. LayerId can store either layer name or layer id.
    %
    % See also: cv.Net.Net, nnet.cnn.layer.Layer, trainNetwork,
    %  SeriesNetwork, importCaffeNetwork, importCaffeLayers, alexnet, vgg16,
    %  vgg19
    %

    properties (SetAccess = private)
        % Object ID
        id
    end

    %% Constructor/destructor
    methods
        function this = Net(varargin)
            %NET  Constructor and importer of trained serialized models from different dnn-frameworks
            %
            %     net = cv.Net()
            %
            %     net = cv.Net('Caffe', prototxt)
            %     net = cv.Net('Caffe', prototxt, caffeModel)
            %
            %     net = cv.Net('Tensorflow', modelmodel)
            %     net = cv.Net('Tensorflow', model, config)
            %
            %     net = cv.Net('Torch', filename)
            %     net = cv.Net('Torch', filename, isBinary)
            %
            %     net = cv.Net('Darknet', cfgFile)
            %     net = cv.Net('Darknet', cfgFile, darknetModel)
            %
            % ## Input
            % * __prototxt__ path to the `.prototxt` file with text
            %   description of the network architecture.
            % * __caffeModel__ (optional) path to the `.caffemodel` file with
            %   learned network. Empty by default.
            % * __model__ path to the `.pb` file with binary protobuf
            %   description of the network architecture. Binary serialized
            %   TensorFlow graph includes weights.
            % * __config__ Optional path to the `.pbtxt` file that contains
            %   text graph definition in protobuf format. Resulting net is
            %   built by text graph using weights from a binary one. This is
            %   more flexible than binary format and may be used to build the
            %   network using binary format only as a weights storage. This
            %   approach is similar to Caffe's `.prorotxt` and `.caffemodel`.
            % * __filename__ path to the file, dumped from Torch by using
            %   `torch.save()` function.
            % * __isBinary__ specifies whether the network was serialized in
            %   ascii mode or binary. default true.
            % * __cfgFile__ path to the `.cfg` file with text description of
            %   the network architecture.
            % * __darknetModel__ (optional) path to the `.weights` file with
            %   learned network.
            %
            % The first variant creates an empty network.
            %
            % The second variant reads a network model stored in
            % [Caffe](http://caffe.berkeleyvision.org) framework's format.
            %
            % The third variant reads a network model stored in
            % [TensorFlow](https://www.tensorflow.org/) framework's format.
            %
            % The fourth variant reads a network model stored in
            % [Torch7](http://torch.ch) framework's format.
            %
            % The fifth variant reads a network model stored in
            % [Darknet](https://pjreddie.com/darknet/) model files.
            %
            % The importers first create a net, add loaded layers into it, and
            % set connections between them.
            %
            % ### Notes for Torch
            %
            % NOTE: ASCII mode of Torch serializer is more preferable, because
            % binary mode extensively use `long` type of C language, which has
            % various bit-length on different systems.
            %
            % The loading file must contain serialized
            % [`nn.Module`](https://github.com/torch/nn/blob/master/doc/module.md)
            % object with importing network. Try to eliminate a custom objects
            % from serialazing data to avoid importing errors.
            %
            % List of supported layers (i.e. object instances derived from
            % Torch `nn.Module` class):
            % - `nn.Sequential`
            % - `nn.Parallel`
            % - `nn.Concat`
            % - `nn.Linear`
            % - `nn.SpatialConvolution`
            % - `nn.SpatialMaxPooling`, `nn.SpatialAveragePooling`
            % - `nn.ReLU`, `nn.TanH`, `nn.Sigmoid`
            % - `nn.Reshape`
            % - `nn.SoftMax`, `nn.LogSoftMax`
            %
            % Also some equivalents of these classes from cunn, cudnn, and
            % fbcunn may be successfully imported.
            %
            % See also: cv.Net, cv.Net.forward
            %
            this.id = Net_(0, 'new', varargin{:});
        end

        function delete(this)
            %DELETE  Destructor
            %
            %     net.delete()
            %
            % See also: cv.Net
            %
            if isempty(this.id), return; end
            Net_(this.id, 'delete');
        end
    end

    %% Net (set/get blobs and params, forward pass)
    methods
        function setInput(this, blob, name)
            %SETINPUT  Sets the new value for the layer output blob
            %
            %     net.setInput(blob)
            %     net.setInput(blob, name)
            %
            % ## Input
            % * __blob__ new blob, constructed from an image or an array of
            %   images.
            % * __name__ descriptor of the updating layer output blob. See
            %   cv.Net.connect to know format of the descriptor.
            %
            % NOTE: If updating blob is not empty then `blob` must have the
            % same shape, because network reshaping is not implemented yet.
            %
            % The blob (4-dimensional blob, so-called batch) is constructed
            % from image or array of images. Image is a 2-dimensional
            % multi-channel or 3-dimensional single-channel image (or array of
            % such images).
            %
            % See also: cv.Net.forward, cv.Net.blobFromImages
            %
            if nargin > 2
                Net_(this.id, 'setInput', blob, name);
            else
                Net_(this.id, 'setInput', blob);
            end
        end

        function setParam(this, layerId, numParam, blob)
            %SETPARAM  Sets the new value for the learned param of the layer
            %
            %     net.setParam(layerId, numParam, blob)
            %
            % ## Input
            % * __layerId__ name or id of the layer.
            % * __numParam__ index of the layer parameter in the blobs array.
            % * __blob__ the new value.
            %
            % NOTE: If shape of the new blob differs from the previous shape,
            % then the following forward pass may fail.
            %
            % See also: cv.Net.getParam
            %
            Net_(this.id, 'setParam', layerId, numParam, blob);
        end

        function blob = getParam(this, layerId, numParam)
            %GETPARAM  Returns parameter blob of the layer
            %
            %     blob = net.getParam(layerId)
            %     blob = net.getParam(layerId, numParam)
            %
            % ## Input
            % * __layerId__ name or id of the layer.
            % * __numParam__ index of the layer parameter in the blobs array.
            %   default 0.
            %
            % ## Output
            % * __blob__ returned parameter blob.
            %
            % Parameters are the weights and biases.
            %
            % See also: cv.Net.setParam
            %
            if nargin > 2
                blob = Net_(this.id, 'getParam', layerId, numParam);
            else
                blob = Net_(this.id, 'getParam', layerId);
            end
        end

        function blob = forward(this, varargin)
            %FORWARD  Runs forward pass
            %
            %     blob = net.forward()
            %     blob = net.forward(outputName)
            %
            %     blobs = net.forward(outBlobNames)
            %
            % ## Input
            % * __outputName__ name for layer which output is needed to get.
            % * __outBlobNames__ names for layers which outputs are needed to
            %   get.
            %
            % ## Output
            % * __blob__ blob for first output of specified layer.
            % * __blobs__ blobs for first outputs of specified layers
            %   (cell array).
            %
            % The first form runs forward pass to compute output of layer
            % with name `outputName`. By default (`outputName` not specified)
            % runs forward pass for the whole network.
            % (i.e `names = net.getLayerNames(); outputName = names(end);`).
            % It returns blob for first output of specified layer.
            %
            % The second form runs forward pass to compute outputs of layers
            % listed in `outBlobNames`. It returns blobs for first outputs of
            % specified layers.
            %
            % See also: cv.Net.forwardAndRetrieve, cv.Net.Net
            %
            blob = Net_(this.id, 'forward', varargin{:});
        end

        function blobs = forwardAndRetrieve(this, varargin)
            %FORWARDANDRETRIEVE  Runs forward pass
            %
            %     blobs = net.forwardAndRetrieve()
            %     blobs = net.forwardAndRetrieve(outputName)
            %
            %     blobsArr = net.forwardAndRetrieve(outBlobNames)
            %
            % ## Input
            % * __outputName__ name for layer which output is needed to get.
            % * __outBlobNames__ names for layers which outputs are needed to
            %   get.
            %
            % ## Output
            % * __blobs__ contains all output blobs for specified layer
            %   (cell array)
            % * __blobsArr__ contains all output blobs for each layer
            %   specified in `outBlobNames` (cell array of cell arrays).
            %
            % The first form runs forward pass to compute output of layer
            % with name `outputName`. By default (`outputName` not specified)
            % runs forward pass for the whole network
            % (i.e `names = net.getLayerNames(); outputName = names(end);`).
            % It returns all output blobs for specified layer.
            %
            % The second form runs forward pass to compute outputs of layers
            % listed in `outBlobNames`. It returns all output blobs for each
            % layer specified in `outBlobNames`.
            %
            % See also: cv.Net.forward, cv.Net.Net
            %
            blobs = Net_(this.id, 'forwardAndRetrieve', varargin{:});
        end

        function [timings, total] = getPerfProfile(this)
            %GETPERFPROFILE  Returns overall time for inference and timings (in ticks) for layers
            %
            %     [timings, total] = net.getPerfProfile()
            %
            % ## Output
            % * __timings__ vector for tick timings for all layers.
            % * __total__ overall ticks for model inference.
            %
            % Indexes in returned vector correspond to layers ids. Some layers
            % can be fused with others, in this case zero ticks count will be
            % return for that skipped layers.
            %
            % See also: cv.Net.forward, cv.TickMeter
            %
            [timings, total] = Net_(this.id, 'getPerfProfile');
        end
    end

    %% Net (network architecture)
    methods
        function b = empty(this)
            %EMPTY  Returns true if there are no layers in the network.
            %
            %     b = net.empty()
            %
            % ## Output
            % * __b__ Boolean.
            %
            % See also: cv.Net.Net
            %
            b = Net_(this.id, 'empty');
        end

        function id = addLayer(this, name, layerType, params)
            %ADDLAYER  Adds new layer to the net
            %
            %     id = net.addLayer(name, layerType, params)
            %
            % ## Input
            % * __name__ unique name of the adding layer.
            % * __layerType__ typename of the adding layer (type must be
            %   registered).
            % * __params__ parameters which will be used to initialize the
            %   creating layer. Scalar structure with the following fields:
            %   * __dict__ name-value dictionary as struct, values are scalar
            %     values (or arrays) of one of the following type: double,
            %     integer, or string.
            %   * __blobs__ List of learned parameters stored as blobs.
            %   * __name__ Name of the layer instance (optional, can be used
            %     internal purposes).
            %   * __type__ Type name which was used for creating layer by
            %     layer factory (optional).
            %
            % ## Output
            % * __id__ unique identifier of created layer, or -1 if a failure
            %   will happen.
            %
            % A LayerParams provides all data needed to initialize layer. It
            % includes dictionary with scalar params (`params.dict` struct),
            % blob params `params.blobs` and optional meta information
            % `params.name` and `params.type` of layer instance.
            %
            % Built-in layers listed below partially reproduce functionality
            % of corresponding Caffe and Torch7 layers. In partuclar, the
            % following layers and Caffe importer were tested to reproduce
            % [Caffe](http://caffe.berkeleyvision.org/tutorial/layers.html)
            % functionality:
            % - Convolution
            % - Deconvolution
            % - Pooling
            % - InnerProduct
            % - TanH, ReLU, Sigmoid, BNLL, Power, AbsVal
            % - Softmax
            % - Reshape, Flatten, Slice, Split
            % - LRN
            % - MVN
            % - Dropout (since it does nothing on forward pass)
            %
            % See also: cv.Net.addLayerToPrev, cv.Net.deleteLayer, cv.Net.connect
            %
            id = Net_(this.id, 'addLayer', name, layerType, params);
            id = int32(id);
        end

        function id = addLayerToPrev(this, name, layerType, params)
            %ADDLAYERTOPREV  Adds new layer and connects its first input to the first output of previously added layer
            %
            %     id = net.addLayerToPrev(name, layerType, params)
            %
            % ## Input
            % * __name__ unique name of the adding layer.
            % * __layerType__ typename of the adding layer (type must be
            %   registered).
            % * __params__ parameters which will be used to initialize the
            %   creating layer.
            %
            % ## Output
            % * __id__ unique identifier of created layer, or -1 if a failure
            %   will happen.
            %
            % See also: cv.Net.addLayer, cv.Net.deleteLayer, cv.Net.connect
            %
            id = Net_(this.id, 'addLayerToPrev', name, layerType, params);
            id = int32(id);
        end

        function id = getLayerId(this, name)
            %GETLAYERID  Converts string name of the layer to the integer identifier
            %
            %     id = net.getLayerId(name)
            %
            % ## Input
            % * __name__ string name of the layer.
            %
            % ## Output
            % * __id__ id of the layer, or -1 if the layer wasn't found.
            %
            % See also: cv.Net.getLayer, cv.Net.getLayerNames
            %
            id = Net_(this.id, 'getLayerId', name);
            id = int32(id);
        end

        function names = getLayerNames(this)
            %GETLAYERNAMES  Get layer names
            %
            %     names = net.getLayerNames()
            %
            % ## Output
            % * __names__ names of layers.
            %
            % See also: cv.Net.getLayerId, cv.Net.getLayer
            %
            names = Net_(this.id, 'getLayerNames');
        end

        function layer = getLayer(this, layerId)
            %GETLAYER  Returns layer with specified id or name which the network use
            %
            %     layer = net.getLayer(layerId)
            %
            % ## Input
            % * __layerId__ layer name or layer id.
            %
            % ## Output
            % * __layer__ returned layer. Scalar structure with the following
            %   fields:
            %   * __blobs__ List of stored learned parameters as returned by
            %     cv.Net.getParam.
            %   * __name__ name of the layer instance, can be used for logging
            %     or other internal purposes.
            %   * __type__ Type name which was used for creating layer by
            %     layer factory.
            %   * __preferableTarget__ preferred target for layer forwarding
            %     (see cv.Net.setPreferableTarget).
            %
            % Layers are the building blocks of networks.
            %
            % See also: cv.Net.getLayerId
            %
            layer = Net_(this.id, 'getLayer', layerId);
        end

        function layers = getLayerInputs(this, layerId)
            %GETLAYERINPUTS  Returns input layers of specific layer
            %
            %     layers = net.getLayerInputs(layerId)
            %
            % ## Input
            % * __layerId__ layer name or layer id.
            %
            % ## Output
            % * __layers__ returned layers, struct array.
            %
            % See also: cv.Net.getLayerId, cv.Net.getLayer
            %
            layers = Net_(this.id, 'getLayerInputs', layerId);
        end

        function deleteLayer(this, layerId)
            %DELETELAYER  Delete layer for the network
            %
            %     net.deleteLayer(layerId)
            %
            % ## Input
            % * __layerId__ layer name or layer id.
            %
            % Warning: Not yet implemented.
            %
            % See also: cv.Net.addLayer
            %
            Net_(this.id, 'deleteLayer', layerId);
        end

        function connect(this, varargin)
            %CONNECT  Connects output of the first layer to input of the second layer
            %
            %     net.connect(outPin, inpPin)
            %     net.connect(outLayerId, outNum, inpLayerId, inpNum)
            %
            % ## Input
            % * __outPin__ descriptor of the first layer output. See below.
            % * __inpPin__ descriptor of the second layer input. See below.
            %
            % ## Input
            % * __outLayerId__ identifier of the first layer.
            % * __outNum__ number of the first layer output.
            % * __inpLayerId__ identifier of the second layer.
            % * __inpNum__ number of the second layer input.
            %
            % Descriptors have the following template
            % `<layer_name>[.input_number]`:
            % - the first part of the template `layer_name` is sting name of
            %   the added layer. If this part is empty then the network input
            %   pseudo layer will be used;
            % - the second optional part of the template `input_number` is
            %   either number of the layer input, either label one. If this
            %   part is omitted then the first layer input will be used.
            %
            % See also: cv.Net.setInputsNames, cv.Net.addLayer
            %
            Net_(this.id, 'connect', varargin{:});
        end

        function setInputsNames(this, inputBlobNames)
            %SETINPUTSNAMES  Sets outputs names of the network input pseudo layer
            %
            %     net.setInputsNames(inputBlobNames)
            %
            % ## Input
            % * __inputBlobNames__ blob names.
            %
            % Each net always has special own the network input pseudo layer
            % with `id=0`. This layer stores the user blobs only and don't
            % make any computations. In fact, this layer provides the only way
            % to pass user data into the network. As any other layer, this
            % layer can label its outputs and this function provides an easy
            % way to do this.
            %
            % See also: cv.Net.connect, cv.Net.setInput
            %
            Net_(this.id, 'setInputsNames', inputBlobNames);
        end

        function indices = getUnconnectedOutLayers(this)
            %GETUNCONNECTEDOUTLAYERS  Returns indexes of layers with unconnected outputs
            %
            %     indices = net.getUnconnectedOutLayers()
            %
            % ## Output
            % * __indices__ vector of indices.
            %
            % See also: cv.Net.getLayer
            %
            indices = Net_(this.id, 'getUnconnectedOutLayers');
        end

        function layersTypes = getLayerTypes(this)
            %GETLAYERTYPES  Returns list of types for layer used in model
            %
            %     layersTypes = net.getLayerTypes()
            %
            % ## Output
            % * __layersTypes__ layer types.
            %
            % See also: cv.Net.getLayersCount
            %
            layersTypes = Net_(this.id, 'getLayerTypes');
        end

        function count = getLayersCount(this, layerType)
            %GETLAYERSCOUNT  Returns count of layers of specified type
            %
            %     count = net.getLayersCount(layerType)
            %
            % ## Input
            % * __layerType__ type.
            %
            % ## Output
            % * __count__ count of layers.
            %
            % See also: cv.Net.getLayerTypes
            %
            count = Net_(this.id, 'getLayersCount', layerType);
        end

        function enableFusion(this, fusion)
            %ENABLEFUSION  Enables or disables layer fusion in the network
            %
            %     net.enableFusion(fusion)
            %
            % ## Input
            % * __fusion__ true to enable the fusion, false to disable. The
            %   fusion is enabled by default.
            %
            % See also: cv.Net.connect
            %
            Net_(this.id, 'enableFusion', fusion);
        end

        function setHalideScheduler(this, scheduler)
            %SETHALIDESCHEDULER  Compile Halide layers
            %
            %     net.setHalideScheduler(scheduler)
            %
            % ## Input
            % * __scheduler__ scheduler Path to YAML file with scheduling
            %   directives.
            %
            % Schedule layers that support Halide backend. Then compile them
            % for specific target. For layers that not represented in
            % scheduling file or if no manual scheduling used at all,
            % automatic scheduling will be applied.
            %
            % See also: cv.Net.setPreferableBackend
            %
            Net_(this.id, 'setHalideScheduler', scheduler);
        end

        function setPreferableBackend(this, backend)
            %SETPREFERABLEBACKEND  Ask network to use specific computation backend where it supported
            %
            %     net.setPreferableBackend(backend)
            %
            % ## Input
            % * __backend__ computation backend supported by layers, one of:
            %   * __Default__
            %   * __Halide__ Halide language backend.
            %   * __InferenceEngine__ Intel's Deep Learning Inference Engine.
            %
            % See also: cv.Net.setPreferableTarget, cv.Net.setHalideScheduler
            %
            Net_(this.id, 'setPreferableBackend', backend);
        end

        function setPreferableTarget(this, target)
            %SETPREFERABLETARGET  Ask network to make computations on specific target device
            %
            %     net.setPreferableTarget(target)
            %
            % ## Input
            % * __target__ target device for computations, one of:
            %   * __CPU__
            %   * __OpenCL__
            %
            % See also: cv.Net.setPreferableBackend
            %
            Net_(this.id, 'setPreferableTarget', target);
        end
    end

    %% Auxiliary functions
    methods (Static)
        function blob = readTorchBlob(filename, varargin)
            %READTORCHBLOB  Loads blob which was serialized as torch.Tensor object of Torch7 framework
            %
            %     blob = cv.Net.readTorchBlob(filename)
            %     blob = cv.Net.readTorchBlob(filename, 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __filename__ path to the blob file.
            %
            % ## Output
            % * __blob__ output blob.
            %
            % ## Options
            % * __IsBinary__ specifies whether blob file was serialized in
            %   ascii mode or binary. default true.
            %
            % This function has the same limitations as cv.Net.Net with
            % regards to the Torch importer.
            %
            % See also: cv.Net.setInput, cv.Net.blobFromImages
            %
            blob = Net_(0, 'readTorchBlob', filename, varargin{:});
        end

        function blob = blobFromImages(img, varargin)
            %BLOBFROMIMAGES  Creates 4-dimensional blob from image or series of images
            %
            %     blob = cv.Net.blobFromImages(img)
            %     blob = cv.Net.blobFromImages(imgs)
            %     blob = cv.Net.blobFromImages(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __img__ input image (with 1-, 3- or 4-channels).
            % * __imgs__ input images (all with 1-, 3- or 4-channels).
            %
            % ## Output
            % * __blob__ 4-dimansional array with NCHW dimensions order.
            %
            % ## Options
            % * __Size__ spatial size for output image `[w,h]`. default [0,0]
            %   (in which case input image size is used)
            % * __Mean__ scalar with mean values which are subtracted from
            %   channels. Values are intended to be in
            %   (mean-R, mean-G, mean-B) order if image has BGR ordering and
            %   `SwapRB` is true. default [0,0,0]
            % * __ScaleFactor__ multiplier for images values. default 1.0
            % * __SwapRB__ flag which indicates that swap first and last
            %   channels in 3-channel image is necessary. For instance, Caffe
            %   models are usually trained on BGR images, while TensorFlow
            %   models expect RGB images as input. default true
            % * __Crop__ flag which indicates whether image will be cropped
            %   after resize or not. default true
            %
            % Creates blob and optionally resizes and crops the images from
            % center, subtracts mean values, scales values, and swaps blue and
            % red channels.
            %
            % If `Crop` is true, input image is resized so one side after
            % resize is equal to corresponding dimension in `Size` and another
            % one is equal or larger. Then, crop from the center is performed.
            % If `Crop` is false, direct resize without cropping and
            % preserving aspect ratio is performed.
            %
            % A blob is a 4-dimensional matrix (so-called batch) with the
            % following shape: `[num, cn, rows, cols]`.
            %
            % See also: cv.Net.setInput
            %
            blob = Net_(0, 'blobFromImages', img, varargin{:});
        end

        function imgs = imagesFromBlob(blob)
            %IMAGESFROMBLOB  Parse a 4D blob and output the images it contains
            %
            %     imgs = cv.Net.imagesFromBlob(blob)
            %
            % ## Input
            % * __blob__ 4-dimensional array `(images, channels, height, width)`
            %   in floating-point precision (`single`) from which you would
            %   like to extract the images.
            %
            % ## Output
            % * __imgs__ cell-array of matrices containing the images
            %   extracted from the blob in floating-point precision (`single`).
            %   They are non-normalized neither mean-added. The number of
            %   returned images equals the first dimension of the blob
            %   (batch size). Every image has a number of channels equals to
            %   the second dimension of the blob (depth).
            %
            % See also: cv.Net.blobFromImages
            %
            imgs = Net_(0, 'imagesFromBlob', blob);
        end

        function shrinkCaffeModel(src, dst, varargin)
            %SHRINKCAFFEMODEL  Convert all weights of Caffe network to half precision floating point
            %
            %     cv.Net.shrinkCaffeModel(src, dst)
            %     cv.Net.shrinkCaffeModel(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __src__ Path to origin model from Caffe framework contains
            %   single precision floating point weights (usually has
            %   `.caffemodel` extension).
            % * __dst__ Path to destination model with updated weights.
            %
            % ## Options
            % * __LayersTypes__ Set of layers types which parameters will be
            %   converted. By default (not set), converts only Convolutional
            %   and Fully-Connected layers' weights,
            %   i.e `{'Convolution', 'InnerProduct'}`.
            %
            % Note: Shrinked model has no origin `float32` weights so it can't
            % be used in origin Caffe framework anymore. However the structure
            % of data is taken from NVidia's
            % <https://github.com/NVIDIA/caffe Caffe fork>. So the resulting
            % model may be used there.
            %
            Net_(0, 'shrinkCaffeModel', src, dst, varargin{:});
        end

        function indices = NMSBoxes(bboxes, scores, score_threshold, nms_threshold, varargin)
            %NMSBOXES  Performs non-maximum suppression given boxes and corresponding scores
            %
            %     indices = cv.Net.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
            %     indices = cv.Net.NMSBoxes(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __bboxes__ a set of bounding boxes to apply NMS.
            % * __scores__ a set of corresponding confidences.
            % * **score_threshold** a threshold used to filter boxes by score.
            % * **nms_threshold** a threshold used in non maximum suppression.
            %
            % ## Output
            % * __indices__ the kept indices of bboxes after NMS.
            %
            % ## Options
            % * __Eta__ a coefficient in adaptive threshold formula:
            %   `nms_threshold_{i+1} = eta * nms_threshold_{i}`. default 1.0
            % * __TopK__ if `> 0`, keep at most `TopK` picked indices.
            %   default 0
            %
            % See also: cv.groupRectangles
            %
            indices = Net_(0, 'NMSBoxes', bboxes, scores, score_threshold, nms_threshold, varargin{:});
        end
    end
end


function output = callsdplr(interfacedata)

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

% Create the parameter structure
pars = options.sdplr;
pars.printlevel = options.verbose;

% *********************************************
% Bounded variables converted to constraints
% N.B. Only happens when caller is BNB
% *********************************************
if ~isempty(ub)
    [F_struc,K] = addStructureBounds(F_struc,K,ub,lb);
end

% rmfield is slow...
Knew.l = K.l;
Knew.s = K.s;
K = Knew;

if options.savedebug
    save sdplrdebug F_struc c K pars -V6
end

% *********************************************
%FIND LOW RANK STRUCTURES
% *********************************************
problem = 0;
lrA = [];
if ~isempty(lowrankdetails) | (options.sdplr.maxrank>0 & (K.s(1)>0))
    showprogress('Detecting low rank data',options.showprogress);
    sdploc = K.l+cumsum([1 K.s.^2]);
    k = 1;
    % FIX : Lazy code copy...
    [ix,jx,sx] = find(F_struc);
    if isempty(lowrankdetails)
        % Okay, this means we have to go through everything...
        % Get all data in F_struc for later
        for lmiid = 1:length(K.s)
            removethese = zeros(1,size(F_struc,2)-1);
            for i = 1:size(F_struc,2)-1
                Fi = reshape(F_struc(sdploc(lmiid):sdploc(lmiid+1)-1,i+1),K.s(lmiid),K.s(lmiid));
                if nnz(Fi)>0
                    [D,V] = getfactors(Fi);
                    if length(D) <= options.sdplr.maxrank
                        lrA(k).cons = i;
                        lrA(k).start = sdploc(lmiid);
                        lrA(k).D = D;
                        lrA(k).V = V;
                        k = k+1;
                        removethese(i) = 1;
                    end
                end
            end
            removethese = find(removethese);
            if ~isempty(removethese)
                these = find((sdploc(lmiid+1)-1>= ix) & (ix>=sdploc(lmiid)) & ismember(jx,1+removethese));
                sx(these) = 0;
            end
        end
    else
        % Just check those constraints declared low-rank by user
        for lrdef = 1:length(lowrankdetails)
            for lrconstraint = 1:length(lowrankdetails{lrdef}.id)
                lmiid = lowrankdetails{lrdef}.id(lrconstraint);
                removethese = zeros(1,size(F_struc,2)-1);
                checkthese = lowrankdetails{lrdef}.variables;
                if isempty(checkthese)
                    checkthese = 1:size(F_struc,2)-1;
                end
                for i = checkthese
                    Fi = reshape(F_struc(sdploc(lmiid):sdploc(lmiid+1)-1,i+1),K.s(lmiid),K.s(lmiid));
                    if nnz(Fi)>0
                        [D,V] = getfactors(Fi);
                        if (options.sdplr.maxrank == 0) | (options.sdplr.maxrank ~= 0 & (length(D) <= options.sdplr.maxrank))
                            lrA(k).cons = i;
                            lrA(k).start = sdploc(lmiid);
                            lrA(k).D = D;
                            lrA(k).V = V;
                            k = k+1;
                            removethese(i) = 1;
                        end
                    end
                end
                removethese = find(removethese);
                if ~isempty(removethese)
                    these = find((sdploc(lmiid+1)-1>= ix) & (ix>=sdploc(lmiid)) & ismember(jx,1+removethese));
                    sx(these) = 0;
                    %F_struc(sdploc(lmiid):sdploc(lmiid+1)-1,1+removethese) = 0;
                end
            end
        end
        F_struc = sparse(ix,jx,sx,size(F_struc,1),size(F_struc,2));
    end
end

% *********************************************
% CALL SDPLR
% *********************************************
if options.showprogress;showprogress(['Calling ' interfacedata.solver.tag],options.showprogress);end
solvertime = tic;
if isempty(lrA)
   [x_s,y_s,info] = sdplr(F_struc(:,2:end),c,F_struc(:,1),K);
else
   % pars.reduce = 0;
    [x_s,y_s,info] = sdplr(F_struc(:,2:end),full(c),full(F_struc(:,1)),K,pars,lrA);
end
solvertime = toc(solvertime);

% YALMIP format
D_struc = x_s;
x = -y_s;

% No error codes currently...
problem = 0;

% Save ALL data sent to solver
if options.savesolverinput
    solverinput.A = F_struc(:,2:end);
    solverinput.c = F_struc(:,1);
    solverinput.b = c;
    solverinput.K = K;
    solverinput.pars = pars;
else
    solverinput = [];
end

% Save ALL data from the solution?
if options.savesolveroutput
    solveroutput.x = x_s;
    solveroutput.y = y_s;
    solveroutput.info = info;
else
    solveroutput = [];
end

% Standard interface
output = createOutputStructure(x(:),D_struc,[],problem,interfacedata.solver.tag,solverinput,solveroutput,solvertime);

function [D,V] = getfactors(Fi)
if nnz(Fi)>0
    [v,d] = eig(full(Fi));
    d = diag(d);
    keep = find(abs(d)>1e-6);
    V = v(:,keep);
    D = d(keep);
    % lrA(k).cons = i;
    % lrA(k).start = sdploc(j);
    % lrA(k).D = D;
    % lrA(k).V = V;
    % k = k+1;
else
    D = [];
    V = [];
end


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

indexS = planC{end};

if length(doseBinsV) == 1
    doseBinsV(2) = 2*doseBinsV(1);
    volsHistV(2) = 0;
end

%Calculate width of bins, use to find middle of each bin.
binWidthsV = diff(doseBinsV);
lastBinWidth = binWidthsV(end);
binWidthsV(end+1) = lastBinWidth;

%Extract dose bin values, adding half to binwidth to get lower edge.
planC{indexS.IVH}(IVHNum).IVHMatrix(:,1) = doseBinsV - binWidthsV/2;
planC{indexS.IVH}(IVHNum).IVHMatrix(:,2) = volsHistV;
return;


function test_pull1456

% MEM 8gb
% WALLTIME 00:20:00
% DEPENDENCY ft_sourceanalysis ft_inverse_eloreta

load(dccnpath('/home/common/matlab/fieldtrip/data/test/pull1456.mat'));

% Compute spectrum
cfg = [];
cfg.output = 'powandcsd';
cfg.channel = 'all';
cfg.method = 'mtmfft';
cfg.taper = 'hanning';%'boxcar';
dataFreq1 = ft_freqanalysis(cfg, dataPre);
cfg.output = 'fourier';
dataFreq2 = ft_freqanalysis(cfg, dataPre);

% source reconstruction
cfg = [];
cfg.method = 'eloreta';
cfg.sourcemodel = sourcemodel;
cfg.headmodel = vol.vol;
source_eloreta1 = ft_sourceanalysis(cfg, dataFreq1); % compute the source model

assert(isequal(size(source_eloreta1.avg.pow),[size(source_eloreta1.pos,1) numel(source_eloreta1.freq)]));

source_eloreta2 = ft_sourceanalysis(cfg, dataFreq2); % compute the source model
i1 = find(source_eloreta2.inside,1,'first');

assert(isequal(size(source_eloreta2.avg.mom{i1}),[3 80 193]));

cfg.mne.snr = 10;
cfg.method = 'mne';
source_mne1 = ft_sourceanalysis(cfg, dataFreq1);
source_mne2 = ft_sourceanalysis(cfg, dataFreq2);

% -> this does not work. AT ALLedit f
%cfg.method = 'harmony';
%source_harmony1 = ft_sourceanalysis(cfg, dataFreq1);
%source_harmony2 = ft_sourceanalysis(cfg, dataFreq2);

% -> this should throw an explicit error
cfg.method = 'music';
try
  source_music1 = ft_sourceanalysis(cfg, dataFreq1);
  ok = true;
catch
  ok = false;
end
assert(~ok);
try
  source_music2 = ft_sourceanalysis(cfg, dataFreq2);
  ok = true;
catch
  ok = false;
end
assert(~ok);

% -> this currently also does note work, but throws a non informative error
%cfg.method = 'rv';
%source_rv1 = ft_sourceanalysis(cfg, dataFreq1);
%source_rv2 = ft_sourceanalysis(cfg, dataFreq2);

% -----------------------------

% Compute an ERP
cfg = [];
cfg.covariance = 'yes';
cfg.covariancewindow = [-1 0]; % calculate the average of the covariance matrices
% for each trial (but using the pre-event baseline data only)
dataAvg = ft_timelockanalysis(cfg, dataPre);

% source reconstruction
cfg = [];
cfg.method = 'eloreta';
cfg.sourcemodel = sourcemodel;
cfg.headmodel = vol.vol;
sourceTime = ft_sourceanalysis(cfg, dataAvg);


% The COBRAToolbox: testWriteCbModel.m
%
% Purpose:
%     - test the writeCbModel function
%
% Authors:
%     - Laurent Heirendt

global CBTDIR

% save the current path
currentDir = pwd;

% initialize the test
fileDir = fileparts(which('testWriteCbModel'));
cd(fileDir);

% Note: test is only compatible with Matlab R2015b or later
if ~verLessThan('matlab', '8.6')
    % define tolerance
    tol = 1e-6;

    % load the model
    model = getDistributedModel('ecoli_core_model.mat');

    % write the model to an xls file
    writeCbModel(model, 'xlsx', 'testData');

    % read in the xls model file
    modelIn = xls2model('testData.xlsx');

    % convert an old style model
    model = convertOldStyleModel(model);

    % test
    assert(isequal(model.lb, modelIn.lb))
    assert(isequal(model.b, modelIn.b))
    assert(isequal(model.ub, modelIn.ub))
    assert(isequal(sort(model.mets), sort(modelIn.mets)))
    assert(isequal(model.csense, modelIn.csense))
    assert(isequal(model.osenseStr, modelIn.osenseStr))
    assert(isequal(model.rxns, modelIn.rxns))
    assert(isequal(sort(model.genes), sort(modelIn.genes)))
    assert(isequal(model.c, modelIn.c))

    % NOTE: model.rules and model.S are different from modelIn.S and modelIn.rules
    %       as the metabolites are not ordered in the same way.

    solverOK = changeCobraSolver('glpk');

    if solverOK
        % run an LP and compare the solutions
        solModel = optimizeCbModel(model);
        solModelIn = optimizeCbModel(modelIn);

        assert(abs(solModel.f - solModelIn.f) < tol)
        assert(solModel.stat == solModelIn.stat)
    end

    % remove the generated file
    delete('testData.xlsx');
else
    fprintf('\ntestWriteCbModel is not compatible with this version of MATLAB. Please upgrade your version of MATLAB.\n\n');
end

% test varargin

% load the model
model = getDistributedModel('ecoli_core_model.mat');

% write out using varargin
outmodel1 = writeCbModel(model, 'format', 'mat', 'fileName', 'testModel1');
outmodel2 = writeCbModel(model, 'mat', 'testModel2.mat');

% read in the testModel and testModel2
testModel1 = readCbModel('testModel1.mat');
testModel2 = readCbModel('testModel2.mat');
testModel2.description = '';
testModel1.description = '';
assert(isequal(testModel1, testModel2));

% test the legacy signature with more input arguments
[compSymbols, compNames] = getDefaultCompartmentSymbols();
outmodel3 = writeCbModel(model, 'mat', 'testModel3.mat', compNames, compSymbols);
testModel3 = readCbModel('testModel3.mat');
testModel3.description = '';
assert(isequal(testModel1, testModel3));

% test new signature
outmodel4 = writeCbModel(model, 'format', 'mat', 'fileName', 'testModel4.mat', 'compNames', compNames, 'compSymbols', compSymbols);
outmodel5 = writeCbModel(model, 'format', 'mat', 'compNames', compNames, 'compSymbols', compSymbols,'fileName', 'testModel5.mat');
testModel4 = readCbModel('testModel4.mat');
testModel5 = readCbModel('testModel5.mat');
testModel4.description = '';
testModel5.description = '';
assert(isequal(testModel4, testModel5));

% remove generate files during testing
for i = 1:5
    delete(['testModel', num2str(i),'.mat']);
end

% change to old directory
cd(currentDir);


function [success]=checksignres_favar(Sj,fj)
 % check here for success only

% if there are no sign restrictions on this shock, don't do anything and automatically count as success
if isempty(Sj)
success=1;
% if there are sign restriction on this shock, check them
else
% check if the restrictions hold
   % if yes, count as success
   if all(Sj*fj>=0)
   success=1;
%    % if the restrictions do not hold, there may still be a possibility by switching the sign of qj
%    elseif all(Sj*(-fj)>=0)
%    qj=-qj;
%    success=1;
   % else, if there is no way to have qj succesful, count as a fail
   else
   success=0;
   end
end


function opts = getTrainingOptions(hyperparam,imds_validation)

if isempty(imds_validation) % if there is no validation set
opts = trainingOptions('adam',...
    'InitialLearnRate',hyperparam.InitialLearnRate,...
    'L2Regularization',hyperparam.L2Regularization,...
    'MiniBatchSize',hyperparam.MiniBatchSize,...
    'MaxEpochs',hyperparam.MaxEpochs,...
    'ExecutionEnvironment',hyperparam.ExecutionEnvironment,...
    'VerboseFrequency',50,...
    'Plots','training-progress');
else  % if there is a validation set
opts = trainingOptions('adam',...
    'InitialLearnRate',hyperparam.InitialLearnRate,...
    'ValidationData',imds_validation,...
    'ValidationFrequency',hyperparam.ValidationFrequency,...
    'ValidationPatience',hyperparam.ValidationPatience,...
    'L2Regularization',hyperparam.L2Regularization,...
    'MiniBatchSize',hyperparam.MiniBatchSize,...
    'MaxEpochs',hyperparam.MaxEpochs,...
    'ExecutionEnvironment',hyperparam.ExecutionEnvironment,...
    'VerboseFrequency',50,...
    'Plots','training-progress');
end

end