%% visall
% Visualize x-, y-, z-normal slices of a 3D field solution with objects and
% sources.

%%% Syntax
%  visall(scalar3d, [opts])
%  visall(scalar3d, obj_array, [opts])
%  visall(scalar3d, obj_array, src_array, [opts])

%%% Description
% |visall(scalar3d)| vizualizes one of the x-, y-, z-components of the E- or
% H-field stored as an instance of <Scalar3d.html |Scalar3d|>.  The field is
% visualized on x-, y-, z-normal slices, which are shown in 3D as well as in 2D.
%
% |visall(..., obj_array)| visualizes the objects in |obj_array| with the slices
% of a field. The elements of |obj_array| are instances of <EMObject.html
% |EMObject|>.
%
% |vis2d(..., obj_array, src_array)| visualizes the objects and sources in
% |obj_array| and |src_array| with the slices of a field.  The elements of
% |src_array| are instances of <Source.html |Source|>.
%
% The optional argument |opts| is an options structure that controls the
% behavior of visualization.  The allowed fields of |opts| are explained below.
% The default values of the fields are shown in brackets |{}|.
%
% * |opts.withgrid|: |true| or |{false}| to show the grid or not.
% * |opts.withinterp|: |{true}| or |false| to interpolate the field or not.
% * |opts.withpml|: |true| or |{false}| to show the PML regions or not.
% * |opts.withabs|: |true| or |{false}| to show the absolute values of the field
% or not.
% * |opts.cscale|: positive value that controls the color bar range.  Set to
% values less than |1.0| to saturate colors.  The default value is |1.0|.
% * |opts.cmax|: another positive value that controls the color bar range; the
% positive maximum of the color bar range is |cscale * cmax|.  If it is set to
% |NaN|, which is the default, then |cscale * (maximum amplitude of the plotted
% data)| is used for the maximum of the color bar range.
% * |opts.isopaque|: |{true}| or |false| to show opaque slices in 3D or not.
% * |opts.withobjsrc|: |true| or |false| to show the objects and sources or not.
% The default values is |true| when the number of objects is small (<= 20), but
% |false| when the number of objects is large (> 20).  To show only sources
% without objects, provide an empty |obj_array| in |visall()|.
% * |opts.phase|: additional phase angle |phi|.  The field is visualized with an
% additional factor |exp(i*phi)| multiplied.  Not useful if |opts.withabs =
% true|.

%%% Note
% When |opts.isopaque = false| is used, the 3D view shows the slices nicely with
% some transparency.  However, the 2D views show worse-looking images because
% the figure renderer that supports transparency interpolates colors differently
% from the normal renderer.

%%% Example
%   [E, H, obj_array, src_array] = maxwell_run({ARGUMENTS});
%   opts.cscale = 1e-1;
%   opts.wihabs = true;
%   visall(E{Axis.x}, obj_array, src_array, opts);

function visall(scalar3d, varargin)

narginchk(1, 4)
chkarg(istypesizeof(scalar3d, 'Scalar3d'), '"scalar3d" should be instance of Scalar3d.');

iarg = 2;
ivararg = 1;
obj_array = [];
if iarg <= nargin && ~istypesizeof(varargin{ivararg}, 'struct')
	obj_array = varargin{ivararg};
	chkarg(istypesizeof(obj_array, 'EMObject', [1 0]), ...
		'argument %d should be "obj_array" (row vector with EMObject as elements).', iarg);
	iarg = iarg + 1;
	ivararg = ivararg + 1;
end

src_array = [];
if iarg <= nargin && ~istypesizeof(varargin{ivararg}, 'struct')
	src_array = varargin{ivararg};
	chkarg(istypesizeof(src_array, 'Source', [1 0]), ...
		'argument %d should be "src_array" (row vector with Source as elements).', iarg);
	iarg = iarg + 1;
	ivararg = ivararg + 1;
end

no_opts = true;
if iarg <= nargin
	opts = varargin{ivararg};
	chkarg(istypesizeof(opts, 'struct'), 'argument %d should be "opts" (struct).', iarg);
	no_opts = false;
end

if no_opts || ~isfield(opts, 'withgrid')
	opts.withgrid = false;
end
if no_opts || ~isfield(opts, 'withinterp')
	opts.withinterp = true;
end
if no_opts || ~isfield(opts, 'withpml')
	opts.withpml = false;
end
if no_opts || ~isfield(opts, 'withabs')
	opts.withabs = false;
end
if no_opts || ~isfield(opts, 'cscale')
	opts.cscale = 1.0;
end
if no_opts || ~isfield(opts, 'cmax')
	opts.cmax = NaN;
end
if no_opts || ~isfield(opts, 'isopaque')
	opts.isopaque = true;
end
if no_opts || ~isfield(opts, 'withobjsrc')
	opts.withobjsrc = true;
end
if no_opts || ~isfield(opts, 'phase')
	opts.phase = 0;
end

tv = TotalView3d();
tv.scalar3d = scalar3d;
tv.obj_array = obj_array;
tv.src_array = src_array;
tv.withgrid = opts.withgrid;
tv.withinterp = opts.withinterp;
tv.withpml = opts.withpml;
tv.withabs = opts.withabs;
tv.cscale = opts.cscale;
tv.cmax = opts.cmax;
tv.isopaque = opts.isopaque;
tv.withobjsrc = opts.withobjsrc;
tv.phase_angle = opts.phase;

tv.show();


function [aTS, bTS] = cRecon1(scanParams, fName, slice, compFlag, rotFlag, shifts)

% [aTS, bTS] = cRecon1(scanParams, fName, slice, compFlag, shifts);
%
% Load and crop complex recon data.
% Returns pair of single-slice time-series arrays of size:
% ny x nx x nFrames -- aTS is real and bTS is imaginary;
% the latter is returned only if the optional compFlag
% input is set. Time-duration and spatial cropping are performed,
% but no trend removal. Inputs are pFile name [fName], and
% slice index [slice]. Optional input rotFlag performs a 90
% degree rotation to make functional images match inplanes;
% use MakeMovie.m or similar to check if necessary. Optional
% input shifts allows correction of fallback errors or similar.
% Assumes pwd points to valid session
% directory, and uses global mrSESSION.
%
% DBR 12/00

global mrSESSION

if ~exist('compFlag'), compFlag = 0; end
if ~exist('rotFlag'), rotFlag = 0; end

% Do recon, extract complex time series:
[aTS, bTS] = PaulyRecon(scanParams, fName, slice, compFlag, rotFlag);

% Remove junk frames:
f0 = mrSESSION.junkFirstFrames+1;
nFrames = mrSESSION.nFrames;
fEnd = f0 + nFrames - 1;

% Crop:
x0 = mrSESSION.tseriesCrop(1, 1) + shifts(2);
xN = mrSESSION.tseriesCrop(2, 1) + shifts(2);
y0 = mrSESSION.tseriesCrop(1, 2) + shifts(1);
yN = mrSESSION.tseriesCrop(2, 2) + shifts(1);

% Crop in time/space and shuffle to standard t-series shape:
aTS = aTS(f0:fEnd, :, :);
aTS = aTS(:, y0:yN, x0:xN);
aTS = reshape(aTS, nFrames, (yN-y0+1)*(xN-x0+1));
if compFlag
  bTS = bTS(f0:fEnd, :, :);
  bTS = bTS(:, y0:yN, x0:xN);
  bTS = reshape(bTS, nFrames, (yN-y0+1)*(xN-x0+1));
end


function printConstraints(model, minInf, maxInf, rxnSelection, modelAfter, printLevel)
% Print all network constraints that are between `-Inf (minInf)` or `+Inf
% (maxInf) inclusive`
%
% USAGE:
%
%    printConstraints(model, minInf, maxInf)
%
% INPUTS:
%    model:     COBRA model structure
%
% OPTIONAL INPUTS:
%   minInf:       value that is considered as -Inf (or desired minimum cutoff value)
%   maxInf:       value that is considered as +Inf (or desired maximum cutoff value)
%   rxnSelection: boolean vector or cell array of reaction abbreviations for the reactions to be printed
%   modelAfter:   model after some perturbation to the bounds
%   printLevel:
%

% .. Authors:
%       - Ines Thiele 02/09, Ronan Fleming 2020

if ~exist('minInf','var')|| isempty(minInf)
    minInf=-Inf;
end
if ~exist('maxInf','var') || isempty(maxInf)
    maxInf=Inf;
end
if ~isfield(model,'S')
    if isfield(model,'A')
        model.S = model.A(ismember(model.csense,'E'),:);
        model.dsense = model.csense(~ismember(model.csense,'E'));
        model.csense = model.csense(ismember(model.csense,'E'));
        model.C = model.A(~ismember(model.csense,'E'),:);
    else
        error('model.S missing')
    end
end
if ~exist('rxnSelection','var')
    rxnSelection=true(size(model.S,2),1);
end
if ~exist('printLevel','var')
    printLevel=0;
end
if exist('modelAfter','var')
    if isempty(modelAfter)
        clear modelAfter
    end
end

if ischar(rxnSelection) || iscell(rxnSelection)
    rxnSelection = ismember(model.rxns,rxnSelection);
end

if ~any(rxnSelection)
    return
end

closedRxnBool = model.lb == model.ub & model.lb == 0 & rxnSelection;
reversibleRxnBool = model.lb >= minInf & model.lb < 0 & model.ub <= maxInf & model.ub > 0 & rxnSelection;
%Forward and reverse reactions with NON-ZERO bounds
fwdRxnBoolNon0b = model.lb >= minInf & model.lb > 0 & ~reversibleRxnBool & ~closedRxnBool & model.ub <= maxInf & rxnSelection;
revRxnBoolNon0b = model.lb >= minInf & model.ub <= maxInf & model.ub < 0 & ~reversibleRxnBool & ~closedRxnBool & rxnSelection;
%Forward and reverse reactions with ZERO bounds (standard)
fwdRxnBool0b = model.lb >= minInf & model.lb == 0 & ~reversibleRxnBool & ~closedRxnBool & model.ub <= maxInf & rxnSelection;
revRxnBool0b = model.lb >= minInf & model.ub <= maxInf & model.ub == 0 & ~reversibleRxnBool & ~closedRxnBool & rxnSelection;

if ~any(closedRxnBool | reversibleRxnBool | fwdRxnBool0b | revRxnBool0b | fwdRxnBoolNon0b | revRxnBoolNon0b)
    boolRemainder = rxnSelection & ~(closedRxnBool | reversibleRxnBool | fwdRxnBool | revRxnBool);
    warning('no subset with bounds between [minInf maxInf]')
else
    boolRemainder=0;
end

if any(closedRxnBool & reversibleRxnBool) || any(closedRxnBool & fwdRxnBool0b) || any(closedRxnBool & revRxnBool0b) || any(fwdRxnBool0b & revRxnBool0b)
    warning('inconsistent boolean variables')
end

if isfield(model,'rxnNames')
rxnNames=model.rxnNames;
else
    rxnNames=cell(size(model.S,2),1);
end
for j=1:size(model.S,2)
    rxnNames{j}=rxnNames{j}(1:min(60,length(rxnNames{j})));
end

if ~any(closedRxnBool)
    if printLevel>0
        fprintf('%s\n','No closed reactions with non-default constraints.');
    end
else
    if printLevel>0
        fprintf('%s\n', ['...closed reaction constraints:']);
    end
    if exist('modelAfter','var')
        T = table(model.rxns(closedRxnBool),rxnNames(closedRxnBool),model.lb(closedRxnBool),modelAfter.lb(closedRxnBool),model.ub(closedRxnBool),modelAfter.ub(closedRxnBool),printRxnFormula(model, 'rxnAbbrList',model.rxns(closedRxnBool),'printFlag',0),'VariableNames',{'Closed_Reaction','Name','lb_before','lb_after','ub_before','ub_after','equation'});
    else
        T = table(model.rxns(closedRxnBool),rxnNames(closedRxnBool),model.lb(closedRxnBool),model.ub(closedRxnBool),printRxnFormula(model, 'rxnAbbrList', model.rxns(closedRxnBool),'printFlag',0),'VariableNames',{'Closed_reaction','Name','lb','ub','equation'});
    end
    disp(T);
end

if ~any(fwdRxnBool0b)
    if printLevel>0
        fprintf('%s\n','No forward reactions with non-default constraints.');
    end
else
    if printLevel>0
        fprintf('%s\n', ['...forward reactions with non-[0, ' num2str(maxInf) '] constraints:']);
    end
    if exist('modelAfter','var')
        T = table(model.rxns(fwdRxnBool0b),rxnNames(fwdRxnBool0b),model.lb(fwdRxnBool0b),modelAfter.lb(fwdRxnBool0b),model.ub(fwdRxnBool0b),modelAfter.ub(fwdRxnBool0b),printRxnFormula(model, 'rxnAbbrList',model.rxns(fwdRxnBool0b),'printFlag',0),'VariableNames',{'Forward_Reaction, 0 bound','Name','lb_before','lb_after','ub_before','ub_after','equation'});
    else
        T = table(model.rxns(fwdRxnBool0b),rxnNames(fwdRxnBool0b),model.lb(fwdRxnBool0b),model.ub(fwdRxnBool0b),printRxnFormula(model, 'rxnAbbrList', model.rxns(fwdRxnBool0b),'printFlag',0),'VariableNames',{'Forward_Reaction, 0 bound','Name','lb','ub','equation'});
    end
    disp(T);
end

if ~any(revRxnBool0b)
    if printLevel>0
        fprintf('%s\n','No reverse reactions with non-default constraints.');
    end
else
    if printLevel>0
        fprintf('%s\n',['...reverse reactions with non-[' num2str(minInf)  ', 0]  constraints:']);
    end
    if exist('modelAfter','var')
        T = table(model.rxns(revRxnBool0b),rxnNames(revRxnBool0b),model.lb(revRxnBool0b),modelAfter.lb(revRxnBool0b),model.ub(revRxnBool0b),modelAfter.ub(revRxnBool0b),printRxnFormula(model, 'rxnAbbrList', model.rxns(revRxnBool0b),'printFlag',0),'VariableNames',{'Reverse_Reaction, 0 bound','Name','lb_before','lb_after','ub_before','ub_after','equation'});
    else
        T = table(model.rxns(revRxnBool0b),rxnNames(revRxnBool0b),model.lb(revRxnBool0b),model.ub(revRxnBool0b),printRxnFormula(model, 'rxnAbbrList', model.rxns(revRxnBool0b),'printFlag',0),'VariableNames',{'Reverse_Reaction, 0 bound','Name','lb','ub','equation'});
    end
    disp(T);
end

if ~any(fwdRxnBoolNon0b)
    if printLevel>0
        fprintf('%s\n','No forward reactions with non-default constraints.');
    end
else
    if printLevel>0
        fprintf('%s\n', ['...forward reactions with non-[0, ' num2str(maxInf) '] constraints:']);
    end
    if exist('modelAfter','var')
        T = table(model.rxns(fwdRxnBoolNon0b),rxnNames(fwdRxnBoolNon0b),model.lb(fwdRxnBoolNon0b),modelAfter.lb(fwdRxnBoolNon0b),model.ub(fwdRxnBoolNon0b),modelAfter.ub(fwdRxnBoolNon0b),printRxnFormula(model, 'rxnAbbrList',model.rxns(fwdRxnBoolNon0b),'printFlag',0),'VariableNames',{'Forward_Reaction, non-0 bound','Name','lb_before','lb_after','ub_before','ub_after','equation'});
    else
        T = table(model.rxns(fwdRxnBoolNon0b),rxnNames(fwdRxnBoolNon0b),model.lb(fwdRxnBoolNon0b),model.ub(fwdRxnBoolNon0b),printRxnFormula(model, 'rxnAbbrList', model.rxns(fwdRxnBoolNon0b),'printFlag',0),'VariableNames',{'Forward_Reaction, non-0 bound','Name','lb','ub','equation'});
    end
    disp(T);
end

if ~any(revRxnBoolNon0b)
    if printLevel>0
        fprintf('%s\n','No reverse reactions with non-default constraints.');
    end
else
    if printLevel>0
        fprintf('%s\n',['...reverse reactions with non-[' num2str(minInf)  ', 0]  constraints:']);
    end
    if exist('modelAfter','var')
        T = table(model.rxns(revRxnBoolNon0b),rxnNames(revRxnBoolNon0b),model.lb(revRxnBoolNon0b),modelAfter.lb(revRxnBoolNon0b),model.ub(revRxnBoolNon0b),modelAfter.ub(revRxnBoolNon0b),printRxnFormula(model, 'rxnAbbrList', model.rxns(revRxnBoolNon0b),'printFlag',0),'VariableNames',{'Reverse_Reaction, non-0 bound','Name','lb_before','lb_after','ub_before','ub_after','equation'});
    else
        T = table(model.rxns(revRxnBoolNon0b),rxnNames(revRxnBoolNon0b),model.lb(revRxnBoolNon0b),model.ub(revRxnBoolNon0b),printRxnFormula(model, 'rxnAbbrList', model.rxns(revRxnBoolNon0b),'printFlag',0),'VariableNames',{'Reverse_Reaction, non-0 bound','Name','lb','ub','equation'});
    end
    disp(T);
end

if ~any(reversibleRxnBool)
    if printLevel>0
        fprintf('%s\n','No reversible reactions with non-default constraints.');
    end
else
    if printLevel>0
        fprintf('%s\n',['...reversible reactions with non-[' num2str(minInf)  ', ' num2str(maxInf) ']  constraints:']);
    end
    if exist('modelAfter','var')
        T = table(model.rxns(reversibleRxnBool),rxnNames(reversibleRxnBool),model.lb(reversibleRxnBool),modelAfter.lb(reversibleRxnBool),model.ub(reversibleRxnBool),modelAfter.ub(reversibleRxnBool),printRxnFormula(model, 'rxnAbbrList', model.rxns(reversibleRxnBool),'printFlag',0),'VariableNames',{'Reversible_Reaction','Name','lb_before','lb_after','ub_before','ub_after','equation'});
    else
        T = table(model.rxns(reversibleRxnBool),rxnNames(reversibleRxnBool),model.lb(reversibleRxnBool),model.ub(reversibleRxnBool),printRxnFormula(model, 'rxnAbbrList', model.rxns(reversibleRxnBool),'printFlag',0),'VariableNames',{'Reversible_Reaction','Name','lb','ub','equation'});
    end
    disp(T);
end

% if ~any(reversibleRxnBool)
%     if printLevel>0
%         fprintf('%s\n','No reversible reactions with non-default constraints.');
%     end
% else
%     if printLevel>0
%         fprintf('%s\n',['...reversible reactions with non-[' num2str(minInf)  ', ' num2str(maxInf) ']  constraints:']);
%     end
%     if exist('modelAfter','var')
%         T = table(model.rxns(reversibleRxnBool),rxnNames(reversibleRxnBool),model.lb(reversibleRxnBool),modelAfter.lb(reversibleRxnBool),model.ub(reversibleRxnBool),modelAfter.ub(reversibleRxnBool),printRxnFormula(model, 'rxnAbbrList', model.rxns(reversibleRxnBool),'printFlag',0),'VariableNames',{'Reversible_Reaction','Name','lb_before','lb_after','ub_before','ub_after','equation'});
%     else
%         T = table(model.rxns(reversibleRxnBool),rxnNames(reversibleRxnBool),model.lb(reversibleRxnBool),model.ub(reversibleRxnBool),printRxnFormula(model, 'rxnAbbrList', model.rxns(reversibleRxnBool),'printFlag',0),'VariableNames',{'Reversible_Reaction','Name','lb','ub','equation'});
%     end
%     disp(T);
% end

if any(boolRemainder)
    if printLevel>0
        fprintf('%s\n',['...reversible reactions with non-[' num2str(minInf)  ', ' num2str(maxInf) ']  constraints:']);
    end
    if exist('modelAfter','var')
        T = table(model.rxns(boolRemainder),rxnNames(boolRemainder),model.lb(boolRemainder),modelAfter.lb(boolRemainder),model.ub(boolRemainder),modelAfter.ub(boolRemainder),printRxnFormula(model, 'rxnAbbrList', model.rxns(boolRemainder),'printFlag',0),'VariableNames',{'Reversible_Reaction','Name','lb_before','lb_after','ub_before','ub_after','equation'});
    else
        T = table(model.rxns(boolRemainder),rxnNames(boolRemainder),model.lb(boolRemainder),model.ub(boolRemainder),printRxnFormula(model, 'rxnAbbrList', model.rxns(boolRemainder),'printFlag',0),'VariableNames',{'Reversible_Reaction','Name','lb','ub','equation'});
    end
    disp(T);
end

fprintf('\n');


%--------------------------------------------------------------------------------------------------------
% The system is created based on the principles described in the following paper
% Jimmy SJ. Ren and Li Xu, "On Vectorization of Deep Convolutional Neural Networks for Vision Tasks",
% The 29th AAAI Conference on Artificial Intelligence (AAAI-15). Austin, Texas, USA, January 25-30, 2015
% email: jimmy.sj.ren@gmail.com
%--------------------------------------------------------------------------------------------------------
addpath applications/
addpath utils/
addpath cuda/
addpath mem/
addpath layers/
addpath layers_adapters/
addpath pipeline/
addpath data/MNIST/

clearvars -global config;
clearvars -global mem;

global config;
mnist_configure();
init(0);

%verify_mode = 'gradient';
verify_mode = 'speed';

if strcmp(verify_mode, 'gradient')
    % for gradient checking
    image = config.NEW_MEM(rand(32, 32, 1, config.batch_size)) / (32*32);
    label = config.NEW_MEM((ones(10, config.batch_size) * 2 - 1)) ./ 10;
    op_train_pipe(image, label);
    computeNumericalGradient(image, label, 1);
elseif strcmp(verify_mode, 'speed')
    % for speed testing
    I = gpuArray(single(rand(32,32,1,config.batch_size)));
    y = gpuArray(single(rand(10, config.batch_size)));
    loop = 100;
    tic
    for m = 1:loop
        op_train_pipe(I, y);
    end
    elapse = toc/loop/config.batch_size;
    num = 1 / elapse;
    fprintf('Process %f samples per second.\n', num);
end


function img = createImage(size, type, varargin)
%CREATEIMAGE Create a new image with given size and type
%
%   Deprecated, use 'imCreate' instead.
%
%   Usage
%   IMG = createImage(SIZE, TYPE)
%   IMG = createImage(SIZE, TYPE, VALUE)
%
%   Description
%   IMG = createImage(SIZE, TYPE)
%   SIZE is a row vector containing the size of the result image, and TYPE
%   is a string representating the class of result image.
%   The effect is similar to the function 'zeros' or 'false', but attends
%   to provide a unified method to create image.
%
%   Example
%   % create uint8 image
%   img = createImage([256 256], 'uint8');
%   imshow(img);
%
%   % create binary image
%   img = createImage([256 256], 'logical');
%   imshow(img);
%
%   % create an image with same size and type as another image
%   baseImage = imread('cameraman.tif');
%   img = createImage(size(baseImage), class(baseImage));
%   imshow(img);
%
%   % create uint8 image filled with dark gray pixels
%   img = createImage([256 256], 'uint8', 100);
%   imshow(img);
%
%   See also
%   zeros, ones, false
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2010-07-19,    using Matlab 7.9.0.529 (R2009b)
% Copyright 2010 INRA - Cepia Software Platform.

warning('malimpa:imFilters:createImage:deprecated', ...
    'function createImage is obsolete, use imCreate instead');

% allocate memory depending on type
if strcmp(type, 'logical')
    img = false(size);
else
    img = zeros(size, type);
end

% initialiaze with given value
if ~isempty(varargin)
    img(:) = varargin{1};
end


function sVF = rotate(sVF, rot)
% rotate a function by a rotation
%
% Syntax
%   sVF = sVF.rotate(rot)
%
% Input
%  sVF - @S2VectorFieldHarmonic
%  rot - @rotation
%
% Output
%   sVF - @S2VectorFieldHarmonic
%

sVF.sF = rotate(sVF.sF, rot);

end


% This is used to set the VIF algorithms that to be run
%
% Author:Xingchen Zhang, Ping Ye, Gang Xiao
% Contact: xingchen.zhang@imperial.ac.uk

function methods=configMethods

 methodVIFB={struct('name','ADF'),...
        struct('name','CBF'),...
        struct('name','CNN'),...
        struct('name','DLF'),...
        struct('name','FPDE'),...
        struct('name','GFCE'),...
        struct('name','GFF'),...
        struct('name','GTF'),...
        struct('name','HMSD_GF'),...
        struct('name','Hybrid_MSD'),...
        struct('name','IFEVIP'),...
        struct('name','LatLRR'),...
        struct('name','MGFF'),...
        struct('name','MST_SR'),...
        struct('name','MSVD'),...
        struct('name','NSCT_SR'),...
        struct('name','ResNet'),...
        struct('name','RP_SR'),...
        struct('name','TIF'),...
        struct('name','VSMWLS'),...
     };

methods = [methodVIFB];


function y = abs( x )

%Disciplined convex/geometric programming information for ABS:
%   ABS(X) is convex and nonmonotonic in X. Therefore, when used in
%   DCPs, X must be affine. ABS(X) is not useful in DGPs, since all
%   log-convex and log-concave expressions are already positive.

%
% Determine the expression types
%

% 0 : convex, concave, invalid
% 1 : constant
% 2 : real affine
% 3 : complex affine
persistent remap
if isempty( remap ),
    remap_1 = cvx_remap( 'constant' );
    remap_2 = cvx_remap( 'real-affine' );
    remap_3 = cvx_remap( 'complex-affine' );
    remap_4 = cvx_remap( 'log-valid' );
    remap = remap_1 + ( 2 * remap_2 + 3 * remap_3 + 4 * remap_4 ) .* ~remap_1;
end
v = remap( cvx_classify( x ) );

%
% Process each type of expression one piece at a time
%

vu = sort( v(:) );
vu = vu([true;diff(vu)~=0]);
nv = length( vu );
sx = x.size_;
if nv ~= 1,
    y = cvx( sx, [] );
end
for k = 1 : nv,

    %
    % Select the category of expression to compute
    %

    vk = vu( k );
    if nv == 1,
        xt = x;
    else
        t = v == vk;
        xt = cvx_subsref( x, t );
    end

    %
    % Perform the computations
    %

    switch vk,
        case 0,
            % Invalid
            error( 'Disciplined convex programming error:\n    Illegal operation: abs( {%s} ).', cvx_class( xt ) );
        case 1,
            % Constant
            cvx_optval = cvx( builtin( 'abs', cvx_constant( xt ) ) );
        case 2,
            % Real affine
            w = [];
            st = size( xt );
            cvx_begin
                epigraph variable w( st )
                { xt, w } == lorentz( st, 0 ); %#ok
            cvx_end
        case 3,
            % Complex affine
            w = [];
            st = size( xt );
            cvx_begin
                epigraph variable w( st )
                { xt, w } == complex_lorentz( st, 0 ); %#ok
            cvx_end
        case 4,
            % log-affine, log-convex
            cvx_optval = xt;
        otherwise,
            error( 'Shouldn''t be here.' );
    end

    %
    % Store the results
    %

    if nv == 1,
        y = cvx_optval;
    else
        y = cvx_subsasgn( y, t, cvx_optval );
    end

end

% Copyright 2005-2016 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function [outputVar1, outputVar2] = cs_mri2scs(MRI, mriCoord)
% CS_MRI2SCS: Compute the transform to move from the MRI coordinate system (in mm) to the SCS
%
% USAGE:            [transfSCS] = cs_mri2scs(MRI);
%         [scsCoord, transfSCS] = cs_mri2scs(MRI, mriCoord);
%
% DEPRECATED: Replace with cs_convert()

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

disp('BST> WARNING: Deprecated function cs_mri2scs(), use cs_convert() instead.');

if (nargin == 1)
    outputVar1 = cs_compute(MRI, 'scs');
    outputVar2 = [];
else
    outputVar1 = cs_convert(MRI, 'mri', 'scs', mriCoord' ./ 1000)' .* 1000;
    outputVar2 = MRI.SCS;
end


function marginal = marginal_nodes(engine, nodes, t, add_ev)
% MARGINAL_NODES Compute the marginal on the specified query nodes (hmm)
% marginal = marginal_nodes(engine, nodes, t, add_ev)
%
% 'nodes' must be a single node.
% t is the time slice.

if nargin < 3, t = 1; end
if nargin < 4, add_ev = 0; end

assert(length(nodes)==1)
ss = engine.slice_size;

i = nodes(1);
bigT = engine.one_slice_marginal(:,t);
dom = i + (t-1)*ss;

ns = engine.eff_node_sizes(:);
bigdom = 1:ss;
marginal.T = marg_table(bigT, bigdom + (t-1)*ss, ns(bigdom), dom, engine.maximize);

marginal.domain = dom;
marginal.mu = [];
marginal.Sigma = [];

if add_ev
  marginal = add_ev_to_dmarginal(marginal, engine.evidence, engine.node_sizes);
end


function [g1, g2, g3] = sdlfmXsdlfmKernGradientBlockILJ(lfmKern1, lfmKern2, ...
    t1, t2, i, j, generalConst, generalConstGrad, covGrad, g1Mean, ...
    g2Mean, gsp1Mean, gsp2Mean, typeMeanParam, typeMeanSwitching, ...
    typeKernParam1, typeKernParam2, typeKernSwitching1, typeKernSwitching2)

% SDLFMXSDLFMKERNGRADIENTBLOCKILJ
% FORMAT
% DESC computes the gradients of the parameters for system 1 and system 2
% when i is lower than j.
% ARG lfmKern1 : structure containing parameters for the system 1
% ARG lfmKern2 : structure containing parameters for the system 2
% ARG t1 : times at which the system 1 is evaluated
% ARG t2 : times at which the system 2 is evaluated
% ARG i : interval to be evaluated for system 1
% ARG j : interval to be evaluated for system 2
% ARG generalConstant : constants evaluated with sdlfmKernComputeConstant.m
% ARG generalConstGrad : derivatives of the constants computed with
% sdlfmKernGradientConstant.m
% ARG covGrad : partial derivatives of the objective function wrt portion
% of the corresponding kernel matrix
% ARG g1Mean : gradients of the parameter of the system 1 obtained from the
% part of the function that uses the funcitons accommpanying the initial
% conditions.
% ARG g2Mean : gradients of the parameter of the system 2 obtained from the
% part of the function that uses the funcitons accommpanying the initial
% conditions.
% ARG gsp1Mean : gradient of the switching point of the system 1 obtained
% from the part of the function that uses the funcitons accommpanying the
% initial conditions.
% ARG gsp2Mean : gradient of the switching point of the system 2 obtained
% from the part of the function that uses the funcitons accommpanying the
% initial conditions.
% ARG typeMeanParam : specify the mean functions used to compute this part
% of the kernel
% ARG typeMeanSwitching : specify the functions used to compute the
% gradients of the swicthing points in part thst uses mean functions
% ARG typeKernParam1 : specify the first kernel function used to compute
% this part of the kernel
% ARG typeKernParam2 : specify the second kernel function used to compute
% this part of the kernel
% ARG typeKernSwitching1 : specify the functions used to compute the
% gradients of the swicthing points in both sides of the kernel function 1
% ARG typeKernSwitching2 : specify the functions used to compute the
% gradients of the swicthing points in both sides of the kernel function 2
% RETURN g1 : gradients of parameters for the system 1
% RETURN g2 : gradients of parameters for the system 2
% RETURN g3 : gradients of switching points
%
% COPYRIGHT : Mauricio A. Alvarez, 2010.

% KERN

if nargin < 14
    typeMeanParam = 'sdlfm';
    typeMeanSwitching = 'sdlfmv';
    typeKernParam1 = 'lfmXlfm';
    typeKernParam2 = 'lfmvXlfm';
    typeKernSwitching1= {'lfmvXlfm', 'lfmvXlfm'};
    typeKernSwitching2 ={'lfmvXlfmv', 'lfmaXlfm'};
end

g3 = [];

fhandleMeanParam = str2func([typeMeanParam 'MeanCompute']);
fhandleMeanGradParam = str2func([typeMeanParam 'MeanGradient']);
fhandleMeanGradSwitching = str2func([typeMeanSwitching 'MeanCompute']);
fhandleKernPosPos = str2func([typeKernParam1 'KernCompute']);
fhandleKernGradPosPos = str2func([typeKernParam1 'KernGradient']);
fhandleKernGradSwitchingPosPos1 = str2func([typeKernSwitching1{1} 'KernCompute']);
fhandleKernGradSwitchingPosPos2 = str2func([typeKernSwitching1{2} 'KernCompute']);
fhandleKernVelPos = str2func([typeKernParam2 'KernCompute']);
fhandleKernGradVelPos = str2func([typeKernParam2 'KernGradient']);
fhandleKernGradSwitchingVelPos1 = str2func([typeKernSwitching2{1} 'KernCompute']);
fhandleKernGradSwitchingVelPos2 = str2func([typeKernSwitching2{2} 'KernCompute']);

c2 = fhandleMeanParam(lfmKern2(1), t2, 'Pos');
e2 = fhandleMeanParam(lfmKern2(1), t2, 'Vel');

if isempty(generalConst{i,j})
    coeffPosPos = c2;
    coeffPosVel = e2;
else
    coeffPosPos = generalConst{i,j}(1,1)*c2 + generalConst{i,j}(2,1)*e2;
    coeffPosVel = generalConst{i,j}(1,2)*c2 + generalConst{i,j}(2,2)*e2;
end
g1Kern = zeros(length(lfmKern1), 5);
g2Kern = zeros(length(lfmKern1), 5);
PosPos = zeros(length(t1),1);
PosVel = zeros(length(t1),1);
for k=1:length(lfmKern1)
    PosPos = PosPos + fhandleKernPosPos(lfmKern1(k), lfmKern2(k), t1,...
        lfmKern1(k).limit);
    [g1KLocal, g2KLocal] = fhandleKernGradPosPos(lfmKern1(k), lfmKern2(k), ...
        t1, lfmKern1(k).limit, covGrad, coeffPosPos.');
    g1Kern(k,:) = g1Kern(k, :) + g1KLocal;
    g2Kern(k,:) = g2Kern(k, :) + g2KLocal;
    PosVel = PosVel + fhandleKernVelPos(lfmKern2(k), lfmKern1(k), ...
        lfmKern1(k).limit, t1).';
    [g2KLocal, g1KLocal] = fhandleKernGradVelPos(lfmKern2(k), lfmKern1(k), ...
        lfmKern1(k).limit, t1, covGrad, coeffPosVel);
    g1Kern(k,:) = g1Kern(k, :) + g1KLocal;
    g2Kern(k,:) = g2Kern(k, :) + g2KLocal;
end
[gcAlpha, gcOmega] = fhandleMeanGradParam(lfmKern2(1), t2, 'Pos');
[geAlpha, geOmega] = fhandleMeanGradParam(lfmKern2(1), t2, 'Vel');
[gradAlpha, gradOmega] = getLocalGradAlphaOmega(lfmKern2);
g2Pos = fhandleMeanGradSwitching(lfmKern2(1), t2, 'Pos');
h2Vel = fhandleMeanGradSwitching(lfmKern2(1), t2, 'Vel');
gsp1Kern = zeros(1, length(lfmKern1));
gsp2Kern = zeros(1, length(lfmKern1));
% This means that are only two switching points involved, t1
% and t0 appear in k, like k_{ff}(t1-t0,t'-t0) and
% k_{mf}(t1-t0,t'-t0). The other points appear in c1(t - t1)
% and e1(t - t1)
for k=1:length(lfmKern1)
    temp = fhandleKernGradSwitchingPosPos1(lfmKern1(k), lfmKern2(k), t1, lfmKern1(k).limit);
    gsp1Kern(k) = gsp1Kern(k) - sum(sum((temp*coeffPosPos.').*covGrad));
    temp = fhandleKernGradSwitchingPosPos2(lfmKern2(k), lfmKern1(k), lfmKern1(k).limit, t1).';
    gsp1Kern(k) = gsp1Kern(k) - sum(sum((temp*coeffPosPos.').*covGrad));
    gsp2Kern(k) = gsp2Kern(k) + sum(sum((temp*coeffPosPos.').*covGrad));
    temp = fhandleKernGradSwitchingVelPos1(lfmKern1(k), lfmKern2(k), t1, lfmKern1(k).limit);
    gsp1Kern(k) = gsp1Kern(k) - sum(sum((temp*coeffPosVel.').*covGrad));
    temp = fhandleKernGradSwitchingVelPos2(lfmKern2(k), lfmKern1(k), lfmKern1(k).limit, t1).';
    gsp1Kern(k) = gsp1Kern(k) - sum(sum((temp*coeffPosVel.').*covGrad));
    gsp2Kern(k) = gsp2Kern(k) + sum(sum((temp*coeffPosVel.').*covGrad));
end
if isempty(generalConst{i,j})
    matGradAlpha = PosPos*gcAlpha.' + PosVel*geAlpha.';
    matGradOmega = PosPos*gcOmega.' + PosVel*geOmega.';
    gCoeff = gradAlpha*sum(sum(matGradAlpha.*covGrad)) + ...
        gradOmega*(sum(sum(matGradOmega.*covGrad)));
    matGradSp2 = PosPos*g2Pos.' + PosVel*h2Vel.';
    gsp2 = - sum(sum(matGradSp2.*covGrad));
    g3(i) = gsp1Mean + sum(gsp1Kern);                % switching points 1
    g3(j) = gsp2Mean + sum(gsp2Kern) + gsp2;         % switching points 2
else
    constGradAlpha = generalConstGrad{1}{i,j};
    constGradOmega = generalConstGrad{2}{i,j};
    constVal = generalConst{i,j};
    % Derivative wrt parameters
    matGradAlpha = PosPos*((constVal(1,1)*gcAlpha.' + constGradAlpha(1,1)*c2.') ...
        + constVal(2,1)*geAlpha.' + constGradAlpha(2,1)*e2.') ...
        + PosVel*((constVal(1,2)*gcAlpha.' + constGradAlpha(1,2)*c2.') ...
        + constVal(2,2)*geAlpha.' + constGradAlpha(2,2)*e2.');

    matGradOmega = PosPos*((constVal(1,1)*gcOmega.' + constGradOmega(1,1)*c2.') ...
        + constVal(2,1)*geOmega.' + constGradOmega(2,1)*e2.') ...
        + PosVel*((constVal(1,2)*gcOmega.' + constGradOmega(1,2)*c2.') ...
        + constVal(2,2)*geOmega.' + constGradOmega(2,2)*e2.');

    gCoeff = gradAlpha*sum(sum(matGradAlpha.*covGrad)) + ...
        gradOmega*(sum(sum(matGradOmega.*covGrad)));
    % Derivative wrt switching points
    % Firts, notice that gsp2Kern doesn't correspond to the switching point
    % of the interval j (or say 2). It's just the derivative of the inner
    % switching point that lead to the actual switching point for the
    % interval j. So we rename it first.
    gspInt = sum(gsp2Kern);
    % Compute the derivative of the swicthing point j, not appearing in the
    % constant
    matGradSp2 = PosPos*(constVal(1,1)*g2Pos.' + constVal(2,1)*h2Vel.') + ...
        PosVel*(constVal(1,2)*g2Pos.' + constVal(2,2)*h2Vel.');
    gsp2 = - sum(sum(matGradSp2.*covGrad));
    % Compute the derivatives for all the switching points apearing in the
    % constant
    constGradSPoint = generalConstGrad{3}{i,j};
    numberSP = size(constGradSPoint,2);
    gspInBetween = zeros(1, numberSP);
    for k=1:numberSP
        temp = PosPos*(constGradSPoint(1,k)*c2.' + constGradSPoint(3,k)*e2.') + ...
            PosVel*(constGradSPoint(2,k)*c2.' + constGradSPoint(4,k)*e2.');
        gspInBetween(k) = sum(sum(temp.*covGrad));
    end
    % Assign derivatives wrt all other switching points, with a correction
    % for the derivative of the innermost switching point in the constant
    gspInBetween(end) =  gspInBetween(end) + gspInt;
    g3(i) = gsp1Mean + sum(gsp1Kern);           % switching point 1
    g3(j) = gsp2Mean + gsp2 + gspInBetween(1);  % switching point 2
    g3(i+1:j-1) = fliplr(gspInBetween(2:end));
end
% Assign derivatives wrt first system
g1{1} = g1Mean + sum(g1Kern(:,1:3), 1);          % mass 1, spring 1, damper 1
g1{2} = g1Kern(:,4).';                            % inverse widths
g1{3} = g1Kern(:,5).';                            % sensitivities 1
% Assign derivatives wrt second system
g2{1} = g2Mean + sum(g2Kern(:,1:3), 1) + gCoeff; % mass 2, spring 2, damper 2
g2{2} = g2Kern(:,4).';                            % inverse widths
g2{3} = g2Kern(:,5).';                            % sensitivities 2


report_this_filefun(mfilename('fullpath'));

%l = isnan(tmap);
%tmap(l) = 1;

%l = tmap < 150;
%tmap(l) = 150;

[lat,lon] = meshgrat(tmap,tmapleg);
%[smap,smapleg] = country2mtx('switzerland',100);
%[lat0, lon0] = meshgrat(smap,smapleg);

% tmap = km2deg(tmap/1);
[X , Y]  = meshgrid(gx,gy);

%sw = interp2(lon0,lat0,smap,lon,lat);

%  re4 = re3;

l = re4 < -6.9;
re4(l) = -6.9;
l = re4 > 6.9;
re4(l) = 6.9;

ren = interp2(X,Y,re4,lon,lat);

mi = min(min(ren));
l =  isnan(ren);
ren(l) = mi-20;

figure_w_normalized_uicontrolunits('pos',[150 500 1000 700])

hold on; axis off
axesm('MapProjection','eqaconic','MapParallels',[],...
    'MapLatLimit',[33.0 36.2],'MapLonLimit',[-118.1 -115.3])

meshm(ren,tmapleg,size(tmap),tmap);

daspectm('m',5);
tightmap
%view([10 30])
hl = camlight ; lighting phong
set(gca,'projection','perspective');

aa = a;

cd /alaskah2/stefan/ZMAP/agu99
load hec.mat

for i = 1:length(a)
    dep = interp2(lon,lat,tmap,a(i,1),a(i,2));

    pl =plot3m(a(i,2),a(i,1),dep+55,'ok');
    hold on
    fac = 64/max(a.Depth);

    facm = 6/max(a.Magnitude);
    sm = a(i,6)* facm;
    if sm < 1; sm = 1; end

    co = ceil(a(i,7)*fac)+1; if co > 63; co = 63; end
    set(pl,'Markersize',sm,'markerfacecolor','w');
end

load land.mat

for i = 1:length(a)
    dep = interp2(lon,lat,tmap,a(i,1),a(i,2));

    pl =plot3m(a(i,2),a(i,1),dep+55,'sk');
    ;
    hold on
    fac = 64/max(a.Depth);

    facm = 6/max(a.Magnitude);
    sm = a(i,6)* facm;
    if sm < 1; sm = 1; end

    co = ceil(a(i,7)*fac)+1; if co > 63; co = 63; end
    set(pl,'Markersize',sm,'markerfacecolor','w');
end
load bb.mat

for i = 1:length(a)
    dep = interp2(lon,lat,tmap,a(i,1),a(i,2));

    pl =plot3m(a(i,2),a(i,1),dep+55,'sk');

    hold on
    fac = 64/max(a.Depth);

    facm = 6/max(a.Magnitude);
    sm = a(i,6)* facm;
    if sm < 1; sm = 1; end

    co = ceil(a(i,7)*fac)+1; if co > 63; co = 63; end
    set(pl,'Markersize',sm,'markerfacecolor','w');
end

for i = 1:length(maepi(:,3))
    pl =plotm(maepi(i,2),maepi(i,1),'hk');
    set(pl,'Markersize',14,'markerfacecolor','w');
end

plotm(faults(:,2), faults(:,1),'k','Linewidth',1.0);

zdatam(handlem('allline'),10000) % keep line on surface
j = jet;
j = j(64:-1:1,:);
j = [ [ 0.85 0.9 0.9] ; j];
caxis([ min(min(re4)) max(max(re4)) ]);

colormap(j); brighten(0.1);
caxis([-7.2 7.2]);
axis off; set(gcf,'color','k')

setm(gca,'ffacecolor','k')
setm(gca,'fedgecolor','w','flinewidth',3);

setm(gca,'mlabellocation',1)
setm(gca,'meridianlabel','on')
setm(gca,'plabellocation',1)
setm(gca,'parallellabel','on')
setm(gca,'Fontcolor','w','Fontweight','bold','FontSize',12,'Labelunits','dm')

h5 = colorbar;
set(h5,'position',[0.67 0.15 0.01 0.2],'TickDir','out','Ycolor','w','Xcolor','w',...
    'Fontweight','bold','FontSize',12);
set(gcf,'Inverthardcopy','off');

a = aa;


function Script_CLNF_cross_data_general()

addpath(genpath('../'));

% Replace this with the location of the Menpo dataset
[images, detections, labels] = Collect_menpo_imgs('G:\Datasets\menpo/');

%% loading the patch experts

[ patches, pdm, clmParams ] = Load_CLNF_general();
views = [0,0,0; 0,-30,0; 0,30,0; 0,-55,0; 0,55,0; 0,0,30; 0,0,-30; 0,-90,0; 0,90,0; 0,-70,40; 0,70,-40];
views = views * pi/180;

[ patches_51, pdm_51, clmParams_51, inds_full, inds_inner ] = Load_CLNF_inner();

shapes_all = zeros(size(labels,2),size(labels,3), size(labels,1));
labels_all = zeros(size(labels,2),size(labels,3), size(labels,1));
lhoods = zeros(numel(images),1);

% for recording purposes
experiment.params = clmParams;

num_points = numel(pdm.M)/3;

shapes_all = cell(numel(images), 1);
labels_all = cell(numel(images), 1);
lhoods = zeros(numel(images),1);
all_lmark_lhoods = zeros(num_points, numel(images));
all_views_used = zeros(numel(images),1);

verbose = false; % set to true to visualise the fitting

tic
for i=1:numel(images)

    image = imread(images(i).img);
    image_orig = image;

    if(size(image,3) == 3)
        image = rgb2gray(image);
    end

    bbox = detections(i,:);

    [shape,~,~,lhood,lmark_lhood,view_used] = Fitting_from_bb_multi_hyp(image, [], bbox, pdm, patches, clmParams, views);

    % Perform inner landmark fitting now
    [shape, shape_inner] = Fitting_from_bb_hierarch(image, pdm, pdm_51, patches_51, clmParams_51, shape, inds_full, inds_inner);

    all_lmark_lhoods(:,i) = lmark_lhood;
    all_views_used(i) = view_used;

    shapes_all{i} = shape;
    labels_all{i} = labels{i};

    if(mod(i, 200)==0)
        fprintf('%d done\n', i );
    end

    lhoods(i) = lhood;

    if(verbose)
        v_points = logical(patches(1).visibilities(view_used,:))';
        DrawFaceOnFig(image_orig, shape, bbox, v_points);
    end

end
toc

experiment.lhoods = lhoods;
experiment.shapes = shapes_all;
experiment.labels = labels_all;
experiment.all_lmark_lhoods = all_lmark_lhoods;
experiment.all_views_used = all_views_used;

%%
output_results = 'results/results_clnf_cross-data_general.mat';
save(output_results, 'experiment');

end


function gainS = computeGainS(n,w)
    gainS = w*eye(n);
end


function [f,L,Ls,W,dim,permutedsize,order]=assert_sigreshape_pre(f,L,dim,callfun)
%ASSERT_SIGRESHAPE_PRE  Preprocess and handle dimension input.
%
%   Input parameters:
%      f            : signal, possibly ND-array
%      L            : L parameter
%      dim          : dim parameter
%      callfun      : Name of calling function
%   Output parameters:
%      f            : Input signal as matrix
%      L            : Verified L
%      Ls           : Length of signal along dimension to be processed
%      W            : Number of transforms to do.
%      dim          : Verified dim
%      permutedsize : pass to assert_sigreshape_post
%      order        : pass to assert_sigreshape_post

if ~isnumeric(f)
  error('%s: The input must be numeric.',callfun);
end;

D=ndims(f);

% Dummy assignment.
order=1;

if isempty(dim)
  dim=1;

  if sum(size(f)>1)==1
    % We have a vector, find the dimension where it lives.
    dim=find(size(f)>1);
  end;

else
  if (numel(dim)~=1 || ~isnumeric(dim))
    error('%s: dim must be a scalar.',callfun);
  end;
  if rem(dim,1)~=0
    error('%s: dim must be an integer.',callfun);
  end;
  if (dim<1) || (dim>D)
    error('%s: dim must be in the range from 1 to %d.',callfun,D);
  end;

end;

if (numel(L)>1 || ~isnumeric(L))
  error('%s: L must be a scalar.',callfun);
end;
if (~isempty(L) && rem(L,1)~=0)
  error('%s: L must be an integer.',callfun);
end;

if dim>1
  order=[dim, 1:dim-1,dim+1:D];

  % Put the desired dimension first.
  f=permute(f,order);

end;

Ls=size(f,1);

% If L is empty it is set to be the length of the transform.
if isempty(L)
  L=Ls;
end;

% Remember the exact size for later and modify it for the new length
permutedsize=size(f);
permutedsize(1)=L;

% Reshape f to a matrix.
if ~isempty(f)
  f=reshape(f,size(f,1),numel(f)/size(f,1));
end;
W=size(f,2);


function [isih] = ft_spike_isi(cfg, spike)

% FT_SPIKE_ISI computes the interspike interval histogram
%
% The input SPIKE should be organised as
% a) the spike datatype, obtained from FT_SPIKE_MAKETRIALS
% b) the raw datatype, containing binary spike trains, obtained from
% FT_APPENDSPIKE or FT_CHECKDATA. In this case the raw datatype is
% converted to the spike datatype.
%
% Use as
%   [isih] = ft_spike_isi(cfg, spike)
%
% Configurations:
%   cfg.outputunit       = 'spikecount' (default) or 'proportion' (sum of all bins = 1).
%   cfg.spikechannel     = string or index of spike channels to
%                          trigger on (default = 'all')
%                          See FT_CHANNELSELECTION for details.
%   cfg.trials           = numeric selection of trials (default = 'all')
%   cfg.bins             = ascending vector of isi bin edges.
%   cfg.latency          = [begin end] in seconds, 'max' (default), 'min', 'prestim'(t<=0), or
%                          'poststim' (t>=0).
%                          If 'max', we use all available latencies.
%                          If 'min', we use only the time window contained by all trials.
%                          If 'prestim' or 'poststim', we use time to or
%                          from 0, respectively.
%`  cfg.keeptrials       = 'yes' or 'no'. If 'yes', we keep the individual
%                           isis between spikes and output as isih.isi
%   cfg.param            = string, one of
%      'gamfit'      : returns [shape scale] for gamma distribution fit
%      'coeffvar'    : coefficient of variation (sd / mean)
%      'lv'          : Shinomoto's Local Variation measure (2009)
%
% Outputs:
%   isih.avg             = nUnits-by-nBins interspike interval histogram
%   isih.time            = 1 x nBins bincenters corresponding to isih.avg
%   isih.isi             = 1-by-nUnits cell with interval to previous spike per spike.
%                          For example isih.isi{1}(2) = 0.1 means that the
%                          second spike fired was 0.1 s later than the
%                          first. Note that jumps within trials or first
%                          spikes within trials are given NaNs.
%   isih.label           = 1-by-nUnits cell-array with labels

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

% these are used by the ft_preamble/ft_postamble function and scripts
ft_revision = '$Id$';
ft_nargin   = nargin;
ft_nargout  = nargout;

% do the general setup of the function
ft_defaults
ft_preamble init
ft_preamble provenance spike

% check if data is of proper format
spike = ft_checkdata(spike,'datatype', 'spike', 'feedback', 'yes');

% get the default options
cfg.outputunit   = ft_getopt(cfg,'outputunit','spikecount');
cfg.spikechannel = ft_getopt(cfg,'spikechannel', 'all');
cfg.trials       = ft_getopt(cfg,'trials', 'all');
cfg.latency      = ft_getopt(cfg,'latency','maxperiod');
cfg.keeptrials   = ft_getopt(cfg,'keeptrials', 'yes');
cfg.bins         = ft_getopt(cfg,'bins', 0:0.002:1);
cfg.param        = ft_getopt(cfg,'param', 'coeffvar');

% ensure that the options are valid
cfg = ft_checkopt(cfg,'outputunit','char', {'spikecount', 'proportion'});
cfg = ft_checkopt(cfg,'bins', 'ascendingdoublevector');
cfg = ft_checkopt(cfg,'spikechannel',{'cell', 'char', 'double'});
cfg = ft_checkopt(cfg,'latency', {'char', 'ascendingdoublebivector'});
cfg = ft_checkopt(cfg,'trials', {'char', 'doublevector', 'logical'});
cfg = ft_checkopt(cfg,'keeptrials', 'char', {'yes', 'no'});
cfg = ft_checkopt(cfg,'param', 'char', {'gamfit', 'coeffvar', 'lv'});

cfg = ft_checkconfig(cfg, 'allowed', {'param', 'outputunit', 'bins', 'spikechannel', 'latency', 'trials', 'keeptrials'});

% get the number of trials or change DATA according to cfg.trials
if  strcmp(cfg.trials,'all')
  cfg.trials = 1:size(spike.trialtime,1);
elseif islogical(cfg.trials) || all(cfg.trials==0 | cfg.trials==1)
  cfg.trials = find(cfg.trials);
end
cfg.trials = sort(cfg.trials);

cfg.channel = ft_channelselection(cfg.spikechannel, spike.label);
spikesel    = match_str(spike.label, cfg.channel);
nUnits      = length(spikesel); % number of spike channels
if nUnits==0, error('No spikechannel selected by means of cfg.spikechannel'); end

% determine the duration of each trial
begTrialLatency = spike.trialtime(cfg.trials,1);
endTrialLatency = spike.trialtime(cfg.trials,2);

% select the latencies
if strcmp(cfg.latency,'minperiod')
  cfg.latency = [max(begTriallatency) min(endTriallatency)];
elseif strcmp(cfg.latency,'maxperiod')
  cfg.latency = [min(begTrialLatency) max(endTrialLatency)];
elseif strcmp(cfg.latency,'prestim')
  cfg.latency = [min(begTrialLatency) 0];
elseif strcmp(cfg.latency,'poststim')
  cfg.latency = [0 max(endTrialLatency)];
end

% construct the isi bins
bins  = cfg.bins;
nBins = length(bins)-1;

% compute the interspike interval
keepTrials = strcmp(cfg.keeptrials,'yes');
if keepTrials, isiSpike = cell(1,nUnits); end  % contains the individual histogram spike times
isihist  = zeros(nUnits,nBins+1); % isi histogram
out = [];
for iUnit = 1:nUnits
  unitIndx = spikesel(iUnit);

  % only select the spikes in the right latencies and trials
  spikeTrials    = spike.trial{unitIndx}(:)'; % ensure row vector
  spikeTimes     = spike.time{unitIndx}(:)'; % ensure row vector

  % select only the spikes in the window and with the selected trials
  spikesInTrials = ismember(spikeTrials, cfg.trials); % row vec
  spikesInWin    = spikeTimes>=cfg.latency(1)&spikeTimes<=cfg.latency(2); % row vec
  spikeTimes     = spikeTimes(spikesInTrials & spikesInWin);
  spikeTrials    = spikeTrials(spikesInTrials & spikesInWin);

  % find the spikes that jumped to the next trial, replace them with NaNs
  trialJump = logical([1 diff(spikeTrials(:)')]);
  isi = [NaN diff(spikeTimes(:)')];
  isi(trialJump) = NaN;

  switch cfg.param
  case 'coeffvar'
    out(iUnit) = nanstd(isi)./nanmean(isi);
  case 'gamfit'
    data = isi(~isnan(isi));  % remove the nans from isiSpike
    if ~isempty(data)
      [out(iUnit,:)] = mle(data,'distribution', 'gamma'); % fit a gamma distribution
    else
      out(iUnit,:)   = [NaN NaN];
    end
  case 'lv'
    dIsi     = isi(1:end-1) - isi(2:end);
    sumIsi   = isi(1:end-1) + isi(2:end);
    sl       = ~isnan(dIsi) & ~isnan(sumIsi); % remove if one has nan
    df       = sum(sl) - 1;
    out(iUnit) = (3/df)*sum((dIsi(sl)./sumIsi(sl)).^2);
  end

  % convert and store the isi
  if keepTrials, isiSpike{iUnit} = isi; end
  isihist(iUnit,:)   = histc(isi,bins);
end

isihist(:,end) = []; % the last number is only an equality to a bin edge
if strcmp(cfg.outputunit,'proportion')
  isihist = isihist./repmat(nansum(isihist,2),1,size(isihist,2));
end

% gather the rest of the results
if strcmp(cfg.keeptrials,'yes'), isih.isi  = isiSpike; end
isih.time        = bins(1:end-1);
isih.avg         = isihist;
isih.dimord      = 'chan_time';
isih.label       = spike.label(spikesel);
param = cfg.param;
isih.(param) = out;

% do the general cleanup and bookkeeping at the end of the function

ft_postamble previous   spike
ft_postamble provenance isih
ft_postamble history    isih


%% planRRT
%%  - basic coverage algorithm
%%
%% Last Modified - 11/15/2010 - R. Beard

function path=planCover(wpp_start, map)

    % desired down position is down position of start node
    pd = wpp_start(3);

    % specify start node from wpp_start
    start_node = [wpp_start(1), wpp_start(2), pd, 0, 0, 0];
    % format is [N, E, D, chi, cost, parent]

    % return map
    returnMapSize = 30;  % this is a critical parameter!
    return_map = 50*ones(returnMapSize,returnMapSize)+ rand(returnMapSize,returnMapSize);
    plotReturnMap(return_map), %pause

    % construct search path by doing N search cycles
    SEARCH_CYCLES = 50;  % number of search cycles

    % look ahead tree parameters
    L = 50;  % segment Length
    vartheta = pi/4; % search angle
    depth = 5; % depth of look ahead tree

    % initialize path and tree
    path = start_node;
    for i=1:SEARCH_CYCLES,
        tree = extendTree(path(end,:),L,vartheta,depth,map,return_map,pd);
        next_path = findMaxReturnPath(tree);
        path = [path; next_path(1,:)];
        % update the return map
        return_map = updateReturnMap(next_path(1,:),return_map,map);
        plotReturnMap(return_map), %pause
        % set the end of the path as the root of the tree
    end

    % remove path segments where there is no turn
    path_=path;
    path = path(1,:);
    for i=2:size(path_,1),
        if path_(i,4)~=path_(i-1,4);
            path = [path; path_(i,:)];
        end
    end

    % specify that these are straight-line paths.
    for i=1:size(path,1),
        path(i,4)=-9999;
    end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% extendTree
%%   extend tree by randomly selecting point and growing tree toward that
%%   point
function tree = extendTree(start_node,L,vartheta,depth,map,return_map,pd)

  tree_ = [start_node, 0];  % the last variable marks node as expanded

  % extend tree initially
  for d = 1:depth,
      newnodes = [];
      for j=1:size(tree_,1),
          if tree_(j,7)~=1, % process unexpanded nodes
              for i=1:3,
                  if     i==1, theta = tree_(j,4)-vartheta;
                  elseif i==2, theta = tree_(j,4);
                  elseif i==3, theta = tree_(j,4)+vartheta;
                  end
                  newnode_ = [...
                      tree_(j,1)+L*cos(theta),...
                      tree_(j,2)+L*sin(theta),...
                      tree_(j,3),...
                      theta,...
                      0,...
                      j,...
                      0,...
                      ];
                  if collision(tree_(j,:), newnode_, map)==0,
                      newnode_(5) = tree_(j,5)...
                          +findReturn(newnode_(1),newnode_(2),return_map,map);
                      newnodes = [newnodes; newnode_];
                  end
              end
              tree_(j,7)=1; % mark as expanded
          end
      end
      tree_ = [tree_; newnodes];
  end
  tree = tree_(:,1:6);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% collision
%%   check to see if a node is in collsion with obstacles
function collision_flag = collision(start_node, end_node, map)
    collision_flag = 0;
    sigma = 0:.1:1; % define where collisions will be checked
    for i=1:length(sigma),
        X = (1-sigma(i))*start_node(1) + sigma(i)*end_node(1);
        Y = (1-sigma(i))*start_node(2) + sigma(i)*end_node(2);
        Z = (1-sigma(i))*start_node(3) + sigma(i)*end_node(3);
        if Z >= downAtNE(map, X, Y),
            collision_flag = 1;
        end
        % check to see if outside of world
        if (X>map.width) | (X<0) | (Y>map.width) | (Y<0),
            collision_flag = 1;
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% downAtNE
%%   find the map down coordinate at a specified (n,e) location
function down = downAtNE(map, n, e)

      [d_n,idx_n] = min(abs(n - map.buildings_n));
      [d_e,idx_e] = min(abs(e - map.buildings_e));

      if (d_n<=map.BuildingWidth) & (d_e<=map.BuildingWidth),
          down = -map.heights(idx_e,idx_n);
      else
          down = 0;
      end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% findReturn
%%   compute the return value at a particular location
function return_value = findReturn(pn,pe,return_map,map);

  [pn_max,pe_max] = size(return_map);
  fn = pn_max*pn/map.width;
  fn = min(pn_max,round(fn));
  fn = max(1,fn);
  fe = pe_max*pe/map.width;
  fe = min(pe_max,round(fe));
  fe = max(1,fe);
  return_value = return_map(fn,fe);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% findMaxReturnPath
%%   find the maximum return path in the tree
function path = findMaxReturnPath(tree)

     % find node with max return
    [tmp,idx] = max(tree(:,5));

    % construct path with maximum return
    path = tree(idx,:);
    parent_node = tree(idx,6);
    %while parent_node>1,
    while parent_node>1,
        path = [tree(parent_node,:); path];
        parent_node = tree(parent_node,6);
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% updateReturnMap
%%   update the return map to indicate where MAV has been
function new_return_map = updateReturnMap(path,return_map,map)

  new_return_map = return_map;
  for i=1:size(path,1),
    pn = path(i,1);
    pe = path(i,2);
    [pn_max,pe_max] = size(return_map);
    fn = pn_max*pn/map.width;
    fn = min(pn_max,round(fn));
    fn = max(1,fn);
    fe = pe_max*pe/map.width;
    fe = min(pe_max,round(fe));
    fe = max(1,fe);

    new_return_map(fn,fe) = return_map(fn,fe) - 50;
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% plotReturnMap
%%   plot the return map
function plotReturnMap(return_map)

  figure(2), clf
  mesh(return_map)
end


%kvmindis 'Minimum Distance Classifier (K1)'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros vmindis.pane file
%
% Parameters:
% InputFile: i1 'Input Image ', required: 'input image to be classified'
% InputFile: i2 'Input Center/Class Image', required: 'input center/class image'
% Integer: b 'Border Width ', default: 0: ' specifies the border width in pixels (default = 0)'
% OutputFile: o 'Output Classified Image ', required: 'output specifying which vector belongs to which cluster'
%
% Example: o = kvmindis({i1, i2}, {'i1','';'i2','';'b',0;'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% vmindis - Minimum Distance Classifier  (K1)
%
%  DESCRIPTION
% .I vmindis
% is a simple minimum distance classifier. The distance metric used
% to the Euclidean distance. This routine accepts two images as the
% input. The image that corresponds to the -i1 argument is the image
% that needs to be classified. This image can be have as many data
% bands as necessary. The number of data bands depicts the dimensionality
% of the vectors. Each pixel in the image is a vector with dimensionality
% of the number of data bands.
%
% The other input image which corresponds to the -i2 argument is
% the prototype image. The last data band of this image is the
% class data band. This image must contain the same number of data
% bands as the other input image plus an extra data band that represents
% the class mapping. This
% image would most likely have been created by vkmeans or some other
% routine that will give cluster centers. This image contains vectors that
% correspond to the prototype of each class.
%
% As stated above the center image's last data band is a class data band. The
% class data band simply maps each vector in the center image to the final class.
%
% At this point most class images must be created manually.
% A class image can be created by using pseudo color in editimage
% on the resulting clustered image from the
% vkmeans routine. Vcustom can then be used to create the class image. Finally
% kinset can be used to add the class image data to the center image. Normally
% one would over cluster using vkmeans then reduce the space down. So vkmeans
% might produce 100 clusters but, really only 3 clusters are desired. Pseudo
% color in editimage and kasc2val can be used to reduce the space down and
% create a class image. The class data might map cluster center vectors 1-50
% to class 1, vectors 51-60 to class 2 and vectors 61-100 to class 3.
% When the vmindis routine is run, the result would be a classified image of
% three classes.
%
% The border option (-b) allows the user to specify a border width,
% in pixels, encompassing the image. The border region is skipped
% by vmindis when classification is performed.
% This useful if neighborhood operators have been used
% previously and have not updated edge pixels.
%
% All input images must be of data storage type FLOAT.
%
%
%
%  EXAMPLES
% vmindis -i1 aerial_image.xv -i2 vkmeans_centers -b 5 -o test
%
% aerial_image.xv is a 5 band image; thus, each vector has dimensionality of 5,
% vkmeans_centers image is a 6 band image, 5 bands are the cluster center values
% produced by vkmeans and 1 class band.
% The border that vmindis will ignore is 5 pixels wide. the output image will be
% a single band image called test.
%
%  "SEE ALSO"
%
%  RESTRICTIONS
% All input images must be of data storage type FLOAT.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kvmindis(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,..] = kvmindis(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i1', '__input';'i2', '__input';'b', 0;'o', '__output'};
maxval={0,0,100,0};
minval={0,0,0,0};
istoggle=[0,0,1,0];
was_set=istoggle * 0;
paramtype={'InputFile','InputFile','Integer','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 'vmindis"  '],Inputs,narglist);


function varargout = abs(varargin)
%ABS Absolute value of a DISKFUN.
%   ABS(F) returns the absolute value of a DISKFUN. This function does not work
%   if the function passes through or becomes numerically close to zero.

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

[varargout{1:nargout}] = abs@separableApprox(varargin{:});

end


function p3 = mpower(p1,p2)
%PREAL/MPOWER Overloaded mpower (^) operator for class preal.
% Note: preal/mpower is the same as preal/power.

global useUnitsFlag

if ~(useUnitsFlag) % If physunits is disabled...
    p3=mpower(double(p1),double(p2)); % ... treat as double.
    return
end

p1=preal(p1);
p2=preal(p2);
tol=0.001;
if isscalar(p1)
    p1=preal(p1.value*ones(size(p2)),p1.units);
elseif isscalar(p2)
    p2=preal(p2.value*ones(size(p1)),p2.units);
elseif ndims(p1)==ndims(p2)&size(p1)==size(p2)
    % do nothing
else
    error('Array dimensions must agree')
end
p3=preal(ones(size(p1)));
for k=1:numel(p1)
    if any(abs(p2(k).units)>tol)
        error('Exponent must be non-dimensional (pure) number')
    end
    p3(k).value=p1(k).value^p2(k).value;
    p3(k).units=p1(k).units*p2(k).value;
end


% 0.05 700

% 0.1 1200

% 0.2 2200

%0.02

totalNum = 447026;

loopCompress(0.1, '/home/yinhuan/compression_exps/park/weightVector.txt', '/home/yinhuan/compression_exps/park/visMatrix/', 50, totalNum, 350, '/home/yinhuan/compression_exps/park/gurobi_compress_0.02/');

ratio = salientNumCnt( '/home/yinhuan/compression_exps/park/gurobi_compress_0.02/', totalNum ) / totalNum


classdef KeplerianElementSetVariable < AbstractOrbitModelVariable
    %KeplerianElementSetVariable Summary of this class goes here
    %   Detailed explanation goes here

    properties
        varObj(1,1) KeplerianElementSet = KeplerianElementSet.getDefaultElements();

        lb(1,6) double = 0;
        ub(1,6) double = 0;

        varSma(1,1) logical = false;
        varEcc(1,1) logical = false;
        varInc(1,1) logical = false;
        varRaan(1,1) logical = false;
        varArg(1,1) logical = false;
        varTru(1,1) logical = false;
    end

    methods
        function obj = KeplerianElementSetVariable(varObj)
            obj.varObj = varObj;
            obj.varObj.optVar = obj;

            obj.id = rand();
        end

        function x = getXsForVariable(obj)
            x = [];

            if(obj.varSma)
                x(end+1) = obj.varObj.sma;
            end

            if(obj.varEcc)
                x(end+1) = obj.varObj.ecc;
            end

            if(obj.varInc)
                x(end+1) = obj.varObj.inc;
            end

            if(obj.varRaan)
                x(end+1) = obj.varObj.raan;
            end

            if(obj.varArg)
                x(end+1) = obj.varObj.arg;
            end

            if(obj.varTru)
                x(end+1) = obj.varObj.tru;
            end
        end

        function [lb, ub] = getBndsForVariable(obj)
            useTf = obj.getUseTfForVariable();

            lb = obj.lb(useTf);
            ub = obj.ub(useTf);
        end

        function [lb, ub] = getAllBndsForVariable(obj)
            lb = obj.lb;
            ub = obj.lb;
        end

        function setBndsForVariable(obj, lb, ub)
            if(length(lb) == 6 && length(ub) == 6)
                obj.lb = lb;
                obj.ub = ub;
            else
                useTf = obj.getUseTfForVariable();

                obj.lb(useTf) = lb;
                obj.ub(useTf) = ub;
            end
        end

        function useTf = getUseTfForVariable(obj)
            useTf = [obj.varSma        obj.varEcc        obj.varInc        obj.varRaan        obj.varArg        obj.varTru];
        end

        function setUseTfForVariable(obj, useTf)
            obj.varSma  = useTf(1);
            obj.varEcc = useTf(2);
            obj.varInc  = useTf(3);
            obj.varRaan = useTf(4);
            obj.varArg  = useTf(5);
            obj.varTru = useTf(6);
        end

        function updateObjWithVarValue(obj, x)
            xInd = 1;

            if(obj.varSma)
                obj.varObj.sma = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varEcc)
                obj.varObj.ecc = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varInc)
                obj.varObj.inc = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varRaan)
                obj.varObj.raan = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varArg)
                obj.varObj.arg = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varTru)
                obj.varObj.tru = x(xInd);
                xInd = xInd + 1; %#ok<NASGU>
            end
        end

        function nameStrs = getStrNamesOfVars(obj, evtNum, varLocType)
            if(evtNum > 0)
                subStr = sprintf('Event %i',evtNum);
            else
                subStr = varLocType;
            end

            nameStrs = {sprintf('%s SMA', subStr), ...
                        sprintf('%s Eccentricity', subStr), ...
                        sprintf('%s Inclination', subStr), ...
                        sprintf('%s RAAN', subStr), ...
                        sprintf('%s Argument of Periapsis', subStr), ...
                        sprintf('%s True Anomaly', subStr)};

            nameStrs = nameStrs(obj.getUseTfForVariable());
        end

        function varsStoredInRad = getVarsStoredInRad(obj)
            varsStoredInRad = [false false true true true true];
        end
    end
end


function [stepsize, newx, newkey, lsstats] = ...
  linesearch_adaptive(problem, x, d, f0, df0, options, storedb, key)
% Adaptive line search algorithm (step size selection) for descent methods.
%
% function [stepsize, newx, newkey, lsstats] =
%        linesearch_adaptive(problem, x, d, f0, df0, options, storedb, key)
%
% Adaptive linesearch algorithm for descent methods, based on a simple
% backtracking method. Contrary to linesearch.m, this function is not
% invariant under rescaling of the search direction d. These two line
% search methods vary mainly in their strategy to pick the initial step
% size.
%
% Below, the step is constructed as alpha*d, and the step size is the norm
% of that vector, thus: stepsize = alpha*norm_d. The step is executed by
% retracting the vector alpha*d from the current point x, giving newx.
%
% This line-search may create and maintain a structure called lsmem inside
% storedb.internal. This gives the linesearch the opportunity to remember
% what happened in the previous calls. This is typically used to make a
% first guess at the step size, based on previous events.
%
% Inputs/Outputs : see help for linesearch
%
% See also: steepestdescent conjugategradients linesearch

% This file is part of Manopt: www.manopt.org.
% Original author: Bamdev Mishra, Dec. 30, 2012.
% Contributors: Nicolas Boumal
% Change log:
%
%   Sept. 13, 2013 (NB) :
%       The automatic direction reversal feature was removed (it triggered
%       when df0 > 0). Direction reversal is a decision that needs to be
%       made by the solver, so it can know about it.
%
%	Nov. 7, 2013 (NB) :
%       The whole function has been recoded to mimick more closely the new
%       version of linesearch.m. The parameters are available through the
%       options structure passed to the solver and have the same names and
%       same meaning as for the base linesearch. The information is logged
%       more reliably.
%
%   April 3, 2015 (NB):
%       Works with the new StoreDB class system.
%
%   April 8, 2015 (NB):
%       Got rid of lsmem input/output: now maintained in storedb.internal.

    % Allow omission of the key, and even of storedb.
    if ~exist('key', 'var')
        if ~exist('storedb', 'var')
            storedb = StoreDB();
        end
        key = storedb.getNewKey();
    end

    % Backtracking default parameters. These can be overwritten in the
    % options structure which is passed to the solver.
    default_options.ls_contraction_factor = .5;
    default_options.ls_suff_decr = .5;
    default_options.ls_max_steps = 10;
    default_options.ls_initial_stepsize = 1;

    if ~exist('options', 'var') || isempty(options)
        options = struct();
    end
    options = mergeOptions(default_options, options);

    contraction_factor = options.ls_contraction_factor;
    suff_decr = options.ls_suff_decr;
    max_ls_steps = options.ls_max_steps;
    initial_stepsize = options.ls_initial_stepsize;

    % Compute the norm of the search direction.
    norm_d = problem.M.norm(x, d);

    % If this is not the first iteration, then lsmem should have been
    % filled with a suggestion for the initial step.
    if isfield(storedb.internal, 'lsmem')
        lsmem = storedb.internal.lsmem;
        if isfield(lsmem, 'init_alpha')
            % Pick initial step size based on where we were last time,
            alpha = lsmem.init_alpha;
        end
    % Otherwise, fall back to a user supplied suggestion.
    else
        alpha = initial_stepsize / norm_d;
    end

    % Make the chosen step and compute the cost there.
    newx = problem.M.retr(x, d, alpha);
    newkey = storedb.getNewKey();
    newf = getCost(problem, newx, storedb, newkey);
    cost_evaluations = 1;

    % Backtrack while the Armijo criterion is not satisfied
    while newf > f0 + suff_decr*alpha*df0

        % Reduce the step size,
        alpha = contraction_factor * alpha;

        % and look closer down the line
        newx = problem.M.retr(x, d, alpha);
        newkey = storedb.getNewKey();
        newf = getCost(problem, newx, storedb, newkey);
        cost_evaluations = cost_evaluations + 1;

        % Make sure we don't run out of budget
        if cost_evaluations >= max_ls_steps
            break;
        end

    end

    % If we got here without obtaining a decrease, we reject the step.
    if newf > f0
        alpha = 0;
        newx = x;
        newkey = key;
        newf = f0; %#ok<NASGU>
    end

    % As seen outside this function, stepsize is the size of the vector we
    % retract to make the step from x to newx. Since the step is alpha*d:
    stepsize = alpha * norm_d;

    % Fill lsmem with a suggestion for what the next initial step size
    % trial should be. On average we intend to do only one extra cost
    % evaluation. Notice how the suggestion is not about stepsize but about
    % alpha. This is the reason why this line search is not invariant under
    % rescaling of the search direction d.
    switch cost_evaluations
        case 1
            % If things go very well, push your luck.
            init_alpha = 2 * alpha;
        case 2
            % If things go reasonably well, try to keep pace.
            init_alpha = alpha;
        otherwise
            % If we backtracked a lot, the new stepsize is probably quite
            % small: try to recover.
            init_alpha = 2 * alpha;
    end
    storedb.internal.lsmem.init_alpha = init_alpha;

    % Return some statistics also, for possible analysis.
    lsstats.costevals = cost_evaluations;
    lsstats.stepsize = stepsize;
    lsstats.alpha = alpha;

end


function [F,G] = snopt_callback(x,mmodel)

persistent model
if nargin > 1
    model = mmodel;
    return
end

if model.SimpleLinearObjective | model.SimpleQuadraticObjective
    [f,df] = fmincon_fun_liftlayer(x,model);
    [g,geq,dg,dgeq] = fmincon_con_liftlayer(x,model);
else
    [f,df,xevaled] = fmincon_fun_liftlayer(x,model);
    [g,geq,dg,dgeq] = fmincon_con_liftlayer(x,model,xevaled);
end

F = [f;g;geq];
n = length(x);
m = length(g);
p = length(geq);
G = [reshape(df,1,n);dg';dgeq'];
if ~isempty(model.A)
    F = [F;model.A*x - model.b];
    G = [G;model.A];
end
if ~isempty(model.Aeq)
    F = [F;model.Aeq*x - model.beq];
    G = [G;model.Aeq];
end
G = full(G(model.sparsityElements));


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%	Implemetation of the tracker described in paper
%	"MEEM: Robust Tracking via Multiple Experts using Entropy Minimization",
%   Jianming Zhang, Shugao Ma, Stan Sclaroff, ECCV, 2014
%
%	Copyright (C) 2014 Jianming Zhang
%
%	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 you have problems about this software, please contact: jmzhang@bu.edu
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function expertsDo(I_vf,lambda,sigma)
global sampler;
global svm_tracker;
global experts;
global config

roi_reg = sampler.roi; roi_reg(3:4) = sampler.roi(3:4)-sampler.roi(1:2);

feature_map = imresize(I_vf,config.ratio,'nearest'); %
ratio_x = size(I_vf,2)/size(feature_map,2);
ratio_y = size(I_vf,1)/size(feature_map,1);
% tmp_mask = zeros(sampler.template_size(1:2));
% tmp_mask(1:2:end,1:2:end) = 1;
% tmp_mask = repmat(tmp_mask,[1,1,size(I_vf,3)]);
patterns = im2colstep(feature_map,[sampler.template_size(1:2), size(I_vf,3)],[1, 1, size(I_vf,3)]);
% patterns = patterns(tmp_mask(:)>0,:); % columnwise

x_sz = size(feature_map,2)-sampler.template_size(2)+1;
y_sz = size(feature_map,1)-sampler.template_size(1)+1;
[X Y] = meshgrid(1:x_sz,1:y_sz);
temp = repmat(svm_tracker.output,[numel(X),1]);
temp(:,1) = (X(:)-1)*ratio_x + sampler.roi(1);
temp(:,2) = (Y(:)-1)*ratio_y + sampler.roi(2);
state = temp;

%% select expert

label_prior = fspecial('gaussian',[y_sz,x_sz],sigma);
label_prior_neg = ones(size(label_prior))/numel(label_prior);

% compute log likelihood and entropy
n = numel(experts);
score_temp = zeros(n,1);
rect_temp = zeros(n,4);

if config.debug
    loglik_vec=[];
    ent_vec=[];
    figure(3)
end

kernel_size = sampler.template_size(1:2)*0.5;%half template size;
rad = 0.5*min(sampler.template_size(1:2));

mask_temp = zeros(y_sz,x_sz);
idx_temp = [];
svm_scores = [];
svm_score = {};
svm_density = {};
peaks_collection = {};
peaks = zeros(n,2);
peaks_pool = [];

[X Y] = meshgrid(1:round(rad):x_sz,1:round(rad):y_sz);

for i = 1:n
    % find the highest peak
    svm_score{i} = -(experts{i}.w*patterns+experts{i}.Bias);
    svm_density{i} = normcdf(svm_score{i},0,1).*label_prior(:)';
    [val idx] = max(svm_density{i});
    best_rect = state(idx,:);
    rect_temp(i,:) = best_rect;
    svm_scores(i) = svm_score{i}(idx);
    idx_temp(i) = idx;
    [r c] = ind2sub(size(mask_temp),idx);
    peaks(i,:) = [r c];

    % find the possible peaks

    density_map = reshape(svm_density{i},y_sz,[]);
    density_map = (density_map - min(density_map(:)))/(max(density_map(:)) - min(density_map(:)));
    mm = (imdilate(density_map,strel('square',round(rad))) == density_map) & density_map > 0.9;
    [rn cn] = ind2sub(size(mask_temp),find(mm));
    peaks_pool = cat(1,peaks_pool,[rn cn]);
    peaks_collection{i} = [rn cn];
%     mask_temp(r,c) = 1;
end
peaks_orig = peaks;
% merg peaks
peaks = mergePeaks(peaks,rad);
peaks_pool = mergePeaks(peaks_pool,rad);
mask_temp(sub2ind(size(mask_temp),round(peaks(:,1)),round(peaks(:,2)))) = 1;

%%
for i = 1:n

    dis = pdist2(peaks_pool,peaks_collection{i});
    [rr cc] = ind2sub([size(peaks_pool,1),size(peaks_collection{i},1)],find(dis < rad));
    [C,ia,ic] = unique(cc);
    peaks_temp = peaks_pool;
    peaks_temp(rr(ia),:) = peaks_collection{i}(cc(ia),:);
    mask = zeros(size(mask_temp));
    mask(sub2ind(size(mask_temp),round(peaks_temp(:,1)),round(peaks_temp(:,2)))) = 1;
    mask = mask>0;

    [loglik ent] = getLogLikelihoodEntropy(svm_score{i}(mask(:)),label_prior(mask(:)),label_prior_neg(mask(:)));
    if config.debug
        loglik_vec(end+1) = loglik;
        ent_vec(end+1) = ent;
        subplot(2,4,i)
        imagesc(reshape(svm_score{i},y_sz,[]));
        colorbar
        subplot(2,4,i+4)
        imagesc(reshape(mask,y_sz,[]))
    end

    experts{i}.score(end+1) =  loglik - lambda*ent;
    score_temp(i) = sum(experts{i}.score(max(end+1-config.entropy_score_winsize,1):end));
end

%%
svm_tracker.best_expert_idx = numel(score_temp);
if numel(score_temp) >= 2 && config.use_experts
    [val idx] = max(score_temp(1:end-1));
    if score_temp(idx) > score_temp(end) && size(peaks,1) > 1%svm_scores(idx) > config.svm_thresh
        % recover previous version
%         output = svm_tracker.output;
%         experts{end}.snapshot = svm_tracker;
        experts{end}.score = experts{idx}.score;
        svm_tracker = experts{idx}.snapshot;
%         svm_tracker.output = rect_temp(idx,:);
        svm_tracker.best_expert_idx = idx;
%         experts([idx end]) = experts([end idx]);
    end
end
svm_tracker.output = rect_temp(svm_tracker.best_expert_idx,:);
svm_tracker.confidence = svm_scores(svm_tracker.best_expert_idx);
svm_tracker.output_exp = rect_temp(end,:);
svm_tracker.confidence_exp = svm_scores(end);

% svm_tracker.w = experts{svm_tracker.best_expert_idx}.w;
% svm_tracker.Bias = experts{svm_tracker.best_expert_idx}.Bias;

if config.debug

    for i = 1:n
        subplot(2,4,i)
        if i == svm_tracker.best_expert_idx
            color = [1 0 0];
        else
            color = [1 1 1];
        end
        text(0,1,num2str(experts{i}.score(end)),'BackgroundColor',color);
        text(15,1,num2str(score_temp(i)),'BackgroundColor',color);
        text(0,3,num2str(loglik_vec(i)),'BackgroundColor',color);
        text(15,3,num2str(ent_vec(i)),'BackgroundColor',color);
    end
    figure(2)
    imagesc(mask_temp)
    figure(1)
end

%% update training sample
% approximately 200 training samples
step = round(sqrt((y_sz*x_sz)/120));
mask_temp = zeros(y_sz,x_sz);
mask_temp(1:step:end,1:step:end) = 1;
mask_temp = mask_temp > 0;
sampler.patterns_dt = patterns(:,mask_temp(:))';
sampler.state_dt = state(mask_temp(:),:);
sampler.costs = 1 - getIOU(sampler.state_dt,svm_tracker.output);
if min(sampler.costs)~=0
    sampler.state_dt = [sampler.state_dt; rect_temp(svm_tracker.best_expert_idx,:)];
    sampler.patterns_dt = [sampler.patterns_dt; patterns(:,idx_temp(svm_tracker.best_expert_idx))'];
    sampler.costs = [sampler.costs;0];
end

% better localization and add the predicted state and pattern
% output = svm_tracker.output;
% output(1:2) = output(1:2) - sampler.roi(1:2) + 1;
% [shift pattern_loc] = localize(I_vf,...
%     -reshape(svm_tracker.w,config.template_sz(1),config.template_sz(2),[]),...
%     output,5);
% svm_tracker.output(1:2) = svm_tracker.output(1:2) + shift;

end

function merged_peaks = mergePeaks(peaks, rad)

dis_mat = pdist2(peaks,peaks) + diag(inf*ones(size(peaks,1),1));
while min(dis_mat(:)) < rad && size(peaks,1) > 1
    [val idx] = min(dis_mat(:));
    [id1 id2] = ind2sub(size(dis_mat),idx);
    merged_peak = 0.5*(peaks(id1,:) + peaks(id2,:));
    peaks([id1 id2],:) = [];
    peaks = [peaks;merged_peak];
    dis_mat = pdist2(peaks,peaks) + diag(inf*ones(size(peaks,1),1));
end

merged_peaks = peaks;

end


%% clear the workspace and select data
clear; clc; close all;

%% choose data
neuron = Sources2D();
nam = get_fullname('./data_1p.tif');          % this demo data is very small, here we just use it as an example
nam = neuron.select_data(nam);  %if nam is [], then select data interactively

%% parameters
% -------------------------    COMPUTATION    -------------------------  %
pars_envs = struct('memory_size_to_use', 8, ...   % GB, memory space you allow to use in MATLAB
    'memory_size_per_patch', 0.6, ...   % GB, space for loading data within one patch
    'patch_dims', [64, 64]);  %GB, patch size

% -------------------------      SPATIAL      -------------------------  %
gSig = 3;           % pixel, gaussian width of a gaussian kernel for filtering the data. 0 means no filtering
gSiz = 13;          % pixel, neuron diameter
ssub = 1;           % spatial downsampling factor
with_dendrites = true;   % with dendrites or not
if with_dendrites
    % determine the search locations by dilating the current neuron shapes
    updateA_search_method = 'dilate';  %#ok<UNRCH>
    updateA_bSiz = 5;
    updateA_dist = neuron.options.dist;
else
    % determine the search locations by selecting a round area
    updateA_search_method = 'ellipse'; %#ok<UNRCH>
    updateA_dist = 5;
    updateA_bSiz = neuron.options.dist;
end
spatial_constraints = struct('connected', true, 'circular', false);  % you can include following constraints: 'circular'
spatial_algorithm = 'hals_thresh';

% -------------------------      TEMPORAL     -------------------------  %
Fs = 10;             % frame rate
tsub = 1;           % temporal downsampling factor
deconv_options = struct('type', 'ar1', ... % model of the calcium traces. {'ar1', 'ar2'}
    'method', 'foopsi', ... % method for running deconvolution {'foopsi', 'constrained', 'thresholded'}
    'smin', -5, ...         % minimum spike size. When the value is negative, the actual threshold is abs(smin)*noise level
    'optimize_pars', true, ...  % optimize AR coefficients
    'optimize_b', true, ...% optimize the baseline);
    'max_tau', 100);    % maximum decay time (unit: frame);

nk = 3;             % detrending the slow fluctuation. usually 1 is fine (no detrending)
% when changed, try some integers smaller than total_frame/(Fs*30)
detrend_method = 'spline';  % compute the local minimum as an estimation of trend.

% -------------------------     BACKGROUND    -------------------------  %
bg_model = 'ring';  % model of the background {'ring', 'svd'(default), 'nmf'}
nb = 1;             % number of background sources for each patch (only be used in SVD and NMF model)
ring_radius = 18;  % when the ring model used, it is the radius of the ring used in the background model.
%otherwise, it's just the width of the overlapping area
num_neighbors = []; % number of neighbors for each neuron
bg_ssub = 2;        % downsample background for a faster speed

% -------------------------      MERGING      -------------------------  %
show_merge = false;  % if true, manually verify the merging step
merge_thr = 0.65;     % thresholds for merging neurons; [spatial overlap ratio, temporal correlation of calcium traces, spike correlation]
method_dist = 'max';   % method for computing neuron distances {'mean', 'max'}
dmin = 5;       % minimum distances between two neurons. it is used together with merge_thr
dmin_only = 2;  % merge neurons if their distances are smaller than dmin_only.
merge_thr_spatial = [0.8, 0.4, -inf];  % merge components with highly correlated spatial shapes (corr=0.8) and small temporal correlations (corr=0.1)

% -------------------------  INITIALIZATION   -------------------------  %
K = [];             % maximum number of neurons per patch. when K=[], take as many as possible.
min_corr = 0.8;     % minimum local correlation for a seeding pixel
min_pnr = 8;       % minimum peak-to-noise ratio for a seeding pixel
min_pixel = gSig^2;      % minimum number of nonzero pixels for each neuron
bd = 0;             % number of rows/columns to be ignored in the boundary (mainly for motion corrected data)
frame_range = [];   % when [], uses all frames
save_initialization = false;    % save the initialization procedure as a video.
use_parallel = true;    % use parallel computation for parallel computing
show_init = true;   % show initialization results
choose_params = true; % manually choose parameters
center_psf = true;  % set the value as true when the background fluctuation is large (usually 1p data)
% set the value as false when the background fluctuation is small (2p)

% -------------------------  Residual   -------------------------  %
min_corr_res = 0.7;
min_pnr_res = 6;
seed_method_res = 'auto';  % method for initializing neurons from the residual
update_sn = true;

% ----------------------  WITH MANUAL INTERVENTION  --------------------  %
with_manual_intervention = true;

% -------------------------  FINAL RESULTS   -------------------------  %
save_demixed = true;    % save the demixed file or not
kt = 3;                 % frame intervals

% -------------------------    UPDATE ALL    -------------------------  %
neuron.updateParams('gSig', gSig, ...       % -------- spatial --------
    'gSiz', gSiz, ...
    'ring_radius', ring_radius, ...
    'ssub', ssub, ...
    'search_method', updateA_search_method, ...
    'bSiz', updateA_bSiz, ...
    'dist', updateA_bSiz, ...
    'spatial_constraints', spatial_constraints, ...
    'spatial_algorithm', spatial_algorithm, ...
    'tsub', tsub, ...                       % -------- temporal --------
    'deconv_options', deconv_options, ...
    'nk', nk, ...
    'detrend_method', detrend_method, ...
    'background_model', bg_model, ...       % -------- background --------
    'nb', nb, ...
    'ring_radius', ring_radius, ...
    'num_neighbors', num_neighbors, ...
    'bg_ssub', bg_ssub, ...
    'merge_thr', merge_thr, ...             % -------- merging ---------
    'dmin', dmin, ...
    'method_dist', method_dist, ...
    'min_corr', min_corr, ...               % ----- initialization -----
    'min_pnr', min_pnr, ...
    'min_pixel', min_pixel, ...
    'bd', bd, ...
    'center_psf', center_psf);
neuron.Fs = Fs;

%% distribute data and be ready to run source extraction
neuron.getReady(pars_envs);

%% initialize neurons from the video data within a selected temporal range
if choose_params
    % change parameters for optimized initialization
    [gSig, gSiz, ring_radius, min_corr, min_pnr] = neuron.set_parameters();
end

[center, Cn, PNR] = neuron.initComponents_parallel(K, frame_range, save_initialization, use_parallel);
neuron.compactSpatial();
if show_init
    figure();
    ax_init= axes();
    imagesc(Cn, [0, 1]); colormap gray;
    hold on;
    plot(center(:, 2), center(:, 1), '.r', 'markersize', 10);
end

%% estimate the background components
neuron.update_background_parallel(use_parallel);

%% udpate spatial&temporal components, delete false positives and merge neurons
for m=1:2
    % update spatial
    neuron.update_spatial_parallel(use_parallel);

    % update temporal
    neuron.update_temporal_parallel(use_parallel);
end

%% post-process the results automatically
% delete bad neurons
neuron.remove_false_positives();

% merge neurons based on temporal correlation + distances
neuron.merge_neurons_dist_corr(show_merge);

% merge neurons with high correlations
neuron.merge_high_corr(show_merge, merge_thr_spatial);

%% pick neurons from the residual
[center_res, Cn_res, PNR_res] =neuron.initComponents_residual_parallel([],...
    save_initialization, use_parallel, min_corr_res, min_pnr_res, seed_method_res);
% if show_init
%     axes(ax_init);
%     plot(center_res(:, 2), center_res(:, 1), '.g', 'markersize', 10);
% end

% estimate the background components
neuron.update_background_parallel(use_parallel);

% udpate spatial&temporal components, delete false positives and merge neurons
for m=1:2
    % update spatial
    neuron.update_spatial_parallel(use_parallel);

    % update temporal
    neuron.update_temporal_parallel(use_parallel);
end
% delete bad neurons
neuron.remove_false_positives();

% merge neurons based on temporal correlation + distances
neuron.merge_neurons_dist_corr(show_merge);

% merge neurons with high correlations
neuron.merge_high_corr(show_merge, merge_thr_spatial);

%% add a manual intervention and run the whole procedure for a second time
if with_manual_intervention
    neuron.orderROIs('snr');

    % interactively merge neurons
    show_merge = true;
    neuron.merge_close_neighbors(true, dmin_only);

    % interactively delete neurons
    tags = neuron.tag_neurons_parallel();  % find neurons with fewer nonzero pixels than min_pixel and silent calcium transients
    ids = find(tags>0);
    if ~isempty(ids)
        neuron.viewNeurons(ids, neuron.C_raw);
    end

    % go through all neurons

    % update temporal
    neuron.update_temporal_parallel(use_parallel);

    % update spatial
    neuron.update_spatial_parallel(use_parallel);
end

%% save the workspace for future analysis
neuron.orderROIs('snr');
cnmfe_path = neuron.save_workspace();

%% show neuron contours
Coor = neuron.show_contours(0.6);

%% create a video for displaying the
amp_ac = 140;
range_ac = 5+[0, amp_ac];
multi_factor = 10;
range_Y = 1300+[0, amp_ac*multi_factor];

avi_filename = neuron.show_demixed_video(save_demixed, kt, [], amp_ac, ...
    range_ac, range_Y, multi_factor);

%% save neurons shapes
neuron.save_neurons();


function sVF = plus(sVF1, sVF2)
%
% Syntax
%   sVF = sVF1+sVF2
%   sVF = a+sVF1
%   sVF = sVF1+a
%

if isa(sVF1, 'vector3d')
  sVF = sVF2;
  sVF.x = sVF.x+sVF1.x;
  sVF.y = sVF.y+sVF1.y;
  sVF.z = sVF.z+sVF1.z;

elseif isa(sVF2, 'vector3d')
  sVF = sVF1;
  sVF.x = sVF.x+sVF2.x;
  sVF.y = sVF.y+sVF2.y;
  sVF.z = sVF.z+sVF2.z;

else
  sVF = sVF1;
  sVF.sF = sVF1.sF+sVF2.sF;

end

end


filename='CantileverBeam_Quadrilateral_Bilinear_Structured';
ptype = 'MACRO';
method = 'SIMPALL'; % !! Instead of proportional to material density !!
materialType = 'ISOTROPIC';
initial_case = 'holes';
cost = {'compliance','perimeter'};
weights = [1 0.1];
constraint = {'volumeConstraint'};
optimizer = 'HAMILTON-JACOBI';
incrementFactor = 1;
designVariable = 'LevelSet';
filterType = 'P1';
constraint_case = 'INEQUALITY';
line_search_initiator = 'INCREASING LAST STEP';

nsteps = 10;
Vfrac_final = 0.1;
Perimeter_target=3.5;
optimality_final =1e-3;
constr_final =1e-3;

Vfrac_initial = 0.4;
optimality_initial = 1e-3;
constr_initial = 1e-3;

TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;
TOL.nu_plus = 0.3;
TOL.nu_minus = 0.3;

plotting = 1;
printing = 0;
monitoring = 1;
monitoring_interval = 1;