classdef HarrisLaplaceFeatureDetector < handle
    %HARRISLAPLACEFEATUREDETECTOR  Class implementing the Harris-Laplace feature detector
    %
    % As described in [Mikolajczyk2004].
    %
    % ## References
    % [Mikolajczyk2004]:
    % > Krystian Mikolajczyk and Cordelia Schmid. "Scale & affine invariant
    % > interest point detectors". International journal of computer vision,
    % > 60(1):63-86, 2004.
    %
    % See also: cv.HarrisLaplaceFeatureDetector.HarrisLaplaceFeatureDetector,
    %  cv.FeatureDetector
    %

    properties (SetAccess = private)
        % Object ID
        id
    end

    methods
        function this = HarrisLaplaceFeatureDetector(varargin)
            %HARRISLAPLACEFEATUREDETECTOR  The full constructor
            %
            %     obj = cv.HarrisLaplaceFeatureDetector()
            %     obj = cv.HarrisLaplaceFeatureDetector('OptionName',optionValue, ...)
            %
            % ## Options
            % * __NumOctaves__ the number of octaves in the scale-space
            %   pyramid. default 6
            % * __CornThresh__ the threshold for the Harris cornerness
            %   measure. default 0.01
            % * __DOGThresh__ the threshold for the Difference-of-Gaussians
            %   scale selection. default 0.01
            % * __MaxCorners__ the maximum number of corners to consider.
            %   default 5000
            % * __NumLayers__ the number of intermediate scales per octave.
            %   default 4
            %
            % See also: cv.HarrisLaplaceFeatureDetector.detect
            %
            this.id = HarrisLaplaceFeatureDetector_(0, 'new', varargin{:});
        end

        function delete(this)
            %DELETE  Destructor
            %
            %     obj.delete()
            %
            % See also: cv.HarrisLaplaceFeatureDetector
            %
            if isempty(this.id), return; end
            HarrisLaplaceFeatureDetector_(this.id, 'delete');
        end

        function typename = typeid(this)
            %TYPEID  Name of the C++ type (RTTI)
            %
            %     typename = obj.typeid()
            %
            % ## Output
            % * __typename__ Name of C++ type
            %
            typename = HarrisLaplaceFeatureDetector_(this.id, 'typeid');
        end
    end

    %% Algorithm
    methods
        function clear(this)
            %CLEAR  Clears the algorithm state
            %
            %     obj.clear()
            %
            % See also: cv.HarrisLaplaceFeatureDetector.empty,
            %  cv.HarrisLaplaceFeatureDetector.load
            %
            HarrisLaplaceFeatureDetector_(this.id, 'clear');
        end

        function b = empty(this)
            %EMPTY  Checks if detector object is empty
            %
            %     b = obj.empty()
            %
            % ## Output
            % * __b__ Returns true if the detector object is empty (e.g in the
            %   very beginning or after unsuccessful read).
            %
            % See also: cv.HarrisLaplaceFeatureDetector.clear
            %
            b = HarrisLaplaceFeatureDetector_(this.id, 'empty');
        end

        function save(this, filename)
            %SAVE  Saves the algorithm parameters to a file
            %
            %     obj.save(filename)
            %
            % ## Input
            % * __filename__ Name of the file to save to.
            %
            % This method stores the algorithm parameters in the specified
            % XML or YAML file.
            %
            % See also: cv.HarrisLaplaceFeatureDetector.load
            %
            HarrisLaplaceFeatureDetector_(this.id, 'save', filename);
        end

        function load(this, fname_or_str, varargin)
            %LOAD  Loads algorithm from a file or a string
            %
            %     obj.load(fname)
            %     obj.load(str, 'FromString',true)
            %     obj.load(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __fname__ Name of the file to read.
            % * __str__ String containing the serialized model you want to
            %   load.
            %
            % ## Options
            % * __ObjName__ The optional name of the node to read (if empty,
            %   the first top-level node will be used). default empty
            % * __FromString__ Logical flag to indicate whether the input is a
            %   filename or a string containing the serialized model.
            %   default false
            %
            % This method reads algorithm parameters from the specified XML or
            % YAML file (either from disk or serialized string). The previous
            % algorithm state is discarded.
            %
            % See also: cv.HarrisLaplaceFeatureDetector.save
            %
            HarrisLaplaceFeatureDetector_(this.id, 'load', fname_or_str, varargin{:});
        end

        function name = getDefaultName(this)
            %GETDEFAULTNAME  Returns the algorithm string identifier
            %
            %     name = obj.getDefaultName()
            %
            % ## Output
            % * __name__ This string is used as top level XML/YML node tag
            %   when the object is saved to a file or string.
            %
            % See also: cv.HarrisLaplaceFeatureDetector.save,
            %  cv.HarrisLaplaceFeatureDetector.load
            %
            name = HarrisLaplaceFeatureDetector_(this.id, 'getDefaultName');
        end
    end

    %% Features2D: FeatureDetector
    methods
        function keypoints = detect(this, img, varargin)
            %DETECT  Detects keypoints in an image or image set
            %
            %     keypoints = obj.detect(img)
            %     keypoints = obj.detect(imgs)
            %     [...] = obj.detect(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __img__ Image (first variant), 8-bit grayscale image.
            % * __imgs__ Image set (second variant), cell array of images.
            %
            % ## Output
            % * __keypoints__ The detected keypoints. In the first variant, a
            %   1-by-N structure array. In the second variant of the method,
            %   `keypoints{i}` is a set of keypoints detected in `imgs{i}`.
            %
            % ## Options
            % * __Mask__ A mask specifying where to look for keypoints
            %   (optional). It must be a logical or 8-bit integer matrix with
            %   non-zero values in the region of interest. In the second
            %   variant, it is a cell-array of masks for each input image,
            %   `masks{i}` is a mask for `imgs{i}`. Not set by default.
            %
            % See also: cv.HarrisLaplaceFeatureDetector.HarrisLaplaceFeatureDetector
            %
            keypoints = HarrisLaplaceFeatureDetector_(this.id, 'detect', img, varargin{:});
        end
    end

end


% Map the numerical elements in the vector "v" onto the variables "s" which can
% be of any type. The number of numerical elements must match; on exit "v"
% should be empty. Non-numerical entries are just copied. See also unwrap.m.

function [s v] = rewrap(s, v)

if isnumeric(s)
  if numel(v) < numel(s)
    error('The vector for conversion contains too few elements')
  end
  s = reshape(v(1:numel(s)), size(s));            % numeric values are reshaped
  v = v(numel(s)+1:end);                        % remaining arguments passed on
elseif isstruct(s)
  [s p] = orderfields(s); p(p) = 1:numel(p);      % alphabetize, store ordering
  [t v] = rewrap(struct2cell(s), v);                 % convert to cell, recurse
  s = orderfields(cell2struct(t,fieldnames(s),1),p);  % conv to struct, reorder
elseif iscell(s)
  for i = 1:numel(s)             % cell array elements are handled sequentially
    [s{i} v] = rewrap(s{i}, v);
  end
end                                             % other types are not processed


function [OutputSurfaces, OutputMris] = bst_warp(destPts, srcPts, SurfaceFiles, MriFiles, OutputTag, OutputDir, isSurfaceOnly)
%BST_WARP:  Deform an anatomy (MRI+surfaces) to fit a set of landmarks.
%
% USAGE:  bst_warp(destPts, srcPts, SurfaceFiles, MriFiles, OutputTag, OutputDir, isSurfaceOnly=0)
%
% INPUTS:
%     - destPts      : landmarks in real head coordinates, i.e. from a Polhemus or
%     - srcPts       : landmarks in intial anatomy coordinates
%     - SurfaceFiles : Cell array of the surface files to be warped (full path)
%     - MriFiles     : Cell array of the MRI files to be warped (full path)
%     - OutputTag    : Tag to add at the end of the filenames of the wrapped files
%     - OutputDir    : Output directory
%     - isSurfaceOnly: If 1, do not warp the MRI

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

if (nargin < 7) || isempty(isSurfaceOnly)
    isSurfaceOnly = 0;
end
if ischar(MriFiles)
    MriFiles = {MriFiles};
end
OutputSurfaces = {};
OutputMris = {};

%% ===== COMPUTE WARP PARAMETER =====
% Compute warp transform parameters
[W,A] = warp_transform(srcPts, destPts);

%% ===== WARP SURFACES =====
% Progress bar
bst_progress('start', 'Warp anatomy', 'Warping surfaces...', 0, length(SurfaceFiles));
% Loop on all surface files
for i = 1:length(SurfaceFiles)
    bst_progress('inc', 1);
    % Read input
    sSurf = load(file_fullpath(SurfaceFiles{i}));
    % Warp surface
    switch file_gettype(SurfaceFiles{i})
        case 'fibers'
            nRows = size(sSurf.Points, 1);
            Points = permute(reshape(sSurf.Points, [], 1, 3), [1 3 2]);
            Points = warp_lm(Points, A, W, srcPts) + Points;
            Points = reshape(permute(Points, [1 3 2]), nRows, [], 3);
            sSurfNew.Points = Points;
            sSurfNew.Header = sSurf.Header;
            sSurfNew.Colors = sSurf.Colors;
            sSurfNew.Scouts = sSurf.Scouts;
        case 'fem'
            sSurfNew.Elements     = sSurf.Elements;
            sSurfNew.Tissue       = sSurf.Tissue;
            sSurfNew.TissueLabels = sSurf.TissueLabels;
            sSurfNew.Tensors      = sSurf.Tensors;
            sSurfNew.Vertices     = warp_lm(sSurf.Vertices, A, W, srcPts) + sSurf.Vertices;
        otherwise
            sSurfNew.Faces    = sSurf.Faces;
            sSurfNew.Vertices = warp_lm(sSurf.Vertices, A, W, srcPts) + sSurf.Vertices;
    end
    % Add tag to comment
    sSurfNew.Comment  = [sSurf.Comment ' warped'];
    % Copy previous field
    if isfield(sSurf, 'Atlas') && ~isempty(sSurf.Atlas)
        sSurfNew.Atlas = sSurf.Atlas;
    end
    if isfield(sSurf, 'Reg') && ~isempty(sSurf.Reg)
        sSurfNew.Reg = sSurf.Reg;
    end
    if isfield(sSurf, 'History') && ~isempty(sSurf.History)
        sSurfNew.History = sSurf.History;
    end
    % History: Warp
    sSurfNew = bst_history('add', sSurfNew, 'warp', 'Surface deformed to match the head points from channel file.');
    % Output filename
    [tmp__, fileBase, fileExt] = bst_fileparts(SurfaceFiles{i});
    OutputSurfaces{end+1} = bst_fullfile(OutputDir, [fileBase, OutputTag, fileExt]);
    % Save new file
    bst_save(OutputSurfaces{end}, sSurfNew, 'v7');
end

%% ====== COMPUTE TRANSFORMATION ========
bst_progress('start', 'Warp anatomy', 'Preparing MRI...');
% Load reference MRI (first in the list)
sMriSrc = in_mri_bst(MriFiles{1});
% Transform landmarks into MRI coordinates (meters)
srcPts_mr  = cs_convert(sMriSrc, 'scs', 'voxel', srcPts);
destPts_mr = cs_convert(sMriSrc, 'scs', 'voxel', destPts);
% Compute warp transform in MR coordinates
[Wmr,Amr] = warp_transform(srcPts_mr, destPts_mr);
% Compute "inverse" warp transform in MR coordinates
[Wmr_inv,Amr_inv] = warp_transform(destPts_mr, srcPts_mr);

%% ===== WRAP FIDUCIALS =====
% % SCS transformation
% destSCS.NAS = warp_lm(sMriSrc.SCS.NAS, Amr, Wmr, srcPts_mr) + sMriSrc.SCS.NAS;
% destSCS.LPA = warp_lm(sMriSrc.SCS.LPA, Amr, Wmr, srcPts_mr) + sMriSrc.SCS.LPA;
% destSCS.RPA = warp_lm(sMriSrc.SCS.RPA, Amr, Wmr, srcPts_mr) + sMriSrc.SCS.RPA;
% NCS transformation
if isfield(sMriSrc, 'NCS') && isfield(sMriSrc.NCS, 'AC') && ~isempty(sMriSrc.NCS.AC) && ~isempty(sMriSrc.NCS.PC) && ~isempty(sMriSrc.NCS.IH)
    destNCS.AC = warp_lm(sMriSrc.NCS.AC, Amr, Wmr, srcPts_mr) + sMriSrc.NCS.AC;
    destNCS.PC = warp_lm(sMriSrc.NCS.PC, Amr, Wmr, srcPts_mr) + sMriSrc.NCS.PC;
    destNCS.IH = warp_lm(sMriSrc.NCS.IH, Amr, Wmr, srcPts_mr) + sMriSrc.NCS.IH;
    destNCS.R = [];
    destNCS.T = [];
    destNCS.Origin = [];
else
    destNCS = [];
end

%% ===== WARP MRI =====
bst_progress('start', 'Warp anatomy', 'Warping MRI...', 0, 100*length(MriFiles));
for iMri = 1:length(MriFiles)
    bst_progress('text', sprintf('Warping MRI...   [%d/%d]', iMri, length(MriFiles)));
    % Load MRI (the first one is already loaded above)
    if (iMri >= 2)
        sMriSrc = in_mri_bst(MriFiles{iMri});
    end
    % If warping of the MRI volumes is enabled
    if ~isSurfaceOnly
        % Process coordinates by blocks: Doing all at once costs too much memory, doing only 1 at a time costs too much time
        sizeMri = size(sMriSrc.Cube);
        if (length(sizeMri) > 3)
            error('No support for 4D volumes. Ask on the Brainstorm for help.');
        end
        newCube = ones(sizeMri);
        nVoxels = numel(newCube);
        BLOCK_SIZE = 10000;
        nBlocks = ceil(nVoxels / BLOCK_SIZE);
        ix0 = 1;
        for i = 1:nBlocks
            % Increment progress bar
            if (mod(i, round(nBlocks/100)) == 0)
                bst_progress('inc', 1);
            end
            % Get indices in dest volume
            ix1 = min(ix0 - 1 + BLOCK_SIZE, nVoxels);
            [xv,yv,zv] = ind2sub(sizeMri, ix0:ix1);
            rv = [xv;yv;zv]';
            % Unwarp MRI coordinates
            rv_inv = warp_lm(rv, Amr_inv, Wmr_inv, destPts_mr) + rv;
            % Round coordinates (nearest neighor interpolation)
            rv_inv = round(rv_inv);
            % Remove values that are outside the volume
            iOutside = find(sum((rv_inv < 1) | (rv_inv > repmat(sizeMri,size(rv_inv,1),1)),2) > 0);
            rv_inv(iOutside,:) = 1;
            % Get indices from xyz coordinates
            ix_inv = sub2ind(sizeMri, rv_inv(:,1), rv_inv(:,2), rv_inv(:,3));
            % Get values in initial volume
            newCube(ix0:ix1) = sMriSrc.Cube(ix_inv);
            % Set values outside of the volume to zero
            newCube(iOutside) = 0;
            % Go to next block
            ix0 = ix1 + 1;
        end
        newComment = [sMriSrc.Comment, ' warped'];
    else
        newCube = sMriSrc.Cube;
        newComment = sMriSrc.Comment;
    end

    % === SAVE NEW MRI ===
    % Create new structure
    sMriDest = sMriSrc;
    sMriDest.Cube    = newCube;
    sMriDest.Comment = newComment;
    sMriDest.NCS     = destNCS;
    % History: Copy previous field
    if isfield(sMriSrc, 'History') && ~isempty(sMriSrc.History)
        sMriDest.History = sMriSrc.History;
    end
    % History: Warp
    sMriDest = bst_history('add', sMriDest, 'warp', 'MRI deformed to match the head points from channel file.');
    % Output filename
    [tmp__, fileBase, fileExt] = bst_fileparts(MriFiles{iMri});
    OutputMris{iMri} = bst_fullfile(OutputDir, [fileBase, OutputTag, fileExt]);
    % Save new MRI
    bst_save(OutputMris{iMri}, sMriDest, 'v7');
end

bst_progress('stop');

end

%% =====================================================================================
%  ===== HELPER FUNCTIONS ==============================================================
%  =====================================================================================

%% ===== WARP TRANSFORM =====
% Calculates nonlinear transformation coefficents (see Ermer's Thesis)
% INPUT:
%    - p : Landmarks in system 1
%    - q : Landmarks in system 2
% OUTPUT:
%    - e : Warp energy
function [W,A,e] = warp_transform(p, q)
    N = size(p,1);
    px = repmat(p(:,1), 1, N);
    py = repmat(p(:,2), 1, N);
    pz = repmat(p(:,3), 1, N);
    K = sqrt((px - px').^2 + (py - py').^2 + (pz - pz').^2);

    P = [p, ones(N,1)];
    L = [K P; P' zeros(4,4)];
    D = [q - p; zeros(4,3)];
    warning off
    H = L \ D;
    warning on
    if any(isnan(H))
        H = pinv(L) * D;
    end
    W = H(1:N,:);
    A = H(N+1:end, :);
    e = sum(diag(W' * K * W));
end

%% ===== WARP LANDMARKS: VECTORIZED =====
% Performs warp transformation with linear 3D RFB (see Ermer's Thesis)
function rw = warp_lm(r, A, W, p)
    rw = r * A(1:3,1:3);
    rw = bst_bsxfun(@plus, rw, A(4,:));
    np = size(p,1);
    U = sqrt(bst_bsxfun(@minus, repmat(r(:,1),1,np), p(:,1)') .^ 2 + ...
             bst_bsxfun(@minus, repmat(r(:,2),1,np), p(:,2)') .^ 2 + ...
             bst_bsxfun(@minus, repmat(r(:,3),1,np), p(:,3)') .^ 2);
    rw = rw + U * W;
end

%% ===== WARP LANDMARKS: LOOP VERSION =====
% This function is twice slower
% function rw = warp_lm(r, A, W, p)
%     rw = r * A(1:3,1:3) + repmat(A(4,:), size(r,1), 1);
%     for i = 1:size(p,1)
%         U = sqrt(sum((r - repmat(p(i,:), size(r,1), 1)) .^ 2, 2));
%         rw = rw + U * W(i,:);
%     end
% end


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

if ~exist('planC','var')
    global planC
end

indexS = planC{end};

CTUniformInfoS = planC{indexS.scan}(scanNum).uniformScanInfo;

scanData = planC{indexS.scan}(scanNum);
scanInfo = scanData.scanInfo(1);
clear scanData;

scanArraySup = planC{indexS.scan}(scanNum).scanArraySuperior;
scanArrayInf = planC{indexS.scan}(scanNum).scanArrayInferior;
uniformScanInfo = planC{indexS.scan}(scanNum).uniformScanInfo;
sliceNumSup  = uniformScanInfo.sliceNumSup;
sliceNumInf  = uniformScanInfo.sliceNumInf;

%creation options:
origOpts = planC{indexS.CERROptions};
% this code uses the superior and inferior matrices as well as the original CT scan to graph the CT image.
if isfield(origOpts,'uniformizedDataType')
    if strcmpi(planC{indexS.CERROptions}.uniformizedDataType,'uint8')
        CTMin = planC{indexS.scan}(scanNum).uniformScanInfo.minCTValue;
        CTMax = planC{indexS.scan}(scanNum).uniformScanInfo.maxCTValue;
        CTScale = 255 / (CTMax - CTMin);
    elseif strcmpi(planC{indexS.CERROptions}.uniformizedDataType,'uint16')
        CTMin = planC{indexS.scan}(scanNum).uniformScanInfo.minCTValue;
        CTMax = planC{indexS.scan}(scanNum).uniformScanInfo.maxCTValue;
        CTScale = 65535 / (CTMax - CTMin);
    end
else %scaling wasn't used to create the arrays.  This is here to retain backwards compatibility.
    CTScale = 1;
    CTMin = 0;
end

emptySup = isempty(scanArraySup);
emptyInf = isempty(scanArrayInf);

if exist('native') & native == 1
    if emptySup & emptyInf
        CTUniform3D = single(planC{indexS.scan}(scanNum).scanArray(:, :, sliceNumSup:sliceNumInf));
    elseif emptySup & ~emptyInf
        infM = single((double(scanArrayInf) / CTScale) + CTMin);
        CTUniform3D = cat(3, single(planC{indexS.scan}(scanNum).scanArray(:, :, sliceNumSup:sliceNumInf)),infM);
    elseif ~emptySup & emptyInf
        supM = single((double(scanArraySup) / CTScale) + CTMin);
        CTUniform3D = cat(3, supM, single(planC{indexS.scan}(scanNum).scanArray(:, :, sliceNumSup:sliceNumInf)));
    else % ~emptySup & ~emptyInf
        infM = single((double(scanArrayInf) / CTScale) + CTMin);
        supM = single((double(scanArraySup) / CTScale) + CTMin);
        CTUniform3D = cat(3, supM, single(planC{indexS.scan}(scanNum).scanArray(:, :, sliceNumSup:sliceNumInf)), ...
            infM);
    end
else
    if emptySup & emptyInf
        CTUniform3D = planC{indexS.scan}(scanNum).scanArray(:, :, sliceNumSup:sliceNumInf);
    elseif emptySup & ~emptyInf
        infM = ((double(scanArrayInf) / CTScale) + CTMin);
        CTUniform3D = cat(3, planC{indexS.scan}(scanNum).scanArray(:, :, sliceNumSup:sliceNumInf), uint16(infM));
    elseif ~emptySup & emptyInf
        supM = ((double(scanArraySup) / CTScale) + CTMin);
        CTUniform3D = cat(3, uint16(supM), planC{indexS.scan}(scanNum).scanArray(:, :, sliceNumSup:sliceNumInf));
    else % ~emptySup & ~emptyInf
        infM = (double(scanArrayInf) / CTScale) + CTMin;
        supM = (double(scanArraySup) / CTScale) + CTMin;
        clear scanArrayInf scanArraySup;
        CTUniform3D = cat(3, uint16(supM), planC{indexS.scan}(scanNum).scanArray(:, :, sliceNumSup:sliceNumInf), ...
            uint16(infM));
    end
end

CTUniformInfoS.size = size(CTUniform3D);


function y = quickselect(x, k)
% Brings the largest k entries to the front of array
    y = mex_quickselect(x, k);
end


%--- help for generic/evaluate_general_restrictions ---
%
%  Evaluate general restrictions
%
%  ::
%
%    g = evaluate_general_restrictions(obj)
%
%  Args:
%
%     obj (rise | dsge | rfvar | svar): scalar of vector or RISE model objects
%
%  Returns:
%     :
%
%     - **g** [cell array] : value of restrictions for each object.
%
%  Note:
%
%     - The restrictions will be processed as g(x)<=0. But all the user has to
%       do is to put zero where the restrictions are not violated!!!
%
%


classdef VARtype < uint8
    %VARTYPE enmieration class to define the differnt type of VAR problems
    %that can be solved in BEAR toolbox

    enumeration
        OLS   (1) % OLS VAR
        BVAR  (2) % Bayesian VAR
        PANEL (4) % Panel BVAR
        SV    (5) % Stochastic Volatility BVAR
        TVP   (6) % Time-Varying Parameter BVAR
        MFVAR (7) % Time-Varying Parameter BVAR
    end

end


classdef FEM < handle

    properties (Access = protected)
        inputReader
    end

    methods (Access = public)

        function obj = FEM()
            obj.inputReader = FemInputReader_GiD();
        end

    end

    methods (Static, Access = public)

        function obj = create(s)
            switch s.type
                case 'ELASTIC'
                    switch s.scale
                        case 'MACRO'
                            obj = ElasticProblem(s);
                        case 'MICRO'
                            obj = ElasticProblemMicro(s);
                    end
                case 'THERMAL'
                    obj = ThermalProblem(s);
                case 'DIFF-REACT'
                    obj = DiffReactProblem(s);
                case 'HYPERELASTIC'
                    obj = Hyperelastic_Problem(s);
                case 'Stokes'
                    obj = StokesProblem(s);
            end
        end

    end

end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%                                                                  %%%%%
%%%%    IEEE PES Power Grid Library - Optimal Power Flow - v21.07     %%%%%
%%%%          (https://github.com/power-grid-lib/pglib-opf)           %%%%%
%%%%             Benchmark Group - Active Power Increase              %%%%%
%%%%                         29 - July - 2021                         %%%%%
%%%%                                                                  %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function mpc = pglib_opf_case39_epri__api
mpc.version = '2';
mpc.baseMVA = 100.0;

%% bus data
%	bus_i	type	Pd	Qd	Gs	Bs	area	Vm	Va	baseKV	zone	Vmax	Vmin
mpc.bus = [
	1	 1	 160.91	 44.20	 0.0	 0.0	 2	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	2	 1	 0.0	 0.0	 0.0	 0.0	 2	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	3	 1	 530.88	 2.40	 0.0	 0.0	 2	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	4	 1	 824.35	 184.00	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	5	 1	 0.0	 0.0	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	6	 1	 0.0	 0.0	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	7	 1	 385.47	 84.00	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	8	 1	 860.62	 176.60	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	9	 1	 6.50	 -66.60	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	10	 1	 0.0	 0.0	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	11	 1	 0.0	 0.0	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	12	 1	 14.06	 88.00	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	13	 1	 0.0	 0.0	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	14	 1	 0.0	 0.0	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	15	 1	 527.58	 153.00	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	16	 1	 542.42	 32.30	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	17	 1	 0.0	 0.0	 0.0	 0.0	 2	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	18	 1	 260.49	 30.00	 0.0	 0.0	 2	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	19	 1	 0.0	 0.0	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	20	 1	 1121.12	 103.00	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	21	 1	 451.74	 115.00	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	22	 1	 0.0	 0.0	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	23	 1	 408.05	 84.60	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	24	 1	 308.60	 -92.20	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	25	 1	 369.31	 47.20	 0.0	 0.0	 2	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	26	 1	 229.17	 17.00	 0.0	 0.0	 2	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	27	 1	 463.28	 75.50	 0.0	 0.0	 2	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	28	 1	 339.63	 27.60	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	29	 1	 467.41	 26.90	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	30	 2	 0.0	 0.0	 0.0	 0.0	 2	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	31	 3	 15.17	 4.60	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	32	 2	 0.0	 0.0	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	33	 2	 0.0	 0.0	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	34	 2	 0.0	 0.0	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	35	 2	 0.0	 0.0	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	36	 2	 0.0	 0.0	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	37	 2	 0.0	 0.0	 0.0	 0.0	 2	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	38	 2	 0.0	 0.0	 0.0	 0.0	 3	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
	39	 2	 1820.16	 250.00	 0.0	 0.0	 1	    1.00000	    0.00000	 345.0	 1	    1.06000	    0.94000;
];

%% generator data
%	bus	Pg	Qg	Qmax	Qmin	Vg	mBase	status	Pmax	Pmin
mpc.gen = [
	30	 159.0	 59.0	 400.0	 -282.0	 1.0	 100.0	 1	 318	 0.0; % COW
	31	 789.0	 0.0	 854.4	 -854.4	 1.0	 100.0	 1	 1578	 0.0; % COW
	32	 1277.5	 0.0	 1278.0	 -1278.0	 1.0	 100.0	 1	 2555	 0.0; % COW
	33	 432.5	 0.0	 433.0	 -433.0	 1.0	 100.0	 1	 865	 0.0; % COW
	34	 438.5	 0.0	 439.0	 -439.0	 1.0	 100.0	 1	 877	 0.0; % COW
	35	 560.0	 0.0	 560.0	 -560.0	 1.0	 100.0	 1	 1120	 0.0; % COW
	36	 461.0	 0.0	 461.0	 -461.0	 1.0	 100.0	 1	 922	 0.0; % COW
	37	 759.0	 0.0	 759.0	 -759.0	 1.0	 100.0	 1	 1518	 0.0; % COW
	38	 594.5	 0.0	 595.0	 -595.0	 1.0	 100.0	 1	 1189	 0.0; % COW
	39	 1261.5	 0.0	 1262.0	 -1262.0	 1.0	 100.0	 1	 2523	 0.0; % COW
];

%% generator cost data
%	2	startup	shutdown	n	c(n-1)	...	c0
mpc.gencost = [
	2	 0.0	 0.0	 3	   0.000000	   6.724778	   0.000000; % COW
	2	 0.0	 0.0	 3	   0.000000	  14.707625	   0.000000; % COW
	2	 0.0	 0.0	 3	   0.000000	  24.804734	   0.000000; % COW
	2	 0.0	 0.0	 3	   0.000000	  34.844643	   0.000000; % COW
	2	 0.0	 0.0	 3	   0.000000	  24.652994	   0.000000; % COW
	2	 0.0	 0.0	 3	   0.000000	  32.306483	   0.000000; % COW
	2	 0.0	 0.0	 3	   0.000000	  18.157477	   0.000000; % COW
	2	 0.0	 0.0	 3	   0.000000	  31.550181	   0.000000; % COW
	2	 0.0	 0.0	 3	   0.000000	  22.503168	   0.000000; % COW
	2	 0.0	 0.0	 3	   0.000000	  27.434444	   0.000000; % COW
];

%% branch data
%	fbus	tbus	r	x	b	rateA	rateB	rateC	ratio	angle	status	angmin	angmax
mpc.branch = [
	1	 2	 0.0035	 0.0411	 0.6987	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	1	 39	 0.001	 0.025	 0.75	 1000.0	 1000.0	 1000.0	 0.0	 0.0	 1	 -30.0	 30.0;
	2	 3	 0.0013	 0.0151	 0.2572	 500.0	 500.0	 500.0	 0.0	 0.0	 1	 -30.0	 30.0;
	2	 25	 0.007	 0.0086	 0.146	 500.0	 500.0	 500.0	 0.0	 0.0	 1	 -30.0	 30.0;
	2	 30	 0.0	 0.0181	 0.0	 900.0	 900.0	 2500.0	 1.025	 0.0	 1	 -30.0	 30.0;
	3	 4	 0.0013	 0.0213	 0.2214	 500.0	 500.0	 500.0	 0.0	 0.0	 1	 -30.0	 30.0;
	3	 18	 0.0011	 0.0133	 0.2138	 500.0	 500.0	 500.0	 0.0	 0.0	 1	 -30.0	 30.0;
	4	 5	 0.0008	 0.0128	 0.1342	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	4	 14	 0.0008	 0.0129	 0.1382	 500.0	 500.0	 500.0	 0.0	 0.0	 1	 -30.0	 30.0;
	5	 6	 0.0002	 0.0026	 0.0434	 1200.0	 1200.0	 1200.0	 0.0	 0.0	 1	 -30.0	 30.0;
	5	 8	 0.0008	 0.0112	 0.1476	 900.0	 900.0	 900.0	 0.0	 0.0	 1	 -30.0	 30.0;
	6	 7	 0.0006	 0.0092	 0.113	 900.0	 900.0	 900.0	 0.0	 0.0	 1	 -30.0	 30.0;
	6	 11	 0.0007	 0.0082	 0.1389	 480.0	 480.0	 480.0	 0.0	 0.0	 1	 -30.0	 30.0;
	6	 31	 0.0	 0.025	 0.0	 1800.0	 1800.0	 1800.0	 1.07	 0.0	 1	 -30.0	 30.0;
	7	 8	 0.0004	 0.0046	 0.078	 900.0	 900.0	 900.0	 0.0	 0.0	 1	 -30.0	 30.0;
	8	 9	 0.0023	 0.0363	 0.3804	 900.0	 900.0	 900.0	 0.0	 0.0	 1	 -30.0	 30.0;
	9	 39	 0.001	 0.025	 1.2	 900.0	 900.0	 900.0	 0.0	 0.0	 1	 -30.0	 30.0;
	10	 11	 0.0004	 0.0043	 0.0729	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	10	 13	 0.0004	 0.0043	 0.0729	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	10	 32	 0.0	 0.02	 0.0	 900.0	 900.0	 2500.0	 1.07	 0.0	 1	 -30.0	 30.0;
	12	 11	 0.0016	 0.0435	 0.0	 500.0	 500.0	 500.0	 1.006	 0.0	 1	 -30.0	 30.0;
	12	 13	 0.0016	 0.0435	 0.0	 500.0	 500.0	 500.0	 1.006	 0.0	 1	 -30.0	 30.0;
	13	 14	 0.0009	 0.0101	 0.1723	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	14	 15	 0.0018	 0.0217	 0.366	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	15	 16	 0.0009	 0.0094	 0.171	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	16	 17	 0.0007	 0.0089	 0.1342	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	16	 19	 0.0016	 0.0195	 0.304	 600.0	 600.0	 2500.0	 0.0	 0.0	 1	 -30.0	 30.0;
	16	 21	 0.0008	 0.0135	 0.2548	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	16	 24	 0.0003	 0.0059	 0.068	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	17	 18	 0.0007	 0.0082	 0.1319	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	17	 27	 0.0013	 0.0173	 0.3216	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	19	 20	 0.0007	 0.0138	 0.0	 900.0	 900.0	 2500.0	 1.06	 0.0	 1	 -30.0	 30.0;
	19	 33	 0.0007	 0.0142	 0.0	 900.0	 900.0	 2500.0	 1.07	 0.0	 1	 -30.0	 30.0;
	20	 34	 0.0009	 0.018	 0.0	 900.0	 900.0	 2500.0	 1.009	 0.0	 1	 -30.0	 30.0;
	21	 22	 0.0008	 0.014	 0.2565	 900.0	 900.0	 900.0	 0.0	 0.0	 1	 -30.0	 30.0;
	22	 23	 0.0006	 0.0096	 0.1846	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	22	 35	 0.0	 0.0143	 0.0	 900.0	 900.0	 2500.0	 1.025	 0.0	 1	 -30.0	 30.0;
	23	 24	 0.0022	 0.035	 0.361	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	23	 36	 0.0005	 0.0272	 0.0	 900.0	 900.0	 2500.0	 0.0	 0.0	 1	 -30.0	 30.0;
	25	 26	 0.0032	 0.0323	 0.531	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	25	 37	 0.0006	 0.0232	 0.0	 900.0	 900.0	 2500.0	 1.025	 0.0	 1	 -30.0	 30.0;
	26	 27	 0.0014	 0.0147	 0.2396	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	26	 28	 0.0043	 0.0474	 0.7802	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	26	 29	 0.0057	 0.0625	 1.029	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	28	 29	 0.0014	 0.0151	 0.249	 600.0	 600.0	 600.0	 0.0	 0.0	 1	 -30.0	 30.0;
	29	 38	 0.0008	 0.0156	 0.0	 1200.0	 1200.0	 2500.0	 1.025	 0.0	 1	 -30.0	 30.0;
];

% INFO    : === Translation Options ===
% INFO    : Load Model:                  from file ./pglib_opf_case39_epri.m.api.sol
% INFO    : Gen Active Capacity Model:   stat
% INFO    : Gen Reactive Capacity Model: al50ag
% INFO    : Gen Active Cost Model:       stat
% INFO    :
% INFO    : === Load Replacement Notes ===
% INFO    : Bus 1	: Pd=97.6, Qd=44.2 -> Pd=160.91, Qd=44.20
% INFO    : Bus 3	: Pd=322.0, Qd=2.4 -> Pd=530.88, Qd=2.40
% INFO    : Bus 4	: Pd=500.0, Qd=184.0 -> Pd=824.35, Qd=184.00
% INFO    : Bus 7	: Pd=233.8, Qd=84.0 -> Pd=385.47, Qd=84.00
% INFO    : Bus 8	: Pd=522.0, Qd=176.6 -> Pd=860.62, Qd=176.60
% INFO    : Bus 9	: Pd=6.5, Qd=-66.6 -> Pd=6.50, Qd=-66.60
% INFO    : Bus 12	: Pd=8.53, Qd=88.0 -> Pd=14.06, Qd=88.00
% INFO    : Bus 15	: Pd=320.0, Qd=153.0 -> Pd=527.58, Qd=153.00
% INFO    : Bus 16	: Pd=329.0, Qd=32.3 -> Pd=542.42, Qd=32.30
% INFO    : Bus 18	: Pd=158.0, Qd=30.0 -> Pd=260.49, Qd=30.00
% INFO    : Bus 20	: Pd=680.0, Qd=103.0 -> Pd=1121.12, Qd=103.00
% INFO    : Bus 21	: Pd=274.0, Qd=115.0 -> Pd=451.74, Qd=115.00
% INFO    : Bus 23	: Pd=247.5, Qd=84.6 -> Pd=408.05, Qd=84.60
% INFO    : Bus 24	: Pd=308.6, Qd=-92.2 -> Pd=308.60, Qd=-92.20
% INFO    : Bus 25	: Pd=224.0, Qd=47.2 -> Pd=369.31, Qd=47.20
% INFO    : Bus 26	: Pd=139.0, Qd=17.0 -> Pd=229.17, Qd=17.00
% INFO    : Bus 27	: Pd=281.0, Qd=75.5 -> Pd=463.28, Qd=75.50
% INFO    : Bus 28	: Pd=206.0, Qd=27.6 -> Pd=339.63, Qd=27.60
% INFO    : Bus 29	: Pd=283.5, Qd=26.9 -> Pd=467.41, Qd=26.90
% INFO    : Bus 31	: Pd=9.2, Qd=4.6 -> Pd=15.17, Qd=4.60
% INFO    : Bus 39	: Pd=1104.0, Qd=250.0 -> Pd=1820.16, Qd=250.00
% INFO    :
% INFO    : === Generator Setpoint Replacement Notes ===
% INFO    : Gen at bus 30	: Pg=520.0, Qg=270.0 -> Pg=90.0, Qg=235.0
% INFO    : Gen at bus 31	: Pg=323.0, Qg=100.0 -> Pg=1455.0, Qg=712.0
% INFO    : Gen at bus 32	: Pg=362.5, Qg=225.0 -> Pg=805.0, Qg=402.0
% INFO    : Gen at bus 33	: Pg=326.0, Qg=125.0 -> Pg=858.0, Qg=253.0
% INFO    : Gen at bus 34	: Pg=254.0, Qg=83.5 -> Pg=859.0, Qg=251.0
% INFO    : Gen at bus 35	: Pg=343.5, Qg=100.0 -> Pg=864.0, Qg=250.0
% INFO    : Gen at bus 36	: Pg=290.0, Qg=120.0 -> Pg=874.0, Qg=215.0
% INFO    : Gen at bus 37	: Pg=282.0, Qg=125.0 -> Pg=887.0, Qg=3.0
% INFO    : Gen at bus 38	: Pg=432.5, Qg=75.0 -> Pg=1185.0, Qg=188.0
% INFO    : Gen at bus 39	: Pg=550.0, Qg=100.0 -> Pg=2326.0, Qg=143.0
% INFO    :
% INFO    : === Generator Reactive Capacity Atleast Setpoint Value Notes ===
% INFO    : Gen at bus 30	: Qg 235.0, Qmin 140.0, Qmax 400.0 -> Qmin -282.0, Qmax 400.0
% INFO    : Gen at bus 31	: Qg 712.0, Qmin -100.0, Qmax 300.0 -> Qmin -854.4, Qmax 854.4
% INFO    : Gen at bus 32	: Qg 402.0, Qmin 150.0, Qmax 300.0 -> Qmin -482.4, Qmax 482.4
% INFO    : Gen at bus 33	: Qg 253.0, Qmin 0.0, Qmax 250.0 -> Qmin -303.6, Qmax 303.6
% INFO    : Gen at bus 34	: Qg 251.0, Qmin 0.0, Qmax 167.0 -> Qmin -301.2, Qmax 301.2
% INFO    : Gen at bus 35	: Qg 250.0, Qmin -100.0, Qmax 300.0 -> Qmin -300.0, Qmax 300.0
% INFO    : Gen at bus 36	: Qg 215.0, Qmin 0.0, Qmax 240.0 -> Qmin -258.0, Qmax 240.0
% INFO    : Gen at bus 37	: Qg 3.0, Qmin 0.0, Qmax 250.0 -> Qmin -3.6, Qmax 250.0
% INFO    : Gen at bus 38	: Qg 188.0, Qmin -150.0, Qmax 300.0 -> Qmin -225.6, Qmax 300.0
% INFO    : Gen at bus 39	: Qg 143.0, Qmin -100.0, Qmax 300.0 -> Qmin -171.6, Qmax 300.0
% INFO    :
% INFO    : === Generator Classification Notes ===
% INFO    : COW    10  -   100.00
% INFO    :
% INFO    : === Generator Active Capacity Stat Model Notes ===
% INFO    : Gen at bus 30 - COW	: Pg=90.0, Pmax=1040.0 -> Pmax=318   samples: 2
% WARNING : Failed to find a generator capacity within (1455.0-7275.0) after 100 samples, using percent increase model
% INFO    : Gen at bus 31 - COW	: Pg=1455.0, Pmax=646.0 -> Pmax=1578   samples: 100
% INFO    : Gen at bus 32 - COW	: Pg=805.0, Pmax=725.0 -> Pmax=2555   samples: 26
% INFO    : Gen at bus 33 - COW	: Pg=858.0, Pmax=652.0 -> Pmax=865   samples: 44
% INFO    : Gen at bus 34 - COW	: Pg=859.0, Pmax=508.0 -> Pmax=877   samples: 33
% INFO    : Gen at bus 35 - COW	: Pg=864.0, Pmax=687.0 -> Pmax=1120   samples: 15
% INFO    : Gen at bus 36 - COW	: Pg=874.0, Pmax=580.0 -> Pmax=922   samples: 12
% INFO    : Gen at bus 37 - COW	: Pg=887.0, Pmax=564.0 -> Pmax=1518   samples: 39
% INFO    : Gen at bus 38 - COW	: Pg=1185.0, Pmax=865.0 -> Pmax=1189   samples: 57
% WARNING : Failed to find a generator capacity within (2326.0-11630.0) after 100 samples, using percent increase model
% INFO    : Gen at bus 39 - COW	: Pg=2326.0, Pmax=1100.0 -> Pmax=2523   samples: 100
% INFO    :
% INFO    : === Generator Active Capacity LB Model Notes ===
% INFO    :
% INFO    : === Generator Reactive Capacity Atleast Max 50 Percent Active Model Notes ===
% INFO    : Gen at bus 32 - COW	: Pmax 2555.0, Qmin -482.4, Qmax 482.4 -> Qmin -1278.0, Qmax 1278.0
% INFO    : Gen at bus 33 - COW	: Pmax 865.0, Qmin -303.6, Qmax 303.6 -> Qmin -433.0, Qmax 433.0
% INFO    : Gen at bus 34 - COW	: Pmax 877.0, Qmin -301.2, Qmax 301.2 -> Qmin -439.0, Qmax 439.0
% INFO    : Gen at bus 35 - COW	: Pmax 1120.0, Qmin -300.0, Qmax 300.0 -> Qmin -560.0, Qmax 560.0
% INFO    : Gen at bus 36 - COW	: Pmax 922.0, Qmin -258.0, Qmax 240.0 -> Qmin -461.0, Qmax 461.0
% INFO    : Gen at bus 37 - COW	: Pmax 1518.0, Qmin -3.6, Qmax 250.0 -> Qmin -759.0, Qmax 759.0
% INFO    : Gen at bus 38 - COW	: Pmax 1189.0, Qmin -225.6, Qmax 300.0 -> Qmin -595.0, Qmax 595.0
% INFO    : Gen at bus 39 - COW	: Pmax 2523.0, Qmin -171.6, Qmax 300.0 -> Qmin -1262.0, Qmax 1262.0
% INFO    :
% INFO    : === Generator Setpoint Replacement Notes ===
% INFO    : Gen at bus 30	: Pg=90.0, Qg=235.0 -> Pg=159.0, Qg=59.0
% INFO    : Gen at bus 30	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 31	: Pg=1455.0, Qg=712.0 -> Pg=789.0, Qg=0.0
% INFO    : Gen at bus 31	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 32	: Pg=805.0, Qg=402.0 -> Pg=1277.5, Qg=0.0
% INFO    : Gen at bus 32	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 33	: Pg=858.0, Qg=253.0 -> Pg=432.5, Qg=0.0
% INFO    : Gen at bus 33	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 34	: Pg=859.0, Qg=251.0 -> Pg=438.5, Qg=0.0
% INFO    : Gen at bus 34	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 35	: Pg=864.0, Qg=250.0 -> Pg=560.0, Qg=0.0
% INFO    : Gen at bus 35	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 36	: Pg=874.0, Qg=215.0 -> Pg=461.0, Qg=0.0
% INFO    : Gen at bus 36	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 37	: Pg=887.0, Qg=3.0 -> Pg=759.0, Qg=0.0
% INFO    : Gen at bus 37	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 38	: Pg=1185.0, Qg=188.0 -> Pg=594.5, Qg=0.0
% INFO    : Gen at bus 38	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 39	: Pg=2326.0, Qg=143.0 -> Pg=1261.5, Qg=0.0
% INFO    : Gen at bus 39	: Vg=1.0 -> Vg=1.0
% INFO    :
% INFO    : === Writing Matpower Case File Notes ===


function obj = squeezenet_autonn_custom_fn(block, inputs, ~)
% SQUEEZENET_AUTONN_CUSTOM_FN autonn custom layer converter
%
% Copyright (C) 2017 Samuel Albanie
% Licensed under The MIT License [see LICENSE.md for details]

  switch class(block)
    case 'dagnn.Permute'
      obj = Layer.create(@permute, {inputs{1}, block.order}) ;
    case 'dagnn.Flatten'
      obj = Layer.create(@vl_nnflatten, {inputs{1}, block.axis}) ;
    case 'dagnn.Reshape'
      obj = Layer.create(@vl_nnreshape, {inputs{1}, block.shape}) ;
  end


function varargout = minus(varargin)
%-   Subtraction of two SPHEREFUN objects.
%
%   F - G subtracts G from F, where F and G are SPHEREFUN objects or scalars.
%
% See also SPHEREFUN/PLUS, SPHEREFUN/UMINUS.

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

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

end


%% t_mrdMBA
%
%  Show fibers using FP's mba code
%  Make sure AFQ is on your path
%  SPM needs to be there, too.
%  The repository can be downloaded from:
%     git clone
%
%%

remote.host = 'http://scarlet.stanford.edu/validation/MRI/VISTADATA';
remote.directory = fullfile('diffusion','sampleData','fibers');
rdata('cd',remote);
dirList = rdata('ls',remote,'pdb');                   % Match .pdb extension
%
oname = rdata('get',remote,dirList{2});
fname = [oname,'.pdb'];
copyfile(oname,fname);

%%  Load the fibers and display
fg = fgRead(fname);

% Render the Tract FA Profile for the left uncinate
% A small number of triangles (25 is the default).
nTriangles = 8;
[lgt , fSurf, fvc] = AFQ_RenderFibers(fg,'subdivs',nTriangles);

%%
[lgt , fSurf, fvc] = AFQ_RenderFibers(fg,...
    'subdivs',nTriangles,...
    'color',[.8 0 .8]);

%%
[lgt , fSurf, fvc] = AFQ_RenderFibers(fg,...
    'subdivs',nTriangles,...
    'color',[.6 .6 .8], ...
    'jittercolors',.4);
%%
[~, AFQdata] = AFQ_directories;
cortex = fullfile(AFQdata,'mesh','segmentation.nii.gz');
overlay = fullfile(AFQdata,'mesh','Left_Arcuate_Endpoints.nii.gz');
thresh = .01; % Threshold for the overlay image
crange = [.01 .8]; % Color range of the overlay image
% Render the cortical surface colored by the arcuate endpoint density
[p, msh, lightH] = AFQ_RenderCorticalSurface(cortex, 'overlay' , overlay, 'crange', crange, 'thresh', thresh)

% End


function [train_users, dev_users] = get_balanced_fold(BP4D_dir, users, au, prop_test)

    % Extracting the labels
    [labels, valid_ids, vid_ids, filenames] = extract_BP4D_labels(BP4D_dir, users, au);

    % the grouping should be done per person

    for f=1:numel(filenames)
        filenames{f} = filenames{f}(1:4);
    end

    counts = zeros(numel(users),1);
    for k=1:numel(users)
        counts(k) = sum(cat(1, labels{strcmp(filenames, users{k})}));
    end

    [sorted, inds] = sort(counts);

    dev_users = users(inds(1:round(1/prop_test):end));
    train_users = setdiff(users, dev_users);
end


function compute_rotation_classes(expidx, image_set)

fprintf('rcnn_compute_rotation_classes()\n');

p = exp_params(expidx);

pidxs = p.pidxs;

[~,parts] = util_get_parts24();

num_joints = length(pidxs);

spatidxs = {[22 17],[22 16],[22 23],[22 4],[22 5],[16 14],[17 19],[4 2],[5 7],[2 0],[7 9],[14 12],[19 21]};
% convert spatidxs to 0-14 format
n = 1;
for pidx = pidxs
    for i = 1:length(spatidxs)
        if spatidxs{i}(1) == pidx
            spatidxs{i}(1) = n;
        end
        if spatidxs{i}(2) == pidx
            spatidxs{i}(2) = n;
        end
    end
    n = n + 1;
end
% build incidence map
% adjacent joints
adjc = cell(num_joints, 1);
for n = 1:length(spatidxs)
    edge = spatidxs{n};
    v1 = edge(1);
    v2 = edge(2);
    adjc{v1} = unique([adjc{v1} v2]);
    adjc{v2} = unique([adjc{v2} v1]);
end

GT = p.([image_set 'GT']);
load(GT, 'annolist');

if isfield(p, 'idpr_cache_dir')
    clusters_cache_dir = p.idpr_cache_dir;
else
    clusters_cache_dir = [p.expDir '/' p.shortName '/data'];
end

try
    load([clusters_cache_dir '/clusters'],'clusters');
catch
    % compute clusters
    vecs = cell(num_joints, 1);
    for i = 1:num_joints
        vecs{i} = zeros(length(annolist), length(adjc{i})*2+1);
    end

    sz = zeros(num_joints, 1);

    for imgidx = 1:length(annolist)
    %    if imgidx == 12220 % outlier
    %        continue;
    %    end

        fprintf('.');

        assert(length(annolist(imgidx).annorect) == 1);
        %for ridx = 1:length(annolist(imgidx).annorect)
        ridx = 1;

        rect = annolist(imgidx).annorect(ridx);
        joints = get_joints(rect, pidxs, parts);

        for idx = 1:num_joints
            [vec, no_points] = compute_pairwise_vec(joints, adjc, idx);
            if ~no_points
                sz(idx) = sz(idx) + 1;
                vecs{idx}(sz(idx), :) = [vec', imgidx];
            end
        end

        %img = imread(annolist(imgidx).image.name);
        %vis_pred(img, joints(:,:));
        %pause;
        if (~mod(imgidx, 100))
            fprintf(' %d/%d\n',imgidx,length(annolist));
        end
    end

    clusters = cell(num_joints, 1);
    for idx = 1:num_joints
        vecs{idx} = vecs{idx}(1:sz, :);
    end

    for idx = 1:num_joints
        num_clasters = p.idpr_num_clusters(idx);
        clusters{idx} = cluster_rotation_classes(vecs{idx}(:,1:end-1), num_clasters, false);
    end

    mkdir_if_missing(clusters_cache_dir);
    save([clusters_cache_dir '/clusters'], 'clusters', 'vecs', '-v7.3');
end

pairwise_classes = cell(length(annolist), 1);
skip_class = sum(p.idpr_num_clusters) + 1;

% now compute pairwise class for all images
for imgidx = 1:length(annolist)
    fprintf('.');

    ridx = 1;

    rect = annolist(imgidx).annorect(ridx);
    joints = get_joints(rect, pidxs, parts);

    pairwise_class = ones(num_joints, 3) * 1e6;
    for idx = 1:num_joints
        [vec, no_points] = compute_pairwise_vec(joints, adjc, idx);
        pj = joints(idx, :);
        pairwise_class(idx, 1:2) = pj;
        if ~no_points
            diff = bsxfun(@minus, clusters{idx}, vec');
            [~, min_dist] = min(sum(diff.^2, 2));
            pairwise_class(idx, 3) = compute_idpr_class(idx, min_dist, p.idpr_num_clusters);
        elseif ~isnan(pj(1))
            pairwise_class(idx, 3) = skip_class;
        end
    end
    pairwise_classes{imgidx} = pairwise_class;

    if (~mod(imgidx, 100))
        fprintf(' %d/%d\n',imgidx,length(annolist));
    end
end

cache_dir = [p.expDir '/' p.shortName '/data'];
mkdir_if_missing(cache_dir);
save([cache_dir '/pairwise_classes'],'pairwise_classes', '-v7.3');

function [vec, no_points] = compute_pairwise_vec(joints, adjc, idx)
    pj = joints(idx, :);
    no_points = isnan(pj(1));
    vec = zeros(length(adjc{idx})*2, 1);
    n = 0;
    for adj = adjc{idx}
        pa = joints(adj, :);
        vec(n*2+1:n*2+2) = pa - pj;
        no_points = no_points | isnan(pa(1)) | (abs(vec(1)) > 300) | (abs(vec(2)) > 300);
        n = n + 1;
    end

function joints = get_joints(rect, pidxs, parts)
    points = rect.annopoints.point;
    joints = NaN(14, 2);
    n = 1;
    for pidx = pidxs
        annopoint_idxs = parts(pidx+1).pos;
        assert(annopoint_idxs(1) == annopoint_idxs(2));
        pt = util_get_annopoint_by_id(points, annopoint_idxs(1));
        if (~isempty(pt))
            joints(n, :) = [pt.x pt.y];
        end
        n = n + 1;
    end

function res = compute_idpr_class(joint_no, joint_class, num_clusters)
res = sum(num_clusters(1:joint_no-1))+joint_class;


%
% In order to obtain the source code for Fingerprint Recognition System Release 5.1
% ( you are using this last release ) please visit my webpage
% http://utenti.lycos.it/matlab/fingerprint4.htm
%
% For any question please email me luigi.rosa@tiscali.it
%
% Release 5.1
% Major features:
% - An improved algorithm used in fingerprint matching, highly recommended for high-performance applications
% - A generalized and optimized version of the algorithm for core point localization
% - Improved database
% - Demo code (protected P-files) available for performance evaluation
%
% Release 5.0
% Major features:
% - The merging technique is greatly improved. This new algorithm was tested on FVC2004 training fingerprint images. Test results are available on request. Please email me in order to obtain them.
% - Parameters for image segmentation are estimated automatically
% - An improved algorithm is used when the rotated FingerCode is added to database. Now this procedure does not introduce any additional noise
% - A faster fingerprint image acquisition when a new fingerprint image is added to database
% - Implementation of 1D and 2D recursive Gabor filtering
% - Optimized pixel-wise orientation field estimation ( 80% faster than Release 4.0 )
% - List of fingerprint databases available on the web
%
% Release 4.0
% Major features:
% - An improved algorithm for core point detection, based on a novel hybrid technique
% - A better fingerprint segmentation which makes use of morphological operations (binary erosion and dilation)
% - Exhaustive documentation of the implemented algorithms
% - Improved GUI
% - Better error management
% - Image enhancement
% - Orientation field estimation
%
% For more informations please visit
% http://utenti.lycos.it/matlab/fingerprint4.htm
%
% Luigi ROSA
% Via Centrale 35
% 67042 Civita Di Bagno
% L'Aquila - ITALY
% mobile +39 3207214179
% email luigi.rosa@tiscali.it
%
%


function y = cumprod( x, dim )

%   Disciplined geometric programming information for PROD:
%      CUMPROD(X,DIM) is a vectorized version of multiplication,
%      so in most cases it would be incompatible with DCPs. Therefore it
%      has not been implemented to support DCPs. DGPs however support
%      products more liberally. When PROD is used in a DCP, elements in
%      each subvector must satisfy the corresponding combination rule
%      for multiplication (see TIMES). For example, suppose that X looks
%      like this:
%         X = [ log-convex log-concave log-affine  ;
%               log-affine log-concave log-concave ]
%      Then CUMPROD(X,1) would be legal, but CUMPROD(X,2) would not,
%      because the top row contains the product of log-convex and
%      log-concave terms, in violation of the DGP ruleset.

error( nargchk( 1, 2, nargin ) );

%
% Basic argument check
%

sx = size( x );
if nargin < 2,
    dim = cvx_default_dimension( sx );
elseif ~cvx_check_dimension( dim ),
    error( 'Second argument must be a positive integer.' );
end

%
% Determine sizes
%

sx = [ sx, ones( 1, dim - length( sx ) ) ];
nx = sx( dim );

%
% Quick exit for empty arrays
%

if any( sx == 0 ),
    y = ones( sy );
    return
end

%
% Type check
%

persistent remap_1 remap_2 remap_3 remap_0
if isempty( remap_3 ),
    remap_0 = cvx_remap( 'zero' );
    remap_1 = cvx_remap( 'constant' );
    remap_2 = cvx_remap( 'log-convex' );
    remap_3 = cvx_remap( 'log-concave' );
end
vx = cvx_reshape( cvx_classify( x ), sx );
t0 = any( reshape( remap_0( vx ), sx ), dim );
t1 = all( reshape( remap_1( vx ), sx ), dim );
t2 = all( reshape( remap_2( vx ), sx ), dim ) | ...
     all( reshape( remap_3( vx ), sx ), dim );
t3 = t2 & t0;
ta = ( t1 | t3 ) + 2 * ( t2 & ~t3 );
nu = sort( ta(:) );
nu = nu([true;diff(nu)~=0]);
nk = length( nu );

%
% Quick exit for easy case
%

if nx == 1 && nu(1) > 0,
    y = x;
    return
end

%
% Permute and reshape, if needed
%

perm = [];
if nk > 1 || ( any( nu > 1 ) && nx > 1 ),
    if dim > 1 && any( sx( 1 : dim - 1 ) > 1 ),
        perm = [ dim, 1 : dim - 1, dim + 1 : length( sx ) ];
        x    = permute( x,  perm );
        ta   = permute( ta, perm );
        sx   = sx( perm );
        dim  = 1;
    end
    nv = prod( sx ) / nx;
    x  = reshape( x, nx, nv );
end

%
% Perform the computations
%

if nk > 1,
    y = cvx( [ nx, nv ], [] );
end
for k = 1 : nk,

    if nk == 1,
        xt = x;
    else
        tt = ta == nu( k );
        xt = cvx_subsref( x, ':', tt );
    end

    switch nu( k ),
        case 0,
            error( 'Disciplined convex programming error:\n   Invalid computation: cumprod( {%s} )', cvx_class( xt, true, true ) );
        case 1,
            yt = cvx( cumprod( cvx_constant( xt ), dim ) );
        case 2,
            yt = exp( cumsum( log( xt ), dim ) );
        otherwise,
            error( 'Shouldn''t be here.' );
    end

    if nk == 1,
        y = yt;
    else
        y = cvx_subsasgn( y, ':', tt, yt );
    end

end

%
% Reverse the reshaping and permutation steps
%

y = reshape( y, sx );
if ~isempty( perm ),
    y = ipermute( y, perm );
end

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


function [vol] = nfgFibers2ROIImage(fg,volExFile,roiFile)
%Converts fiber endpoints into ROI image
%
%   [vol] = nfgFibers2ROIImage(fg,volExFile,roiFile)
%
%   Will also write out the image to roiFIle if provided.
%
% AUTHORS:
% 2009.08.05 : AJS wrote it.
%
% NOTES:

if ieNotDefined('roiFile'); roiFile=[]; end

fiberLen = cellfun('size',fg.fibers,2);
fc = horzcat(fg.fibers{:});
eID = cumsum(fiberLen);
sID = [1 1+eID(1:end-1)];
coords1 = fc(:,sID);
coords2 = fc(:,eID);
vol = mtrImageFromCoords(coords1, coords2, volExFile, roiFile);

return;


function sos = sosprogram(vartable,decvartable)
% SOSPROGRAM --- Initialize a new sum of squares program.
%
% SOSP = sosprogram(VARTABLE,DECVARTABLE)
%
% SOSP is a new sum of squares program.
% VARTABLE is a vector of independent variables.
% DECVARTABLE is a vector of decision variables (optional).
%
% Both VARTABLE and DECVARTABLE are either symbolic or polynomial objects.
%

% This file is part of SOSTOOLS - Sum of Squares Toolbox ver 3.00.
%
% Copyright (C)2002, 2004, 2013  A. Papachristodoulou (1), J. Anderson (1),
%                                G. Valmorbida (1), S. Prajna (2),
%                                P. Seiler (3), P. A. Parrilo (4)
% (1) Department of Engineering Science, University of Oxford, Oxford, U.K.
% (2) Control and Dynamical Systems - California Institute of Technology,
%     Pasadena, CA 91125, USA.
% (3) Aerospace and Engineering Mechanics Department, University of
%     Minnesota, Minneapolis, MN 55455-0153, USA.
% (4) Laboratory for Information and Decision Systems, M.I.T.,
%     Massachusetts, MA 02139-4307
%
% Send bug reports and feedback to: sostools@cds.caltech.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%

% 12/24/01 - SP
% 01/07/02 - SP
% 02/21/02 - SP -- Symbolic polynomial
% 10/10/02 - SP -- Path checking

if ~exist('sedumi') & ~exist('sqlp') & ~exist('csdp') & ~exist('sdpnal')
    error('No SDP solvers found.');
end;

if ~exist('getpolysym')
    dd = which('sosprogram');
    dd = strrep(dd,'/sosprogram.m','/');
    dd = strrep(dd,'\sosprogram.m','\');
    pp = genpath(dd);
    addpath(pp);
end;

if isa(vartable,'sym')

	sos.var.num = 0;
	sos.var.type = {};
	sos.var.Z = {};
	sos.var.ZZ = {};
	sos.var.T = {};

	sos.expr.num = 0;
	sos.expr.type = {};
	sos.expr.At = {};
	sos.expr.b = {};
	sos.expr.Z = {};

	sos.extravar.num = 0;
	sos.extravar.Z = {};
	sos.extravar.ZZ = {};
	sos.extravar.T = {};
	sos.extravar.idx = {};

	sos.objective = [];        % 01/07/02

	sos.solinfo.x = [];
	sos.solinfo.y = [];
	sos.solinfo.RRx = [];
	sos.solinfo.RRy = [];
	sos.solinfo.info = [];

	sos.vartable = sym2chartable(vartable);    % 02/21/02
	if size(vartable,2) > 1
        vartable = vartable.';
	end;
	sos.symvartable = vartable;

    sos.varmat.vartable = '[]';                 %JA&GV 06/06/13
    sos.varmat.symvartable = [];
    sos.varmat.count = 0;

	if (nargin == 2 & ~isempty(decvartable))
        sos.objective = sparse(length(decvartable),1);
        sos.decvartable = sym2chartable(decvartable);     % 03/01/02
        setofCommaBrackets = [1 strfind(sos.decvartable,',') strfind(sos.decvartable,']')];%26/04/13

        if size(decvartable,2) > 1
            decvartable = decvartable.';%the transpose of a matrix of decision varibles
                                        %it is put under this form in
                                        %sos.symdecvartable (next line)
        end;
        sos.symdecvartable = decvartable;
        sos.var.idx{1} = length(find(sos.decvartable==','))+2;

	else
        sos.decvartable = '[]';
        sos.symdecvartable = [];
        sos.var.idx{1} = 1;

	end;

else

	sos.var.num = 0;
	sos.var.type = {};
	sos.var.Z = {};
	sos.var.ZZ = {};
	sos.var.T = {};

	sos.expr.num = 0;
	sos.expr.type = {};
	sos.expr.At = {};
	sos.expr.b = {};
	sos.expr.Z = {};

	sos.extravar.num = 0;
	sos.extravar.Z = {};
	sos.extravar.ZZ = {};
	sos.extravar.T = {};
	sos.extravar.idx = {};

	sos.objective = [];        % 01/07/02

	sos.solinfo.x = [];
	sos.solinfo.y = [];
	sos.solinfo.RRx = [];
	sos.solinfo.RRy = [];
	sos.solinfo.info = [];

    sos.vartable = sort(vartable.varname);

    sos.varmat.vartable = [];                 % PJS 9/9/2013
    sos.varmat.symvartable = [];
    sos.varmat.count = 0;

	if (nargin == 2 & ~isempty(decvartable))
        sos.objective = sparse(length(decvartable),1);
        sos.decvartable = sort(decvartable.varname);

        sos.var.idx{1} = length(decvartable)+1;
	else
        sos.decvartable = {};
        sos.var.idx{1} = 1;
	end;

end;


function [new_gait, sol, info, total_time] = solve(nlp, x0, info)

    % Link the NLP problem to a NLP solver
    solver = IpoptApplication(nlp);

    solver.Options.ipopt.bound_frac = 1e-8;
    solver.Options.ipopt.bound_push = 1e-8;
    % Possible parameter changes to solver
    solver.Options.ipopt.tol = 1e-3;
    solver.Options.ipopt.dual_inf_tol = 1e-3;
    solver.Options.ipopt.constr_viol_tol = 1e-3;
    solver.Options.ipopt.compl_inf_tol = 1e-3;
    solver.Options.ipopt.max_iter = 1000;

    %%% Only use this if contraints are the same
    if nargin > 2
        solver.Options.ipopt.point_perturbation_radius = 0;
        solver.Options.ipopt.warm_start_bound_push = 1e-8;
        solver.Options.ipopt.warm_start_mult_bound_push = 1e-8;
        solver.Options.ipopt.mu_init = 1e-6;
        solver.Options.ipopt.warm_start_init_point = 'yes';
        solver.Options.zl = info.zl;
        solver.Options.zu = info.zu;
        solver.Options.lambda = info.lambda;
    end

    %     solver.Options.ipopt.acceptable_tol = 1e-2;
    %     solver.Options.ipopt.acceptable_constr_viol_tol = 1e-4;
    %     solver.Options.ipopt.acceptable_dual_inf_tol = 1e-2;
    %     solver.Options.ipopt.acceptable_compl_inf_tol = 1e-2;
    %

    solver.Options.ipopt.print_timing_statistics = 'yes';
    solver.Options.ipopt.nlp_lower_bound_inf = -1e6;
    solver.Options.ipopt.nlp_upper_bound_inf = 1e6;
    % Run the optimization
    start_time = tic();
    if nargin < 2
        [sol, info] = optimize(solver);
    else
        [sol, info] = optimize(solver, x0);
    end
    [tspan, states, inputs, params] = exportSolution(nlp, sol);
    tspan{3} = tspan{1}(end) + tspan{3};

    total_time = toc(start_time);
    new_gait = struct(...
        'tspan', tspan,...
        'states', states,...
        'inputs', inputs,...
        'params', params);

end


function [upper,x_min,info_text,numglobals,timing,p_upper] = solve_upper_in_node(p,p_upper,x,upper,x_min,uppersolver,info_text,numglobals,timing,cutiterations);

if nargin < 10
    cutiterations = 1;
end

% Call nonlinear solver (if there are SDP cones and non-SDP solver, or user
% specified use of nonlinear SDP cut generation, remove SDP cone)
[output,timing] = global_solve_upper(pruneSDPCone(p),pruneSDPCone(removeCuts(p_upper)),x,p.options,uppersolver,timing);
output.Primal(p_upper.integer_variables) = round(output.Primal(p_upper.integer_variables));
output.Primal(p_upper.binary_variables) = round(output.Primal(p_upper.binary_variables));

z = apply_recursive_evaluation(p_upper,output.Primal);

[upper_residual,~,feasibility] = constraint_residuals(p_upper,z);
feasible = ~isempty(z) & ~any(isnan(z)) & all(upper_residual(1:p_upper.K.f)>=-p.options.bmibnb.eqtol) & all(upper_residual(1+p_upper.K.f:end)>=-p.options.bmibnb.pdtol);
for i = 1:length(p.evalMap)
    if any(p.evalMap{i}.properties.forbidden)
        if any(z(p.evalMap{i}.variableIndex) >p.evalMap{i}.properties.forbidden(1) & z(p.evalMap{i}.variableIndex) < p.evalMap{i}.properties.forbidden(2))
            feasible = 0;
            break
        end
    end
end
if feasible
    this_upper = p_upper.f+p_upper.c'*z+z'*p_upper.Q*z;
    if isequal(p_upper.K.f,0) && isequal(p_upper.K.l,0) && isequal(p_upper.K.q,0) && isequal(p_upper.K.s,0)
        % This is a simple bound-constrained problem. We can try a
        % cross-over and see if it improves the objective
        xx = output.Primal;
        j = find(abs(xx-p_upper.lb)<=p.options.bmibnb.vartol);
        xx(j) = p_upper.lb(j);
        j = find(abs(xx-p_upper.ub)<=p.options.bmibnb.vartol);
        xx(j) = p_upper.ub(j);
        alt_z = apply_recursive_evaluation(p_upper,xx);
        alt_upper = p_upper.f + p_upper.c'*alt_z + alt_z'*p_upper.Q*alt_z;
        if alt_upper < this_upper
            this_upper = alt_upper;
            z = alt_z;
        end
    end
    if this_upper < upper
        x_min = z;
        if length(info_text) == 0
            if isinf(upper)
                info_text = 'Solution found by upper solver';
            else
                info_text = 'Improved solution found by upper solver';
            end
        else
            if isinf(upper)
                info_text = [info_text ' | ' 'Solution found by upper solver'];
            else
                info_text = [info_text ' | ' 'Improved solution found by upper solver'];
            end
         end
        upper = this_upper;
        numglobals = numglobals + 1;
    end
elseif output.problem == 0 && p_upper.K.s(1)>0 && ~p_upper.solver.uppersolver.constraint.inequalities.semidefinite.linear && cutiterations > 0
    % Piggy-back some old code. Generate elementwise cuts from
    % vioalated SDP constraints (if there are any) and add these to the
    % global upper bound model.
    p_u = p_upper;
    p_u.lpcuts = [];
    p_u.cutState = [];
    p_u=createsdpcut(p_u,z);
    p_upper.F_struc = [p_upper.F_struc(1:p_upper.K.f,:);p_u.lpcuts;p_upper.F_struc(1+p_upper.K.f:end,:)];
    p_upper.K.l  = p_upper.K.l + size(p_u.lpcuts,1);
%    if ~isempty(p_u.socpcuts)
%        p_upper.F_struc = [p_upper.F_struc(1:p_upper.K.f+p_upper.K.l,:);p_u.socpcuts;p_upper.F_struc(1+p_upper.K.f+p_upper.K.l:end,:)];
%         if isequal(p_upper.K.q,0)
%             p_upper.K.q  = repmat(3,1,size(p_u.socpcuts,1)/3);
%         else
%             p_upper.K.q  = [repmat(3,1,size(p_u.socpcuts,1)/3) p_upper.K.q];
%         end
%    end

    if ~isempty(p_u.lpcuts)
        n = length(p_u.cutState);
        if length(info_text) == 0
            info_text = ['Added ' num2str(n) ' cut' plurals(n) ' on SDP cone'];
        else
            info_text = [info_text ' | ' 'Added ' num2str(n) ' cut' plurals(n) ' on SDP cone'];
        end
    end

    % Call recursively if we added cuts, and user wants to run more
    % than one iteration
    if ~isempty(p_u.cutState) > 0 && cutiterations > 1
        [upper,x_min,info_text,numglobals,timing,p_upper] = solve_upper_in_node(p,p_upper,x,upper,x_min,uppersolver,info_text,numglobals,timing,cutiterations-1);
    end
end

function p = pruneSDPCone(p)
if any(p.K.s) && p.options.bmibnb.uppersdprelax
    if ~p.solver.uppersolver.constraint.inequalities.semidefinite.linear
        p.F_struc(end-sum(p.K.s.^2)+1:end,:) = [];
        p.K.s = 0;
    end
end

function s = plurals(n)
if n>1
    s = 's';
else
    s = '';
end


function net = resnet52_new_hope()

%----------------------img cnn----------------------
netStruct = load('./data/imagenet-vgg-verydeep-19.mat') ;
net = dagnn.DagNN.loadobj(netStruct) ;
net.removeLayer('fc8');
net.removeLayer('prob');
net.removeLayer('relu7');

for i = 1:numel(net.params)
    if(mod(i,2)==0)
        net.params(i).learningRate= 0; %0.02;
    else net.params(i).learningRate= 0; %0.001;
    end
    net.params(i).weightDecay=0; %1;
end

net.params(1).learningRate = 0; %1e-5;

fc1Block = dagnn.Conv('size',[1 1 4096 4096],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc1',fc1Block,{'x40'},{'fc1'},{'fc1f'});
net.addLayer('fc1bn',dagnn.BatchNorm(),{'fc1'},{'fc1bn'},...
    {'fc1bn_w','fc1bn_b','fc1bn_m'});
net.addLayer('fc1x',dagnn.ReLU(),{'fc1bn'},{'fc1bnx'});
fc1Block = dagnn.Conv('size',[1 1 4096 2048],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc1_1',fc1Block,{'fc1bnx'},{'fc1_1'},{'fc1_1f'});
net.addLayer('fc1_1bn',dagnn.BatchNorm(),{'fc1_1'},{'fc1_1bn'},...
    {'fc1_1bn_w','fc1_1bn_b','fc1_1bn_m'});
net.addLayer('fc1_1x',dagnn.ReLU(),{'fc1_1bn'},{'fc1_1bnx'});
net.addLayer('dropout',dagnn.DropOut('rate',0.75),{'fc1_1bnx'},{'fc1_1bnxd'});

%----------------------char cnn----------------------
% input is 1*32*20074*16
fc2Block = dagnn.Conv('size',[1 1 20074 300],'hasBias',true,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc2',fc2Block,{'data2'},{'fc2'},{'fc2f','fc2b'});
net.addLayer('fc2bn',dagnn.BatchNorm(),{'fc2'},{'fc2bn'},...
    {'fc2bn_w','fc2bn_b','fc2bn_m'});
%net.addLayer('fc2x',dagnn.ReLU(),{'fc2bn'},{'fc2bnx'});
%net.addLayer('dropout_diction',dagnn.DropOut('rate',0.5),{'fc2bn'},{'fc2bnd'});
% 32*256
convBlock = dagnn.Conv('size',[1 1 300 128],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc2_1_1',convBlock,{'fc2bn'},{'fc2_1_1'},{'fc2_1_1f'});
net.addLayer('fc2_1_1bn',dagnn.BatchNorm(),{'fc2_1_1'},{'fc2_1_1bn'},...
    {'fc2_1_1bn_w','fc2_1_1bn_b','fc2_1_1bn_m'});
net.addLayer('fc2_1_1x',dagnn.ReLU(),{'fc2_1_1bn'},{'fc2_1_1bnx'});

convBlock = dagnn.Conv('size',[1 2 128 128],'hasBias',false,'stride',[1,1],'pad',[0,0,1,0]);
net.addLayer('fc2_1_2',convBlock,{'fc2_1_1bnx'},{'fc2_1_2'},{'fc2_1_2f'});
net.addLayer('fc2_1_2bn',dagnn.BatchNorm(),{'fc2_1_2'},{'fc2_1_2bn'},...
    {'fc2_1_2bn_w','fc2_1_2bn_b','fc2_1_2bn_m'});
net.addLayer('fc2_1_2x',dagnn.ReLU(),{'fc2_1_2bn'},{'fc2_1_2bnx'});

convBlock = dagnn.Conv('size',[1 1 128 256],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc2_1_3',convBlock,{'fc2_1_2bnx'},{'fc2_1_3'},{'fc2_1_3f'});
net.addLayer('fc2_1_3bn',dagnn.BatchNorm(),{'fc2_1_3'},{'fc2_1_3bn'},...
    {'fc2_1_3bn_w','fc2_1_3bn_b','fc2_1_3bn_m'});

convBlock = dagnn.Conv('size',[1 1 300 256],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc2_1b',convBlock,{'fc2bn'},{'fc2_1b'},{'fc2_1bf'});
net.addLayer('fc2_1bbn',dagnn.BatchNorm(),{'fc2_1b'},{'fc2_1bbn'},...
    {'fc2_1bbn_w','fc2_1bbn_b','fc2_1bbn_m'});

net.addLayer('fc2_1sum',dagnn.Sum(),{'fc2_1_3bn','fc2_1bbn'},...
    {'fc2_1sum'});
net.addLayer('fc2_1x',dagnn.ReLU(),{'fc2_1sum'},{'fc2_1sumx'});

% 32*256
for i  = 2:3
    convBlock = dagnn.Conv('size',[1 1 256 64],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
    net.addLayer( sprintf('fc2_%d_1',i),convBlock,{sprintf('fc2_%dsumx',i-1)},{sprintf('fc2_%d_1',i)}, ...
        {sprintf('fc2_%d_1f',i)});
    net.addLayer(sprintf('fc2_%d_1bn_1',i),dagnn.BatchNorm(),{sprintf('fc2_%d_1',i)},{sprintf('fc2_%d_1bn',i)},...
        {sprintf('fc2_%d_1bn_w',i),sprintf('fc2_%d_1bn_b',i),sprintf('fc2_%d_1bn_m',i)});
    net.addLayer(sprintf('fc2_%d_1x',i),dagnn.ReLU(),{sprintf('fc2_%d_1bn',i)},{sprintf('fc2_%d_1bnx',i)});

    convBlock = dagnn.Conv('size',[1 2 64 64],'hasBias',false,'stride',[1,1],'pad',[0,0,1,0]);
    net.addLayer( sprintf('fc2_%d_2',i),convBlock,{sprintf('fc2_%d_1bnx',i)},{sprintf('fc2_%d_2',i)}, ...
        {sprintf('fc2_%d_2f',i)});
    net.addLayer(sprintf('fc2_%d_2bn',i),dagnn.BatchNorm(),{sprintf('fc2_%d_2',i)},{sprintf('fc2_%d_2bn',i)},...
        {sprintf('fc2_%d_2bn_w',i),sprintf('fc2_%d_2bn_b',i),sprintf('fc2_%d_2bn_m',i)});
    net.addLayer(sprintf('fc2_%d_2x',i),dagnn.ReLU(),{sprintf('fc2_%d_2bn',i)},{sprintf('fc2_%d_2bnx',i)});

    convBlock = dagnn.Conv('size',[1 1 64 256],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
    net.addLayer( sprintf('fc2_%d_3',i),convBlock,{sprintf('fc2_%d_2bnx',i)},{sprintf('fc2_%d_3',i)}, ...
        {sprintf('fc2_%d_3f',i)});
    net.addLayer(sprintf('fc2_%d_3bn',i),dagnn.BatchNorm(),{sprintf('fc2_%d_3',i)},{sprintf('fc2_%d_3bn',i)},...
        {sprintf('fc2_%d_3bn_w',i),sprintf('fc2_%d_3bn_b',i),sprintf('fc2_%d_3bn_m',i)});

    net.addLayer(sprintf('fc2_%dsum',i),dagnn.Sum(),{sprintf('fc2_%dsumx',i-1),sprintf('fc2_%d_3bn',i)},...
        {sprintf('fc2_%dsum',i)});
    net.addLayer(sprintf('fc2_%dx',i),dagnn.ReLU(),{sprintf('fc2_%dsum',i)},{sprintf('fc2_%dsumx',i)});
end

%32*256
convBlock = dagnn.Conv('size',[1 1 256 512],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc2_4a_1',convBlock,{'fc2_3sumx'},{'fc2_4a_1'},{'fc2_4a_1f'});
net.addLayer('fc2_4a_1bn',dagnn.BatchNorm(),{'fc2_4a_1'},{'fc2_4a_1bn'},...
    {'fc2_4a_1bn_w','fc2_4a_1bn_b','fc2_4a_1bn_m'});
net.addLayer('fc2_4a_1x',dagnn.ReLU(),{'fc2_4a_1bn'},{'fc2_4a_1bnx'});

convBlock = dagnn.Conv('size',[1 2 512 512],'hasBias',false,'stride',[2,2],'pad',[0,0,1,0]);
net.addLayer('fc2_4a_2',convBlock,{'fc2_4a_1bnx'},{'fc2_4a_2'},{'fc2_4a_2f'});
net.addLayer('fc2_4a_2bn',dagnn.BatchNorm(),{'fc2_4a_2'},{'fc2_4a_2bn'},...
    {'fc2_4a_2bn_w','fc2_4a_2bn_b','fc2_4a_2bn_m'});
net.addLayer('fc2_4a_2x',dagnn.ReLU(),{'fc2_4a_2bn'},{'fc2_4a_2bnx'});

convBlock = dagnn.Conv('size',[1 1 512 512],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc2_4a_3',convBlock,{'fc2_4a_2bnx'},{'fc2_4a_3'},{'fc2_4a_3f'});
net.addLayer('fc2_4a_3bn',dagnn.BatchNorm(),{'fc2_4a_3'},{'fc2_4a_3bn'},...
    {'fc2_4a_3bn_w','fc2_4a_3bn_b','fc2_4a_3bn_m'});

convBlock = dagnn.Conv('size',[1 1 256 512],'hasBias',false,'stride',[2,2],'pad',[0,0,0,0]);
net.addLayer('fc2_4b',convBlock,{'fc2_3sumx'},{'fc2_4b'},{'fc2_4bf'});
net.addLayer('fc2_4bbn',dagnn.BatchNorm(),{'fc2_4b'},{'fc2_4bbn'},...
    {'fc2_4bbn_w','fc2_4bbn_b','fc2_4bbn_m'});

%16*512
net.addLayer('fc2_4sum',dagnn.Sum(),{'fc2_4a_3bn','fc2_4bbn'},...
    {'fc2_4sum'});
net.addLayer('fc2_4x',dagnn.ReLU(),{'fc2_4sum'},{'fc3_1sumx'});

for i  = 2:4
    convBlock = dagnn.Conv('size',[1 1 512 128],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
    net.addLayer( sprintf('fc3_%d_1',i),convBlock,{sprintf('fc3_%dsumx',i-1)},{sprintf('fc3_%d_1',i)}, ...
        {sprintf('fc3_%d_1f',i)});
    net.addLayer(sprintf('fc3_%d_1bn_1',i),dagnn.BatchNorm(),{sprintf('fc3_%d_1',i)},{sprintf('fc3_%d_1bn',i)},...
        {sprintf('fc3_%d_1bn_w',i),sprintf('fc3_%d_1bn_b',i),sprintf('fc3_%d_1bn_m',i)});
    net.addLayer(sprintf('fc3_%d_1x',i),dagnn.ReLU(),{sprintf('fc3_%d_1bn',i)},{sprintf('fc3_%d_1bnx',i)});

    convBlock = dagnn.Conv('size',[1 2 128 128],'hasBias',false,'stride',[1,1],'pad',[0,0,1,0]);
    net.addLayer( sprintf('fc3_%d_2',i),convBlock,{sprintf('fc3_%d_1bnx',i)},{sprintf('fc3_%d_2',i)}, ...
        {sprintf('fc3_%d_2f',i)});
    net.addLayer(sprintf('fc3_%d_2bn',i),dagnn.BatchNorm(),{sprintf('fc3_%d_2',i)},{sprintf('fc3_%d_2bn',i)},...
        {sprintf('fc3_%d_2bn_w',i),sprintf('fc3_%d_2bn_b',i),sprintf('fc3_%d_2bn_m',i)});
    net.addLayer(sprintf('fc3_%d_2x',i),dagnn.ReLU(),{sprintf('fc3_%d_2bn',i)},{sprintf('fc3_%d_2bnx',i)});

    convBlock = dagnn.Conv('size',[1 1 128 512],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
    net.addLayer( sprintf('fc3_%d_3',i),convBlock,{sprintf('fc3_%d_2bnx',i)},{sprintf('fc3_%d_3',i)}, ...
        {sprintf('fc3_%d_3f',i)});
    net.addLayer(sprintf('fc3_%d_3bn',i),dagnn.BatchNorm(),{sprintf('fc3_%d_3',i)},{sprintf('fc3_%d_3bn',i)},...
        {sprintf('fc3_%d_3bn_w',i),sprintf('fc3_%d_3bn_b',i),sprintf('fc3_%d_3bn_m',i)});

    net.addLayer(sprintf('fc3_%dsum',i),dagnn.Sum(),{sprintf('fc3_%dsumx',i-1),sprintf('fc3_%d_3bn',i)},...
        {sprintf('fc3_%dsum',i)});
    net.addLayer(sprintf('fc3_%dx',i),dagnn.ReLU(),{sprintf('fc3_%dsum',i)},{sprintf('fc3_%dsumx',i)});
end

convBlock = dagnn.Conv('size',[1 1 512 1024],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc3_5a_1',convBlock,{'fc3_4sumx'},{'fc3_5a_1'},{'fc3_5a_1f'});
net.addLayer('fc3_5a_1bn',dagnn.BatchNorm(),{'fc3_5a_1'},{'fc3_5a_1bn'},...
    {'fc3_5a_1bn_w','fc3_5a_1bn_b','fc3_5a_1bn_m'});
net.addLayer('fc3_5a_1x',dagnn.ReLU(),{'fc3_5a_1bn'},{'fc3_5a_1bnx'});

convBlock = dagnn.Conv('size',[1 2 1024 1024],'hasBias',false,'stride',[2,2],'pad',[0,0,1,0]);
net.addLayer('fc3_5a_2',convBlock,{'fc3_5a_1bnx'},{'fc3_5a_2'},{'fc3_5a_2f'});
net.addLayer('fc3_5a_2bn',dagnn.BatchNorm(),{'fc3_5a_2'},{'fc3_5a_2bn'},...
    {'fc3_5a_2bn_w','fc3_5a_2bn_b','fc3_5a_2bn_m'});
net.addLayer('fc3_5a_2x',dagnn.ReLU(),{'fc3_5a_2bn'},{'fc3_5a_2bnx'});

convBlock = dagnn.Conv('size',[1 1 1024 1024],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc3_5a_3',convBlock,{'fc3_5a_2bnx'},{'fc3_5a_3'},{'fc3_5a_3f'});
net.addLayer('fc3_5a_3bn',dagnn.BatchNorm(),{'fc3_5a_3'},{'fc3_5a_3bn'},...
    {'fc3_5a_3bn_w','fc3_5a_3bn_b','fc3_5a_3bn_m'});

convBlock = dagnn.Conv('size',[1 1 512 1024],'hasBias',false,'stride',[2,2],'pad',[0,0,0,0]);
net.addLayer('fc3_5b',convBlock,{'fc3_4sumx'},{'fc3_5b'},{'fc3_5bf'});
net.addLayer('fc3_5bbn',dagnn.BatchNorm(),{'fc3_5b'},{'fc3_5bbn'},...
    {'fc3_5bbn_w','fc3_5bbn_b','fc3_5bbn_m'});

%8*1024
net.addLayer('fc3_5sum',dagnn.Sum(),{'fc3_5a_3bn','fc3_5bbn'},...
    {'fc3_5sum'});
net.addLayer('fc3_5x',dagnn.ReLU(),{'fc3_5sum'},{'fc4_1sumx'});

for i  = 2:6
    convBlock = dagnn.Conv('size',[1 1 1024 256],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
    net.addLayer( sprintf('fc4_%d_1',i),convBlock,{sprintf('fc4_%dsumx',i-1)},{sprintf('fc4_%d_1',i)}, ...
        {sprintf('fc4_%d_1f',i)});
    net.addLayer(sprintf('fc4_%d_1bn_1',i),dagnn.BatchNorm(),{sprintf('fc4_%d_1',i)},{sprintf('fc4_%d_1bn',i)},...
        {sprintf('fc4_%d_1bn_w',i),sprintf('fc4_%d_1bn_b',i),sprintf('fc4_%d_1bn_m',i)});
    net.addLayer(sprintf('fc4_%d_1x',i),dagnn.ReLU(),{sprintf('fc4_%d_1bn',i)},{sprintf('fc4_%d_1bnx',i)});

    convBlock = dagnn.Conv('size',[1 2 256 256],'hasBias',false,'stride',[1,1],'pad',[0,0,1,0]);
    net.addLayer( sprintf('fc4_%d_2',i),convBlock,{sprintf('fc4_%d_1bnx',i)},{sprintf('fc4_%d_2',i)}, ...
        {sprintf('fc4_%d_2f',i)});
    net.addLayer(sprintf('fc4_%d_2bn',i),dagnn.BatchNorm(),{sprintf('fc4_%d_2',i)},{sprintf('fc4_%d_2bn',i)},...
        {sprintf('fc4_%d_2bn_w',i),sprintf('fc4_%d_2bn_b',i),sprintf('fc4_%d_2bn_m',i)});
    net.addLayer(sprintf('fc4_%d_2x',i),dagnn.ReLU(),{sprintf('fc4_%d_2bn',i)},{sprintf('fc4_%d_2bnx',i)});

    convBlock = dagnn.Conv('size',[1 1 256 1024],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
    net.addLayer( sprintf('fc4_%d_3',i),convBlock,{sprintf('fc4_%d_2bnx',i)},{sprintf('fc4_%d_3',i)}, ...
        {sprintf('fc4_%d_3f',i)});
    net.addLayer(sprintf('fc4_%d_3bn',i),dagnn.BatchNorm(),{sprintf('fc4_%d_3',i)},{sprintf('fc4_%d_3bn',i)},...
        {sprintf('fc4_%d_3bn_w',i),sprintf('fc4_%d_3bn_b',i),sprintf('fc4_%d_3bn_m',i)});

    net.addLayer(sprintf('fc4_%dsum',i),dagnn.Sum(),{sprintf('fc4_%dsumx',i-1),sprintf('fc4_%d_3bn',i)},...
        {sprintf('fc4_%dsum',i)});
    net.addLayer(sprintf('fc4_%dx',i),dagnn.ReLU(),{sprintf('fc4_%dsum',i)},{sprintf('fc4_%dsumx',i)});
end

convBlock = dagnn.Conv('size',[1 1 1024 2048],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc4_7a_1',convBlock,{'fc4_6sumx'},{'fc4_7a_1'},{'fc4_7a_1f'});
net.addLayer('fc4_7a_1bn',dagnn.BatchNorm(),{'fc4_7a_1'},{'fc4_7a_1bn'},...
    {'fc4_7a_1bn_w','fc4_7a_1bn_b','fc4_7a_1bn_m'});
net.addLayer('fc4_7a_1x',dagnn.ReLU(),{'fc4_7a_1bn'},{'fc4_7a_1bnx'});

convBlock = dagnn.Conv('size',[1 2 2048 2048],'hasBias',false,'stride',[1,1],'pad',[0,0,1,0]);
net.addLayer('fc4_7a_2',convBlock,{'fc4_7a_1bnx'},{'fc4_7a_2'},{'fc4_7a_2f'});
net.addLayer('fc4_7a_2bn',dagnn.BatchNorm(),{'fc4_7a_2'},{'fc4_7a_2bn'},...
    {'fc4_7a_2bn_w','fc4_7a_2bn_b','fc4_7a_2bn_m'});
net.addLayer('fc4_7a_2x',dagnn.ReLU(),{'fc4_7a_2bn'},{'fc4_7a_2bnx'});

convBlock = dagnn.Conv('size',[1 1 2048 2048],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc4_7a_3',convBlock,{'fc4_7a_2bnx'},{'fc4_7a_3'},{'fc4_7a_3f'});
net.addLayer('fc4_7a_3bn',dagnn.BatchNorm(),{'fc4_7a_3'},{'fc4_7a_3bn'},...
    {'fc4_7a_3bn_w','fc4_7a_3bn_b','fc4_7a_3bn_m'});

convBlock = dagnn.Conv('size',[1 1 1024 2048],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc4_7b',convBlock,{'fc4_6sumx'},{'fc4_7b'},{'fc4_7bf'});
net.addLayer('fc4_7bbn',dagnn.BatchNorm(),{'fc4_7b'},{'fc4_7bbn'},...
    {'fc4_7bbn_w','fc4_7bbn_b','fc4_7bbn_m'});

%8*2048
net.addLayer('fc4_7sum',dagnn.Sum(),{'fc4_7a_3bn','fc4_7bbn'},...
    {'fc4_7sum'});
net.addLayer('fc4_7x',dagnn.ReLU(),{'fc4_7sum'},{'fc5_1sumx'});

poolBlock = dagnn.Pooling('poolSize',[1 8]);
net.addLayer('fc5_1',poolBlock,{'fc5_1sumx'},{'fc5_1bnx'});
%net.addLayer('fc5_1bn',dagnn.BatchNorm(),{'fc5_1'},{'fc5_1bn'},...
 %   {'fc5_1bn_w','fc5_1bn_b','fc5_1bn_m'});
%net.addLayer('fc5_1x',dagnn.ReLU(),{'fc5_1bn'},{'fc5_1bnx'});

fc5_2Block = dagnn.Conv('size',[1 1 2048 2048],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc5_2',fc5_2Block,{'fc5_1bnx'},{'fc5_2'},{'fc5_2f'});
net.addLayer('fc5_2bn',dagnn.BatchNorm(),{'fc5_2'},{'fc5_2bn'},...
    {'fc5_2bn_w','fc5_2bn_b','fc5_2bn_m'});
net.addLayer('fc5_2x',dagnn.ReLU(),{'fc5_2bn'},{'fc5_2bnx'});
net.addLayer('dropout2',dagnn.DropOut('rate',0.75),{'fc5_2bnx'},{'fc5_2bnxd'});

%----------------------add share layer----------------------
%1

fc_imgBlock = dagnn.Conv('size',[1 1 2048 29783],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc_img',fc_imgBlock,{'fc1_1bnxd'},{'prediction_img'},{'fcsharef'});
net.addLayer('softmaxloss_img',dagnn.Loss('loss','softmaxlog'),{'prediction_img','label_img'},'objective_img');
net.addLayer('top1err_img', dagnn.Loss('loss', 'classerror'), ...
    {'prediction_img','label_img'}, 'top1err_img') ;
net.addLayer('top5err_img', dagnn.Loss('loss', 'topkerror', ...
    'opts', {'topK',5}), ...
    {'prediction_img','label_img'}, 'top5err_img') ;
%2
fc_txtBlock = dagnn.Conv('size',[1 1 2048 29783],'hasBias',false,'stride',[1,1],'pad',[0,0,0,0]);
net.addLayer('fc_txt',fc_txtBlock,{'fc5_2bnxd'},{'prediction_txt'},{'fcsharef'});
net.addLayer('softmaxloss_txt',dagnn.Loss('loss','softmaxlog'),{'prediction_txt','label_txt'},'objective_txt');
net.addLayer('top1err_txt', dagnn.Loss('loss', 'classerror'), ...
    {'prediction_txt','label_txt'}, 'top1err_txt') ;
net.addLayer('top5err_txt', dagnn.Loss('loss', 'topkerror', ...
    'opts', {'topK',5}), ...
    {'prediction_txt','label_txt'}, 'top5err_txt') ;
%}

%}
net.initParams();
%----------NOTICE--------------
first = net.getParamIndex('fc2f');

net.params(first).learningRate = 1e-3;  %w
net.params(first+1).learningRate = 1e-3;  %b

load('./flickr30k_dictionary.mat');
%m = mean(subset.features,2);
%subset.features = subset.features-repmat(m,1,20074);
net.params(first).value = reshape(single(subset.features'),1,1,20074,300);

%net.conserveMemory = false;
%net.move('gpu') ;
%net.eval({'data',gpuArray(single(rand(224,224,3,32))),'data2',gpuArray(single(rand(1,32,20074,32)))});
end


function planC = copyStrToScan(structNum,scanNum,planC)
%function planC = copyStrToScan(structNum,scanNum,planC)
%
%This function derives a new structure from structNum which is associated
%to scanNum. The naming convention for this new structure is
%[structName assoc scanNum]. If structNum is already associated to scanNum,
%the unchanged planC is returned back.
%
%APA, 8/18/06
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

if ~exist('planC')
    global planC
end

indexS = planC{end};

%return if structNum is already associated to scanNum
assocScanNum = getAssociatedScan(planC{indexS.structures}(structNum).assocScanUID, planC);
if assocScanNum == scanNum
    warning(['Structure Number ',num2str(structNum),' is already assocoated with scan ',num2str(scanNum)])
    return;
end

% Structure names of all the structures in existing plan
strNamC = {planC{indexS.structures}.structureName};
strNamC(structNum) = [];

% Structure name of the one to be copied.
strName = planC{indexS.structures}(structNum).structureName;

%obtain r,c,s coordinates of scanNum's (new) x,y,z vals
newScanS = planC{indexS.scan}(scanNum);
[xNewScanValsV, yNewScanValsV, zNewScanValsV] = getScanXYZVals(newScanS);
[rNewScanValsV, cNewScanValsV, sNewScanValsV] = xyztom(xNewScanValsV, yNewScanValsV, zNewScanValsV, scanNum, planC, 1);

%obtain r,c,s coordinates of structure based on its associated (old) scan
[rStructValsV, cStructValsV, sStructValsV] = getUniformStr(structNum, planC);

%obtain x,y,z coordinates of voxels included within structure considering
%transM for old and new scan
[xOldScanValsV, yOldScanValsV, zOldScanValsV] = getUniformScanXYZVals(planC{indexS.scan}(assocScanNum));
xStructValsV = xOldScanValsV(cStructValsV);
yStructValsV = yOldScanValsV(rStructValsV);
zStructValsV = zOldScanValsV(sStructValsV);
if ~isfield(planC{indexS.scan}(scanNum),'transM') || isempty(planC{indexS.scan}(scanNum).transM)
    transMold = eye(4);
else
    transMold = planC{indexS.scan}(scanNum).transM;
end
if ~isfield(planC{indexS.scan}(assocScanNum),'transM') || isempty(planC{indexS.scan}(assocScanNum).transM)
    transMnew = eye(4);
else
    transMnew = planC{indexS.scan}(assocScanNum).transM;
end
transM = inv(transMold)*transMnew;
[xStructValsV, yStructValsV, zStructValsV] = applyTransM(transM, xStructValsV, yStructValsV, zStructValsV);

%convert x,y,z vals of structure to r,c,s of scanNum (new)
[rStructValsV, cStructValsV, sStructValsV] = xyztom(xStructValsV, yStructValsV, zStructValsV, scanNum, planC, 1);
rStructValsV = round(rStructValsV);
rStructValsV = clip(rStructValsV,ceil(min(rNewScanValsV)),floor(max(rNewScanValsV)),'limits');
cStructValsV = round(cStructValsV);
cStructValsV = clip(cStructValsV,ceil(min(cNewScanValsV)),floor(max(cNewScanValsV)),'limits');
sStructValsV = round(sStructValsV);
sStructValsV = clip(sStructValsV,ceil(min(sNewScanValsV)),floor(max(sNewScanValsV)),'limits');

%generate uniformized mask for this new structure
newScanUnifSiz = getUniformScanSize(newScanS);
maskM = zeros(newScanUnifSiz,'uint8');
indicesWithinSkinV = sub2ind(newScanUnifSiz,rStructValsV,cStructValsV,sStructValsV);
maskM(indicesWithinSkinV) = 1;

%generate contours on slices out of uniform mask and add to planC
if any(strncmp(strName,strNamC,inf))
    % strname = [planC{indexS.structures}(structNum).structureName,' asoc ',num2str(scanNum)];
    strName = [strName,' asoc ',num2str(scanNum)];
end
planC = maskToCERRStructure(maskM, 1, scanNum, strName, planC);


% testGraphCutsScript2

if 0
    outdir = '../data';
    load([outdir '/rand_indices.mat']);
    load([outdir '/allimsegs2.mat']);
    load([outdir '/mcmcSuperpixelClassifier.mat']);
    load([outdir '/mcmcEdgeData.mat']);
    load([outdir '/mcmcEdgeClassifier.mat']);
end

alpha = [0:0.5:3];

for k = 1:numel(alpha);

    disp(num2str(alpha(k)))

    for cvf = 1:numel(cv_images)

        %disp([num2str(cvf) ': ' imsegs(cv_images(cvf)).imname])

        f = cv_images(cvf);
        c = ceil(cvf/50);

        [labv, labh] = testImageGraphCuts2(pg{cvf}, efeatures{f}, adjlist{f}, eclassifier, ecal{c}, alpha(k));

        nsp = numel(labv);
        pg2{cvf} = zeros(nsp, 7);
        lab = (labv==1) + (labv==2).*(1+labh) + 7*(labv==3);
        % set most likely label
        pg2{cvf}((lab-1)*nsp + [1:nsp]') = 1;
        % set so that h accuracy can be determined
        pg2{cvf}((labh)*nsp + [1:nsp]') = 0.5;
    end

    [vaccgc(k), haccgc(k)] = mcmcProcessResult(imsegs(cv_images), pg2);
    disp(num2str([vaccgc ; haccgc]))
end


%% NISwGSP-03_SantaMaria-all
% %{
imfolder = 'images\NISwGSP-03_SantaMaria-all';
im_n = 8;
imfile = cell(im_n,1);
for ii = 1:im_n
    imfile{ii} = sprintf('%s\\%02d.jpg', imfolder, ii);
end

im = cell(im_n,1);
for ii = 1:im_n
    im{ii} = imread(imfile{ii});
end

imsize = zeros(im_n,3);

for ii = 1:im_n
    imsize(ii,:) = size(im{ii});
    if imsize(ii,1) > 720
        scale = 720/size(im{ii}, 1);
        im{ii} = imresize(im{ii}, scale);

        imsize(ii,:) = size(im{ii});
    end
end

mosaic = REW_mosaic( im, [], 0, 'equi', 0.02, imfolder );
%}


% This is the main script runner for training, it collects the
% training samples, followed by model training

clear

% define the root name of database
root = '../data_preparation/prepared_data/';

% which scales we're doing
scales = [0.25, 0.35, 0.5];

% the data generation parameters
sigma = 1;
num_samples = 5e5;
ratio_neg = 5;
norm = 1;
normalisation_size = 19;

patch_types = {'reg', 'grad'};

% Should a frontal view be created
frontalView = [1];

% The other views to be used
profileViewInds = [2];
upDownViewInds = [];

version = 'wild';

% the naming of
wild_loc = 'wild_';

for s=scales
    Train_all(root, frontalView, profileViewInds, upDownViewInds, s,...
        sigma, version, norm, 'ratio_neg', ratio_neg,...
        'num_samples', num_samples, 'data_loc', wild_loc,...
        'patch_types', patch_types, 'normalisation_size', normalisation_size);
end


function n = ndims(T)
% overloads size

n = max(2,ndims(T.M) - T.rank);


function  outputData = depatchify(patchData, DParam)
% *************************************************************************
% Video Super-Resolution with Convolutional Neural Networks
% patchify
%
% creates image from patches
%
% DParam:     training parameters
%
%
% Version 1.0
%
% Created by:   Armin Kappeler
% Date:         07/21/2015
%
%
% *************************************************************************
USE_PADDING = 1; %make it divisible by "stride" by extending the image

bordercropping = 0;
overlap = DParam.patchSize - DParam.stride;
offset = (DParam.patchSize - DParam.outputPatchSize)/2; % because we only have center part

outputData = zeros([DParam.inputImgSize(2),DParam.inputImgSize(1)]);
mask = zeros([DParam.inputImgSize(2),DParam.inputImgSize(1)]);

if USE_PADDING == 1
    paddingSize = mod(DParam.stride-(DParam.inputImgSize - DParam.patchSize),DParam.stride);
    [ xPos, yPos ] = getPatchPos( [DParam.inputImgSize(2)+paddingSize(2),DParam.inputImgSize(1)+paddingSize(1)],DParam.patchSize,overlap,bordercropping);
else
    [ xPos, yPos ] = getPatchPos( [DParam.inputImgSize(2),DParam.inputImgSize(1)],DParam.patchSize,overlap,bordercropping);
end
xPos = xPos + offset;
yPos = yPos + offset;

if size(patchData,4) ~= length(xPos)
    error('Error the number of patches is not consistent with the image size / patch size / overlap configuration')
end

if DParam.zeropadding==1
    offset = DParam.outputPatchSize-1;
    for i = 1:size(patchData,4)

        offsety = min(offset,DParam.inputImgSize(2)-yPos(i));
        offsetx = min(offset,DParam.inputImgSize(1)-xPos(i));
        patchStartIdx = (DParam.patchSize-DParam.outputPatchSize)/2 + 1;
        %if offset~=offsetx || offsety ~=offset
        %   display('error')
        %end

    %    outputData(yPos(i):yPos(i)+DParam.outputPatchSize-1,xPos(i):xPos(i)+DParam.outputPatchSize-1,:) = patchData(:,:,:,i);
    %    outputData(yPos(i):yPos(i)+DParam.outputPatchSize-1,xPos(i):xPos(i)+DParam.outputPatchSize-1,:) = patchData(13:24,13:24,:,i);
        outputData(yPos(i):yPos(i)+offsety,xPos(i):xPos(i)+offsetx,:) = patchData(patchStartIdx:patchStartIdx+offsety,patchStartIdx:patchStartIdx+offsetx,:,i);
        mask(yPos(i):yPos(i)+offsety,xPos(i):xPos(i)+offsetx) = mask(yPos(i):yPos(i)+offsety,xPos(i):xPos(i)+offsetx) + 1;
    end
else
    for i = 1:size(patchData,4)
        outputData(yPos(i):yPos(i)+DParam.outputPatchSize-1,xPos(i):xPos(i)+DParam.outputPatchSize-1,:) = patchData(:,:,:,i);
        mask(yPos(i):yPos(i)+DParam.outputPatchSize-1,xPos(i):xPos(i)+DParam.outputPatchSize-1) = mask(yPos(i):yPos(i)+DParam.outputPatchSize-1,xPos(i):xPos(i)+DParam.outputPatchSize-1) + 1;
    end
end

mask(mask==0) = 1; %avoid division by zero
outputData = outputData./mask;

end


function plotFeatureImportanceRF(pathRF)

startpath = pwd;

cd(pathRF), load('testingVariableImportance')
nameOutcomes = fieldnames(training.outcomes); nOutcomes = numel(nameOutcomes);
% fSetNames = fieldnames(training.textures.(nameOutcomes{1})); nFset = numel(fSetNames);
fSetNames = {'PET','CT','PETCT'}; nFset = numel(fSetNames);

for o = 1:nOutcomes
    for f = 1:nFset
        percentAUCdecrease = variableImportance.(nameOutcomes{o}).(fSetNames{f}).percentAUCdecrease;
        varNames = variableImportance.(nameOutcomes{o}).(fSetNames{f}).varNames; nVar = numel(varNames);
        figure
        barh(1:nVar,percentAUCdecrease*100)
        for i = 1:nVar
            ind = strfind(varNames{i},'_'); nInd = numel(ind);
            if ~isempty(ind)
                for n = 1:nInd
                    varNames{i} = [varNames{i}(1:(ind(n)-1+(n-1))),'\',varNames{i}((ind(n)+(n-1)):end)];
                end
            end
        end
        set(gca,'yticklabel',varNames)
        title(['RANDOM PERMUTATIONS (RF):',nameOutcomes{o},' -- ',fSetNames{f}])
        xlabel('Percent AUC decrease')
    end
end

cd(startpath)
end


function X = not(X)
% Internal class for constraint list

superiorto('sdpvar');
superiorto('double');

% Try to evaluate

if length(X.List)>3
    error('Negation can only be applied to BINARY relations')
else
    switch X.List{2}
        case '<'
            X.List{2} = '>';
            X.Evaluated{1} = -X.Evaluated{1};
        case '>'
            X.List{2} = '<';
            X.Evaluated{1} = -X.Evaluated{1};
        case '=='
            % A simple inequality has to be converted to an expression which
            % most likely will be a mixed-integer model....
            X = X.List{1} ~= X.List{3};
        otherwise
            error('Negation cannot be applied on this operator')
    end
end


function status = GE_convertVolume(inBaseName,outName,numImages)
%
% status = GE_convertVolume(inDir,outName,[numImages])
%
%GE_convertVolume
%
% Version 3.1
%
% Converts a series of GE slices into Analyze format for SPM.
% inDir is the name of the directory containing the first file of
% the series, e.g. 003
% outName is used for naming the Analyze files
% status = 1 if there is an error.
%
% Modified to use spm functions
%
% Souheil J. Inati
% Dartmouth College
% September 2001
% souheil.inati@dartmouth.edu
%

status = 1;

if (nargin < 2)
        error('Not enough input arguments.')
        return
end

% Create the name of the first file in inDir
firstfile = fullfile('',[inBaseName,'.001']);

% Read the Header from the first file
disp(['Reading first file: ',firstfile]);
[su_hdr,ex_hdr,se_hdr,im_hdr,pix_hdr,im_offset] = GE_readHeader(firstfile);

% The image Dimensions
Nx =  im_hdr.imatrix_X; % X Voxels
Ny =  im_hdr.imatrix_Y; % Y Voxels
if(exist('numImages','var') & ~isempty(numImages))
    Nz = numImages;
else
    Nz =  im_hdr.slquant;   % Z Voxels
end
volSize = [Nx Ny Nz];

disp(['Reading volume (volsize: ',num2str(volSize),')...']);

% Read in the volume
[imageVol, lastfile] = GE_readVolume(inBaseName, volSize, pix_hdr.img_depth, im_offset);

disp(['Converting...']);
% Is the first image the first or the last?
if (se_hdr.end_loc - se_hdr.start_loc) > 0
  scandir = 1;
else
  scandir = -1;
end

% Compute the M matrix
M = GE_createSPMmat(im_hdr,scandir);

% Create the SPM volume
V.fname = outName;
V.dim = [volSize spm_type('int16')]; % short ints
V.mat = M;
V.pinfo = [1 0 0]';
V = spm_create_image(V);

% Write out the SPM Volume
% Don't use spm_write_vol because that sets a scale factor.
for i = 1:Nz
  V = spm_write_plane(V,squeeze(imageVol(:,:,i)),i);
end

% Done with vol
fprintf('Wrote %s.img.\n',outName);

% Done
fprintf('Conversion Finished. \n\n');

status = 0;

return


function vargout = subplot_tight(m, n, p, margins, varargin)
    %% subplot_tight
    % A subplot function substitude with margins user tunabble parameter.
    %
    %% Syntax
    %  h=subplot_tight(m, n, p);
    %  h=subplot_tight(m, n, p, margins);
    %  h=subplot_tight(m, n, p, margins, subplotArgs...);
    %
    %% Description
    % Our goal is to grant the user the ability to define the margins between neighbouring
    %  subplots. Unfotrtunately Matlab subplot function lacks this functionality, and the
    %  margins between subplots can reach 40% of figure area, which is pretty lavish. While at
    %  the begining the function was implememnted as wrapper function for Matlab function
    %  subplot, it was modified due to axes del;etion resulting from what Matlab subplot
    %  detected as overlapping. Therefore, the current implmenetation makes no use of Matlab
    %  subplot function, using axes instead. This can be problematic, as axis and subplot
    %  parameters are quie different. Set isWrapper to "True" to return to wrapper mode, which
    %  fully supports subplot format.
    %
    %% Input arguments (defaults exist):
    %   margins- two elements vector [vertical,horizontal] defining the margins between
    %        neighbouring axes. Default value is 0.04
    %
    %% Output arguments
    %   same as subplot- none, or axes handle according to function call.
    %
    %% Issues & Comments
    %  - Note that if additional elements are used in order to be passed to subplot, margins
    %     parameter must be defined. For default margins value use empty element- [].
    %  -
    %
    %% Example
    % close all;
    % img=imread('peppers.png');
    % figSubplotH=figure('Name', 'subplot');
    % figSubplotTightH=figure('Name', 'subplot_tight');
    % nElems=17;
    % subplotRows=ceil(sqrt(nElems)-1);
    % subplotRows=max(1, subplotRows);
    % subplotCols=ceil(nElems/subplotRows);
    % for iElem=1:nElems
    %    figure(figSubplotH);
    %    subplot(subplotRows, subplotCols, iElem);
    %    imshow(img);
    %    figure(figSubplotTightH);
    %    subplot_tight(subplotRows, subplotCols, iElem, [0.0001]);
    %    imshow(img);
    % end
    %
    %% See also
    %  - subplot
    %
    %% Revision history
    % First version: Nikolay S. 2011-03-29.
    % Last update:   Nikolay S. 2012-05-24.
    %
    % *List of Changes:*
    % 2012-05-24
    %  Non wrapping mode (based on axes command) added, to deal with an issue of disappearing
    %     subplots occuring with massive axes.

    %% Default params
    isWrapper=false;
    if (nargin<4) || isempty(margins)
        margins=[0.04,0.04]; % default margins value- 4% of figure
    end
    if length(margins)==1
        margins(2)=margins;
    end

    %note n and m are switched as Matlab indexing is column-wise, while subplot indexing is row-wise :(
    [subplot_col,subplot_row]=ind2sub([n,m],p);

    height=(1-(m+1)*margins(1))/m; % single subplot height
    width=(1-(n+1)*margins(2))/n;  % single subplot width

    % note subplot suppors vector p inputs- so a merged subplot of higher dimentions will be created
    subplot_cols=1+max(subplot_col)-min(subplot_col); % number of column elements in merged subplot
    subplot_rows=1+max(subplot_row)-min(subplot_row); % number of row elements in merged subplot

    merged_height=subplot_rows*( height+margins(1) )- margins(1);   % merged subplot height
    merged_width= subplot_cols*( width +margins(2) )- margins(2);   % merged subplot width

    merged_bottom=(m-max(subplot_row))*(height+margins(1)) +margins(1); % merged subplot bottom position
    merged_left=min(subplot_col)*(width+margins(2))-width;              % merged subplot left position
    pos=[merged_left, merged_bottom, merged_width, merged_height];

    if isWrapper
        h=subplot(m, n, p, varargin{:}, 'Units', 'Normalized', 'Position', pos);
    else
        h=axes('Position', pos, varargin{:});
    end

    if nargout==1
        vargout=h;
    end
end


function  y = invsigmoid(x)
% legacy code
s = warning ('on');
warning ('*** The function `invsigmoid` is now deprecated. Please see `VBA_sigmoid` for an alternative.')
warning (s);

% fallback
y = VBA_sigmoid (x, 'inverse', true);