function [mResult, fMls, fMc, fMu, fSigma, mDatPredBest, vPredBest, fBvalue, fAvalue] = calc_McCdfnormal(mCatalog, fBinning)
    % Determine Mc using maximum likelihood estimate; same as calc_McEMR but with output of modeled data
    % [mResult, fMls, fMc, fMu, fSigma, mDatPredBest, vPredBest, fBvalue, fAvalue] = calc_McCdfnormal(mCatalog, fBinning);
    % -----------------------------------------------------------------------------------------------------------------------------
    % Determine Mc using maximum likelihood estimate; same as calc_McEMR but with output of modeled data
    % Fitting non-cumulative frequency magnitude distribution above and below Mc:
    % below: Cumulative NORMAL density function
    % above: Gutenberg-Richter law
    %
    % Incoming variables:
    % mCatalog   : EQ catalog
    % fBinning   : Binning interval, usually 0.1
    %
    % Outgoing variables:
    % mResult     : Solution matrix including
    %               vProbability: maximum likelihood score
    %               vMc         : Mc values
    %               vX_res      : mu (of normal CDF), sigma (of normal CDF), residuum, exitflag
    %               vNmaxBest   : Number of events in lowest magnitude bin considered complete
    %               vABValue    : a and b-value
    % fMls       : minimum maximum likelihood score --> best Mc
    % fMc        : Best estimated magnitude of completeness
    % mDatPredBest   : Matrix of non-cumulative FMD [Prediction, magnitudes, original distribution]
    % vPredBest      : Matrix of non-cumulative FMD below Mc [magnitude, prediction, uncertainty of prediction]
    % fBvalue        : b-value
    %
    % J. Woessner: woessner@seismo.ifg.ethz.ch
    % updated: 03.11.03

    % Initialize
    vProbability = [];
    vMc = [];
    vABValue =[];
    mFitRes = [];
    vX_res = [];
    vNCumTmp = [];
    mDataPred = [];
    vPredBest = [];
    vDeltaBest = [];
    vX_res = [];
    vNmaxBest = [];
    mResult=[];
    mDatPredBest = [];

    % Determine exact time period
    fPeriod1 = max(mCatalog.Date) - min(mCatalog.Date);

    % Determine max. and min. magnitude
    fMaxMag = ceil(10 * max(mCatalog.Magnitude)) / 10;

    % Set starting value for Mc loop and LSQ fitting procedure
    fMcTry= calc_Mc(mCatalog, McMethods.MaxCurvature);
    fSmu = abs(fMcTry/2);
    fSSigma = abs(fMcTry/4);
    if (fSmu > 1)
        fSmu = fMcTry/10;
        fSSigma = fMcTry/20;
    end
    fMcBound = fMcTry;

    % Calculate FMD for original catalog
    [vFMDorg, vNonCFMDorg, fmdbins] = calc_FMD(mCatalog);
    % convert answer back to this file's expectations...
    vFMDorg = [fmdbins'; vFMDorg'] % as rows
    vNonCFMDorg = [fmdbins'; vNonCFMDorg'];

    fMinMag = min(vNonCFMDorg(1,:));

    %% Shift to positive values
    % if fMinMag ~= 0
    %     fMcBound = fMcTry-fMinMag;
    % end
    % Loop over Mc-values
    for fMc = fMcBound-0.4:0.1:fMcBound+0.4
        fMc = round(fMc, -1);
        vFMD = vFMDorg;
        vNonCFMD = vNonCFMDorg;
        vNonCFMD = fliplr(vNonCFMD);
        % Calculate a and b-value for GR-law and distribution vNCum
        [nIndexLo, fMagHi, vSel, vMagnitudes] = fMagToFitBValue(mCatalog, vFMD, fMc);
        if (length(mCatalog.Longitude(vSel)) >= 20)
            [ fBValue, fStdDev, fAValue] =  calc_bmemag(mCatalog.Magnitude(vSel), fBinning);
            % Normalize to time period
            vFMD(2,:) = vFMD(2,:)./fPeriod1; % ceil taken out
            vNonCFMD(2,:) = vNonCFMD(2,:)./fPeriod1; % ceil removed
            % Compute quantity of earthquakes by power law
            fMaxMagFMD = max(vNonCFMD(1,:));
            fMinMagFMD = min(vNonCFMD(1,:));
            vMstep = [fMinMagFMD:0.1:fMaxMagFMD];
            vNCum = 10.^(fAValue-fBValue.*vMstep); % Cumulative number

            % Compute non-cumulative numbers vN
            fNCumTmp = 10^(fAValue-fBValue*(fMaxMagFMD+0.1));
            vNCumTmp  = [vNCum fNCumTmp ];
            vN = abs(diff(vNCumTmp));

            % Normalize vN
            vN = vN./fPeriod1;
            % Data selection
            % mData = Non-cumulative FMD values from GR-law and original data
            mData = [vN' vNonCFMD'];
            vSel = (mData(:,2) >= fMc);
            mDataTest = mData(~vSel,:);
            mDataTmp = mData.subset(vSel);
            %         % Check for zeros in observed data
            vSelCheck = (mDataTest(:,3) == 0);
            mDataTest = mDataTest(~vSelCheck,:);
            % Choices of normalization
            fNmax = mDataTmp(1,3); % Frequency of events in Mc bin
            %fNmax = max(mDataTest(:,3));  % Use maximum frequency of events in bins below Mc
            %fNmax = mDataTest(length(mDataTest(:,1)),3); % Use frequency of events at bin Mc-0.1 -> best fit
            if (~isempty(isempty(fNmax)) &&  ~isnan(fNmax) & fNmax ~= 0 & length(mDataTest(:,1)) > 4)
                mDataTest(:,3) = mDataTest(:,3)/fNmax; % Normalize datavalues for fitting with CDF
                % Move to M=0 to fit with lsq-algorithm
                fMinMagTmp = min(mDataTest(:,2));
                mDataTest(:,2) = mDataTest(:,2)-fMinMagTmp;
                % Curve fitting: Non cumulative part below Mc
                options = optimset;
                %options = optimset('Display','off','Tolfun',1e-7,'TolX',0.0001,'MaxFunEvals', 100000,'MaxIter',10000);
                options = optimset('Display','off','Tolfun',1e-5,'TolX',0.001,'MaxFunEvals', 1000,'MaxIter',1000);
                [vX, resnorm, resid, exitflag, output, lambda, jacobian]=lsqcurvefit(@calc_normalCDF,[fSmu  fSSigma], mDataTest(:,2), mDataTest(:,3),[],[],options);
                mDataTest(:,1) = normcdf(mDataTest(:,2), vX(1), vX(2))*fNmax;
                if (length(mDataTest(:,2)) > length(vX(1,:)))
                    %% Confidence interval determination
                    % vPred : Predicted values of lognormal function
                    % vPred+-delta : 95% confidence level of true values
                    [vPred,delta] = nlpredci(@calc_normalCDF,mDataTest(:,2),vX, resid, jacobian);
                else
                    vPred = NaN;
                    delta = NaN;
                end; % END: This section is due for errors produced with datasets less long than amount of parameters in vX
                % Results of fitting procedure
                mFitRes = [mFitRes; vX resnorm exitflag];
                % Move back to original magnitudes
                mDataTest(:,2) = mDataTest(:,2)+fMinMagTmp;
                % Set data together
                mDataTest(:,3) = mDataTest(:,3)*fNmax;
                mDataPred = [mDataTest; mDataTmp];
                % Denormalize to calculate probabilities
                mDataPred(:,1) = round(mDataPred(:,1).*fPeriod1);
                mDataPred(:,3) = mDataPred(:,3).*fPeriod1;
                vProb_ = calc_log10poisspdf2(mDataPred(:,3), mDataPred(:,1)); % Non-cumulative

                % Sum the probabilities
                fProbability = (-1) * sum(vProb_);
                vProbability = [vProbability; fProbability];
                % Move magnitude back
                mDataPred(:,2) = mDataPred(:,2)+fMinMag;
                vMc = [vMc; fMc];
                vABValue = [vABValue; fAValue fBValue];

                % Keep values
                vDeltaBest = [vDeltaBest; delta];
                vX_res = [vX_res; vX resnorm exitflag];
                vNmaxBest = [vNmaxBest; fNmax];

                % Keep best fitting model
                if (fProbability == min(vProbability))
                    vDeltaBest = delta;
                    vPredBest = [mDataTest(:,2) vPred*fNmax*fPeriod1 delta*fNmax*fPeriod1]; % Gives back uncertainty
                    %fMc+fMinMag : Test procedure
                    mDatPredBest = [mDataPred];
                end
            else
                %disp('Not enough data');
                % Setting values
                fProbability = NaN;
                fMc = NaN;
                vX(1) = NaN;
                vX(2) = NaN;
                resnorm = NaN;
                exitflag = NaN;
                delta = NaN;
                vPred = [NaN NaN NaN];
                fNmax = NaN;
                fAValue = NaN;
                fBValue = NaN;
                vProbability = [vProbability; fProbability];
                vMc = [vMc; fMc];
                vX_res = [vX_res; vX resnorm exitflag];
                %             vDeltaBest = [vDeltaBest; NaN];
                %             vPredBest = [vPredBest; NaN NaN NaN];
                vNmaxBest = [vNmaxBest; fNmax];
                vABValue = [vABValue; fAValue fBValue];
            end; % END of IF fNmax
        end; % END of IF length(mCatalog.Longitude(vSel))

        % Clear variables
        vNCumTmp = [];
        mModelDat = [];
        vNCum = [];
        vSel = [];
        mDataTest = [];
        mDataPred = [];
    end; % END of FOR fMc
    % Result matrix
    mResult = [mResult; vProbability vMc vX_res vNmaxBest vABValue];

    % Find best estimate, excluding the case of mResult all NAN
    if  ~isempty(min(mResult))
        if ~isnan(min(mResult(:,1)))
            vSel = find(min(mResult(:,1)) == mResult(:,1));
            fMc = min(mResult(vSel,2));
            fMls = min(mResult(vSel,1));
            fMu = min(mResult(vSel,3));
            fSigma = min(mResult(vSel,4));
            fAvalue = min(mResult(vSel,8));
            fBvalue = min(mResult(vSel,9));
        else
            fMc = NaN;
            fMls = NaN;
            fMu = NaN;
            fSigma = NaN;
            fAvalue = NaN;
            fBvalue = NaN;
        end
    else
        fMc = NaN;
        fMls = NaN;
        fMu = NaN;
        fSigma = NaN;
        fAvalue = NaN;
        fBvalue = NaN;
    end
end


classdef RMMEDA_F2 < PROBLEM
% <multi> <real> <large/none>
% Benchmark MOP for testing RM-MEDA

%------------------------------- Reference --------------------------------
% Q. Zhang, A. Zhou, and Y. Jin, RM-MEDA: A regularity model-based
% multiobjective estimation of distribution algorithm, IEEE Transactions on
% Evolutionary Computation, 2008, 12(1): 41-63.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    methods
        %% Default settings of the problem
        function Setting(obj)
            obj.M = 2;
            if isempty(obj.D); obj.D = 30; end
            obj.lower    = zeros(1,obj.D);
            obj.upper    = ones(1,obj.D);
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values
        function PopObj = CalObj(obj,X)
            g = 1 + 9*mean((X(:,2:end)-repmat(X(:,1),1,size(X,2)-1)).^2,2);
            PopObj(:,1) = X(:,1);
            PopObj(:,2) = g.*(1-(PopObj(:,1)./g).^2);
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            R(:,1) = linspace(0,1,N)';
            R(:,2) = 1 - R(:,1).^2;
        end
        %% Generate the image of Pareto front
        function R = GetPF(obj)
            R = obj.GetOptimum(100);
        end
    end
end


function V = LR_sort(W)
N = size(W, 2);
LLR = zeros(1, N);
for i = 1 : N
    if (W(1, i) ~= 0) && (W(2, i) ~= 0)
        LLR(i) = log(W(1, i)) - log(W(2, i));
    else
        if (W(1, i) == 0) && (W(2, i) ~= 0)
            LLR(i) = -inf;
        else
            if (W(1, i) ~= 0) && (W(2, i) == 0)
                LLR(i) = inf;
            end
        end
    end
end
[~, ordered]  = sort(LLR, 'descend');
V = W(:, ordered);
end


function phiFaceAverage = upwindMean3D(phi, u)
% This function gets the value of the field variable phi defined
% over the MeshStructure and calculates the upwind average on
% the cell faces, based on the direction of the velocity vector for a uniform mesh.
%
% SYNOPSIS:
%   phiFaceAverage = upwindMean3D(phivar, u)
%
% PARAMETERS:
%
%
% RETURNS:
%
%
% EXAMPLE:
%
% SEE ALSO:
%

% Written by Ali A. Eftekhari
% See the license file

% extract the velocity data
% note: size(ux) = [1:m+1, 1:n] and size(uy) = [1:m, 1:n+1]
ux = u.xvalue;
uy = u.yvalue;
uz = u.zvalue;

% check the size of the variable and the mesh dimension
Nxyz = phi.domain.dims;
Nx = Nxyz(1); Ny = Nxyz(2); Nz = Nxyz(3);

% assign to a temp variable for boundary corrections
phi_tmp = phi.value;

% correct the value of phi at the boundary (calculation trick)
% assign the value of the left boundary to the left ghost cells
phi_tmp(1,:,:) = (phi.value(1,:,:)+phi.value(2,:,:))/2;
% assign the value of the right boundary to the right ghost cells
phi_tmp(end,:,:) = (phi.value(end,:,:)+phi.value(end-1,:,:))/2;
% assign the value of the bottom boundary to the bottom ghost cells
phi_tmp(:,1,:) = (phi.value(:,1,:)+phi.value(:,2,:))/2;
% assign the value of the top boundary to the top ghost cells
phi_tmp(:,end,:) = (phi.value(:,end,:)+phi.value(:,end-1,:))/2;
% assign the value of the back boundary to the back ghost cells
phi_tmp(:,:,1) = (phi.value(:,:,1)+phi.value(:,:,2))/2;
% assign the value of the front boundary to the front ghost cells
phi_tmp(:,:,end) = (phi.value(:,:,end)+phi.value(:,:,end-1))/2;

% calculate the average value
xvalue = (ux>0).*phi_tmp(1:Nx+1,2:Ny+1,2:Nz+1)+ ...
                        (ux<0).*phi_tmp(2:Nx+2,2:Ny+1,2:Nz+1)+ ...
                        0.5*(ux==0).*(phi.value(1:Nx+1,2:Ny+1,2:Nz+1)+phi.value(2:Nx+2,2:Ny+1,2:Nz+1));
yvalue = (uy>0).*phi_tmp(2:Nx+1,1:Ny+1,2:Nz+1)+ ...
                        (uy<0).*phi_tmp(2:Nx+1,2:Ny+2,2:Nz+1)+ ...
                        0.5*(uy==0).*(phi.value(2:Nx+1,1:Ny+1,2:Nz+1)+phi.value(2:Nx+1,2:Ny+2,2:Nz+1));
zvalue = (uz>0).*phi_tmp(2:Nx+1,2:Ny+1,1:Nz+1)+ ...
                        (uz<0).*phi_tmp(2:Nx+1,2:Ny+1,2:Nz+2)+ ...
                        0.5*(uz==0).*(phi.value(2:Nx+1,2:Ny+1,1:Nz+1)+phi.value(2:Nx+1,2:Ny+1,2:Nz+2));
phiFaceAverage=FaceVariable(phi.domain, xvalue, yvalue, zvalue);


function [stats] = est_checkMVARStability(varargin)
%
% Test the stability of a fitted VAR model. See [1-2] for mathematical
% details on testing VAR stability. A stable VAR process is also a
% stationary VAR process [2].
%
% Inputs:
%
%   EEG:        EEGLAB data structure
%   MODEL:      SIFT MODEL structure
%   typeproc:   reserved for future use. Use 0
%
% Optional:
%
%   <Name,Value> pairs containing model fitting parameters. See
%   est_fitMVAR(). Generally, these should be left unspecified.
%
% Outputs:
%
%   stats
%       .stability:  [numwindows x 1] vector of results of stability tests. 1
%                    indicates stable VAR process for that window, 0 indicates
%                    an unstable VAR process.
%
%       .lambda:     [numwindows x nchs*morder] matrix of eigenvalues of VAR
%                    process. All eigenvalues should be < 1 for stable VAR process
%
%
% [1] Mullen T (2010) The Source Information Flow Toolbox (SIFT):
%     Theoretical Handbook and User Manual. Chapters 3,6.
%     Available at: http://www.sccn.ucsd.edu/wiki/Sift
% [2] Lutkepohl, H. (2007) New Introduction to Time Series Analysis.
%     Springer.
%
% Author: Tim Mullen 2010, SCCN/INC, UCSD
% Email:  tim@sccn.ucsd.edu

% This function is part of the Source Information Flow Toolbox (SIFT)
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

g = arg_define([0 2],varargin, ...
        arg_norep({'EEG','ALLEEG'},mandatory,[],'EEGLAB dataset'), ...
        arg_norep({'MODEL','Model'},mandatory,[],'MVAR MODEL object'), ...
        arg_nogui({'winStartIdx','WindowStartIndices'},[],[],'Starting indices for windows. This is a vector of sample points (start of windows) at which to estimate windowed VAR model. Default is empty (use all windows)','cat','Options'), ...
        arg({'prctWinToSample','WindowSamplePercent'},100,[1 100],'Percent of windows to sample','cat','Options'), ...
        arg({'verb','VerbosityLevel'},2,{int32(0) int32(1) int32(2)},'Verbosity level. 0 = no output, 1 = text, 2 = graphical') ...
        );

% commit EEG and MODEL variables to workspace
[data g] = hlp_splitstruct(g,{'EEG','MODEL'});
arg_toworkspace(data);
clear data;

morder = MODEL.morder;

% window size in points
% winLenPnts = floor(MODEL.winlen*EEG.srate);

if isempty(g.winStartIdx)
    % starting point of each window (points)
    g.winStartIdx  = round(MODEL.winStartTimes*EEG.srate)+1;
end

if g.prctWinToSample<100
    % randomly select percentage of windows to work with
    randwin = randperm(length(g.winStartIdx));
    randwin = sort(randwin(1:ceil(length(g.winStartIdx)*g.prctWinToSample/100)));
    g.winStartIdx = g.winStartIdx(randwin);
    g.winArrayIndex = randwin;
end

% get the array indices of the windows we are working with
g.winArrayIndex = getindex(MODEL.winStartTimes,(g.winStartIdx-1)/EEG.srate);

% initialize waitbar
if g.verb==2
    waitbarTitle = sprintf('Checking stability %s...', ...
        fastif(isempty(EEG.condition),'',['for ' EEG.condition]));

    multiWaitbar(waitbarTitle,'Reset');
    multiWaitbar(waitbarTitle,'ResetCancel',true);
    multiWaitbar(waitbarTitle, ...
                 'Color', hlp_getNextUniqueColor, ...
                 'CanCancel','on', ...
                 'CancelFcn',@(a,b) disp('[Cancel requested. Please wait...]'));
end

numWins = length(g.winStartIdx);

stats.stability = zeros(1,numWins);
[nchs Mp] = size(MODEL.AR{1});
stats.lambda = zeros(numWins,Mp);
%lambda = [];
I = eye(nchs*morder-nchs,nchs*morder-nchs);
O = zeros(nchs*morder-nchs,nchs);
for t=1:numWins
    % get the array index of the window we are working with
    winArrIdx = g.winArrayIndex(t);

    % rewrite VAR[p] process as VAR[1]
    A = [MODEL.AR{winArrIdx} ; [I O]];
    stats.lambda(t,:) = log(abs(eig(A)));
    stats.stability(t) = all(stats.lambda(t,:)<0);

    if g.verb==2
        % update waitbar
        drawnow;
        cancel = multiWaitbar(waitbarTitle,t/numWins);
        if cancel && hlp_confirmWaitbarCancel(waitbarTitle)
            stats = [];
            return;
        end
    end

end

stats.winStartIdx = g.winStartIdx;
stats.winStartTimes = MODEL.winStartTimes(g.winArrayIndex);
stats.winArrayIndex = g.winArrayIndex;

% clean up
if g.verb==2
    multiWaitbar(waitbarTitle,'Close');
end


function [v,y,w]=nearnonz(x,d)
%NEARNONZ replace each zero element with the nearest non-zero element [V,Y,W]=nearnonz(X,D)
%
%  Inputs:  x         input vector, matrix or larger array
%           d         dimension to apply filter along [default 1st non-singleton]
%
% Outputs:  v         v is the same size as x but with each zero entry replaced by
%                     the nearest non-zero value along dimension d
%                     elements equidistant from two non-zero entries will be taken
%                     from the higher index
%           y         y is the same size as x and gives the index along dimension d
%                     from which the corresponding entry in v was taken
%                     If there are no non-zero entries, then the corresponding
%                     elements of y will be zero.
%           w         w is the same size as x and gives the distance (+ or -) to the
%                     nearest non-zero entry in x

%      Copyright (C) Mike Brookes 1997
%      Version: $Id: nearnonz.m 713 2011-10-16 14:45:43Z dmb $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   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 can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
e=size(x);
p=prod(e);
if nargin<2             % if no dimension given, find the first non-singleton
    d=find(e>1,1);
    if ~numel(d)
        d=1;
    end
end
k=e(d);                 % size of active dimension
q=p/k;                  % size of remainder
if d==1
    z=reshape(x,k,q);
else
    z=shiftdim(x,d-1);
    r=size(z);
    z=reshape(z,k,q);
end
xx=z~=0;
cx=cumsum(xx);
[i,j]=find(z);
qq=cx(xx);
pos=full(sparse(qq,j,i,k,q)); % list the positions of non-zero elements in each column
mp=ceil((pos(1:end-1,:)+pos(2:end,:))*0.5); % find the mid point between consecutive non-zero elements
[i2,j2]=find(pos(2:end,:)>0);
zz=1+cumsum(full(sparse(mp(pos(2:end,:)>0),j2,1,k,q)));
y=pos(zz+repmat((0:q-1)*k,k,1));
v=z(max(y,1)+repmat((0:q-1)*k,k,1));
w=y-repmat((1:k)',1,q);
w(y==0)=0;
if d==1
    y=reshape(y,e);
    v=reshape(v,e);
    w=reshape(w,e);
else
    y=shiftdim(reshape(y,r),length(e)+1-d);
    v=shiftdim(reshape(v,r),length(e)+1-d);
    w=shiftdim(reshape(w,r),length(e)+1-d);
end


function element_node = grid_q16_element ( nelemx, nelemy )

%*****************************************************************************80
%
%% GRID_Q16_ELEMENT produces a grid of 16 node quadrilaterals.
%
%  Example:
%
%    Input:
%
%      NELEMX = 2, NELEMY = 2
%
%    Output:
%
%      ELEMENT_NODE =
%         1,  2,  3,  4,  8,  9, 10, 11, 15, 16, 17, 18, 22, 23, 24, 25;
%         4,  5,  6,  7, 11, 12, 13, 14, 18, 19, 20, 21, 25, 26, 27, 28;
%        22, 23, 24, 25, 29, 30, 31, 32, 36, 37, 38, 39, 43, 44, 45, 46;
%        25, 26, 27, 28, 32, 33, 34, 35, 39, 40, 41, 42, 46, 47, 48, 49.
%
%  Grid:
%
%   43-44-45-46-47-48-49
%    |        |        |
%    |        |        |
%   36 37 38 39 40 41 42
%    |        |        |
%    |        |        |
%   29 30 31 32 33 34 35
%    |        |        |
%    | 3      | 4      |
%   22-23-24-25-26-27-28
%    |        |        |
%    |        |        |
%   15 16 17 18 19 20 21
%    |        |        |
%    |        |        |
%    8  9 10 11 12 13 14
%    |        |        |
%    | 1      | 2      |
%    1--2--3--4--5--6--7
%
%  Reference Element Q16:
%
%    |
%    1 13--14--15--16
%    |  |   :   :   |
%    |  |   :   :   |
%    |  9..10..11..12
%    S  |   :   :   |
%    |  |   :   :   |
%    |  5...6...7...8
%    |  |   :   :   |
%    |  |   :   :   |
%    0  1---2---3---4
%    |
%    +--0-----R-----1-->
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 April 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer NELEMX, NELEMY, the number of elements along the
%    X and Y directions.  The number of elements generated will be
%    NELEMX * NELEMY.
%
%    Output, integer ELEMENT_NODE(16,NELEMX*NELEMY), the nodes that form
%    each element.
%
  element = 0;

  for j = 1 : nelemy
    for i = 1 : nelemx

      base = ( j - 1 ) * 3 * ( 3 * nelemx + 1 ) + 3 * i - 2;

      element = element + 1;

      element_node( 1,element) = base;
      element_node( 2,element) = base                          + 1;
      element_node( 3,element) = base                          + 2;
      element_node( 4,element) = base                          + 3;
      element_node( 5,element) = base +     ( 3 * nelemx + 1 );
      element_node( 6,element) = base +     ( 3 * nelemx + 1 ) + 1;
      element_node( 7,element) = base +     ( 3 * nelemx + 1 ) + 2;
      element_node( 8,element) = base +     ( 3 * nelemx + 1 ) + 3;
      element_node( 9,element) = base + 2 * ( 3 * nelemx + 1 );
      element_node(10,element) = base + 2 * ( 3 * nelemx + 1 ) + 1;
      element_node(11,element) = base + 2 * ( 3 * nelemx + 1 ) + 2;
      element_node(12,element) = base + 2 * ( 3 * nelemx + 1 ) + 3;
      element_node(13,element) = base + 3 * ( 3 * nelemx + 1 );
      element_node(14,element) = base + 3 * ( 3 * nelemx + 1 ) + 1;
      element_node(15,element) = base + 3 * ( 3 * nelemx + 1 ) + 2;
      element_node(16,element) = base + 3 * ( 3 * nelemx + 1 ) + 3;

    end
  end

  return
end


%% Niblack Image Thresholding
% Sample to compare Niblack thresholding against other algorithms
% (global thresholding and adaptive thresholding) for an image with varying
% illumination.
%
% Sources:
%
% * <https://github.com/opencv/opencv_contrib/blob/3.2.0/modules/ximgproc/samples/niblack_thresholding.cpp>
% * <https://docs.opencv.org/3.2.0/d7/d4d/tutorial_py_thresholding.html>
%

function niblack_thresholding_demo()
    % Input 8-bit grayscale image + Parameters
    % - BS: block size (local neighborhood) [niblack, adaptive]
    % - K : constant multiplied by std dev next subtracted from mean [niblack]
    % - C : constant subtracted from mean [adaptive]
    if ~mexopencv.isOctave() && mexopencv.require('images')
        % image with dark pixels being foreground
        im = which('printedtext.png');
        K = -0.7;
        C = 7;
    elseif true
        % image with dark pixels being foreground
        im = fullfile(mexopencv.root(),'test','sudoku.jpg');
        K = -0.7;
        C = 7;
    elseif ~mexopencv.isOctave() && mexopencv.require('images')
        % image with white pixels being foreground
        im = which('rice.png');
        K = 0.7;
        C = -17;
    end
    assert(~isempty(im) && exist(im, 'file') == 2);
    img = cv.imread(im, 'Grayscale',true);
    BS = min(floor(size(img)/16) * 2 + 1);
    assert(~isempty(img), 'Failed to load image');

    % Preprocess image
    if true
        % no processing
        src = img;
    elseif false
        src = cv.medianBlur(img, 'KSize',3);
    elseif true
        % really effective for global thresholding [otsu]
        src = localNormalization(img, 11, 33);
    else
        % rice image, estimate and subtract non-uniform illumination background
        % (see NonuniformIlluminationExample.mlx example)
        if mexopencv.require('images')
            src = imtophat(img, strel('disk',15));
            src = imadjust(src);
        else
            el = cv.getStructuringElement('Shape','Ellipse', 'KSize',[15 15]*2-1);
            src = cv.morphologyEx(img, 'Tophat', 'Element',el);
            obj = cv.SimpleWB();
            src = obj.balanceWhite(src);
        end
    end

    % Threshold
    opts = {'Type','Binary', 'MaxValue',255};
    bw1 = cv.threshold(src, 'Otsu', opts{:});
    bw2 = cv.adaptiveThreshold(src, 'Method','Mean', ...
        'C',C, 'BlockSize',BS, opts{:});
    bw3 = cv.adaptiveThreshold(src, 'Method','Gaussian', ...
        'C',C, 'BlockSize',BS, opts{:});
    bw4 = cv.niBlackThreshold(src, K, 'Method','Niblack', ...
        'BlockSize',BS, opts{:});
    bw5 = cv.niBlackThreshold(src, -K, 'Method','Sauvola', ...
        'BlockSize',BS, opts{:});
    bw6 = cv.niBlackThreshold(src, -K, 'Method','Wolf', ...
        'BlockSize',BS, opts{:});
    bw7 = cv.niBlackThreshold(src, K, 'Method','Nick', ...
        'BlockSize',BS, opts{:});
    %bw8 = my_niblack(src, K, BS);

    % Results
    subplot(331), imshow(img), title('Source')
    subplot(332), imshow(src), title('Processed')
    subplot(333), imshow(bw1), title('Otsu')
    subplot(334), imshow(bw2), title('Adaptive Mean')
    subplot(335), imshow(bw3), title('Adaptive Gaussian')
    subplot(336), imshow(bw4), title('Niblack')
    subplot(337), imshow(bw5), title('Sauvola')
    subplot(338), imshow(bw6), title('Wolf')
    subplot(339), imshow(bw7), title('Nick')
end

%% Helper function

function out = localNormalization(img, s1, s2)
    %LOCALNORMALIZATION  local normalization to get uniform local mean and variance
    %
    %     out = localNormalization(img)
    %     out = localNormalization(img, s1, s2)
    %
    % The local normalization tends to uniformize the mean and variance of an
    % image around a local neighborhood. This is especially useful for correct
    % non-uniform illumination or shading artifacts.
    %
    % ## Input
    % * __img__ 8-bit input image
    %
    % ## Output
    % * __out__ output image of same size and type.
    %
    % ## Options
    % * __s1__ sigma to estimate the local mean. default 5
    % * __s2__ sigma to estimate the local variance. Often `s2` should be
    %   larger than `s1`. default 15
    %
    % ## References
    % > http://bigwww.epfl.ch/sage/soft/localnormalization/
    %

    % check arguments
    if nargin < 2, s1 = 5; end
    if nargin < 3, s2 = 15; end
    validateattributes(img, {'uint8'}, {});

    % convert to grayscale
    if size(img,3) == 3
        gray = cv.cvtColor(img, 'RGB2GRAY');
    else
        gray = img;
    end

    % convert to floating-point image
    gray = cv.convertTo(gray, 'RType','single', 'Alpha',1.0/255.0);

    % numerator = img - gauss_blur(img)
    blur = cv.GaussianBlur(gray, 'KSize',[0 0], 'SigmaX',s1, 'SigmaY',s1);
    num = gray - blur;

    % denominator = sqrt(gauss_blur(img^2))
    den = sqrt(cv.GaussianBlur(num.^2, 'KSize',[0 0], 'SigmaX',s2, 'SigmaY',s2));

    % output = numerator / denominator
    out = num ./ den;

    % normalize output into [0,1]
    out = cv.normalize(out, 'Alpha',0.0, 'Beta',1.0, 'NormType','MinMax');

    % convert to 8-bit
    out = cv.convertTo(out, 'RType','uint8', 'Alpha',255.0);
end

function bw = my_niblack(img, K, BS)
    %MY_NIBLACK  Manual implementation of Niblack thresholding

    img = im2double(img);
    mu = imboxfilt(img, [BS BS]);
    sd = sqrt(imboxfilt(img.^2, [BS BS]) - mu.^2);
    bw = img > (mu + K*sd);
end


function gen_hermite_poly_test ( )

%******************************hermite****************************************80
%
%% GEN_HERMITE_POLY_TEST tests GEN_HERMITE_POLY.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 February 2015
%
%  Author:
%
%    John Burkardt
%
  i_test = 6;
  n = 10;

  mu_test = [ 0.0, 0.0, 0.1, 0.1, 0.5, 1.0 ];
  x_test = [ 0.0, 1.0, 0.0, 0.5, 0.5, 0.5 ];

  fprintf ( 1, '\n' );
  fprintf ( 1, 'GEN_HERMITE_POLY_TEST\n' );
  fprintf ( 1, '  GEN_HERMITE_POLY evaluates the generalized Hermite \n' );
  fprintf ( 1, '  polynomials.\n' );

  for i = 1 : i_test

    x = x_test(i);
    mu = mu_test(i);

    fprintf ( 1, '\n' );
    fprintf ( 1, '  Table of L(N,MU)(X) for\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '    N(max) = %d\n', n );
    fprintf ( 1, '    MU =     %f\n', mu );
    fprintf ( 1, '    X =      %f\n', x );
    fprintf ( 1, '\n' );

    c = gen_hermite_poly ( n, x, mu );

    for j = 0 : n
      fprintf ( 1, '  %4d  %12f\n', j, c(j+1) );
    end

  end

  return
end


function t = ktensor(varargin)
%KTENSOR Tensor stored as a Kruskal operator (decomposed).
%
%   K = KTENSOR(lambda,U1,U2,...,UM) creates a Kruskal tensor from its
%   constituent parts. Here lambda is a k-vector and each Um is a
%   matrix with k columns.
%
%   K = KTENSOR(lambda, U) is the same as above except that U is a
%   cell array containing matrix Um in cell m.
%
%   K = KTENSOR(U) assumes U is a cell array containing matrix Um in
%   cell m and assigns the weight of each factor to be one.
%
%   K = KTENSOR(T) creates a ktensor by copying an existing ktensor.
%
%   Examples
%   K = ktensor([3; 2], rand(4,2), rand(5,2), rand(3,2))
%
%   See also TENSOR, TTENSOR, KTENSOR/FULL.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

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

% EMPTY CONSTRUCTOR
if nargin == 0
    t.lambda = [];
    t.u = {};
    t = class(t,'ktensor');
    return;
end

% Copy CONSTRUCTOR
if (nargin == 1) && isa(varargin{1}, 'ktensor')
    t.lambda = varargin{1}.lambda;
    t.u = varargin{1}.u;
    t = class(t, 'ktensor');
    return;
end

if isa(varargin{1},'cell')

    u = varargin{1};
    t.lambda = ones(size(u{1},2),1);
    t.u = u;

else

    t.lambda = varargin{1};
    if ~isa(t.lambda,'numeric') || ndims(t.lambda) ~=2 || size(t.lambda,2) ~= 1
	error('LAMBDA must be a column vector.');
    end

    if isa(varargin{2},'cell')
	t.u = varargin{2};
    else
	for i = 2 : nargin
	    t.u{i-1} = varargin{i};
	end
    end

end

% Check that each Um is indeed a matrix
for i = 1 : length(t.u)
    if ndims(t.u{i}) ~= 2
	error(['Matrix U' int2str(i) ' is not a matrix!']);
    end
end

% Size error checking
k = length(t.lambda);
for i = 1 : length(t.u)
    if  size(t.u{i},2) ~= k
       error(['Matrix U' int2str(i) ' does not have ' int2str(k) ' columns.']);
    end
end

t = class(t, 'ktensor');
return;


function UNew = fluidDirichlet3D(varargin);
% fluidDirichlet3D: solve fluid registraion in 3D with Dirichlet
%        boundary conditions
%
%
% author: Nathan D. Cahill
% email: nathan.cahill@rit.edu
% affiliation: Rochester Institute of Technology
% date: January 2014
% licence: GNU GPL v3
%
% Copyright Nathan D. Cahill
% Code available from https://github.com/tomdoel/npReg
%
%

% parse input arguments
[DU,F,mu,lambda,PixSize,M,N,P,RegularizerFactor,HX,HY,HZ] = parse_inputs(varargin{:});

% multiply F by adjoint of Navier-Lame equations
FNew = adjointNL(F/RegularizerFactor,mu,lambda,0,M,N,P);

% compute sine transform of new force field
FS = discreteSineTransform(FNew,M,N,P);

% construct images of coordinates scaled by pi/(N or M or P)
[a,b,c] = ndgrid(pi*(0:(M-1))/(M-1),pi*(0:(N-1))/(N-1),pi*(0:(P-1))/(P-1));

% construct LHS factor
LHSfactor = mu.*(lambda+2*mu).*(2*cos(a) + 2*cos(b) + 2*cos(c) - 6).^2;

% if gamma is zero, set origin term to 1, as DC term does not matter
LHSfactor(1,1,1) = 1;

% solve for FFT of U
VS = cat(4,FS(:,:,:,1)./LHSfactor,FS(:,:,:,2)./LHSfactor,FS(:,:,:,3)./LHSfactor);

% perform inverse DST
V = discreteSineTransform(VS,M,N,P);

% now perform Euler integration to construct new displacements
UNew = zeros(M,N,P,3);
UNew(:,:,:,1) = (1 - imfilter(V(:,:,:,1),HX,'replicate','same')).*V(:,:,:,1) - ...
    imfilter(V(:,:,:,2),HY,'replicate','same').*V(:,:,:,2) - ...
    imfilter(V(:,:,:,3),HZ,'replicate','same').*V(:,:,:,3);
UNew(:,:,:,2) = -imfilter(V(:,:,:,1),HY,'replicate','same').*V(:,:,:,1) + ...
    (1 - imfilter(V(:,:,:,2),HY,'replicate','same')).*V(:,:,:,2) - ...
    imfilter(V(:,:,:,3),HY,'replicate','same').*V(:,:,:,3);
UNew(:,:,:,3) = -imfilter(V(:,:,:,1),HZ,'replicate','same').*V(:,:,:,1) - ...
    imfilter(V(:,:,:,2),HZ,'replicate','same').*V(:,:,:,2) + ...
    (1 - imfilter(V(:,:,:,3),HZ,'replicate','same')).*V(:,:,:,3);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function FS = discreteSineTransform(F,M,N,P);
% compute discrete sine transform of 3-D vector field

% initialize resulting array
FS = F;

% first perform sine transform down columns
len = 2*M-2; ind = 1:M;
for p=1:P
    for n=1:N
        s = fft(FS(:,n,p,:),len,1);
        FS(:,n,p,:) = imag(s(ind,:,:,:));
    end
end
FS = sqrt(2/(M-1))*FS;

% next perform sine transform across rows
len = 2*N-2; ind = 1:N;
for p=1:P
    for m=1:M
        s = fft(FS(m,:,p,:),len,2);
        FS(m,:,p,:) = imag(s(:,ind,:,:));
    end
end
FS = sqrt(2/(N-1))*FS;

% finally perform sine transform across pages
len = 2*P-2; ind = 1:P;
for n=1:N
    for m=1:M
        s = fft(FS(m,n,:,:),len,3);
        FS(m,n,:,:) = imag(s(:,:,ind,:));
    end
end
FS = sqrt(2/(P-1))*FS;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function FNew = adjointNL(F,mu,lambda,gamma,M,N,P);
% multiply vector field F by adjoint Navier-Lame equations

% initialize FNew
FNew = zeros(M,N,P,3);

% construct filter that implements 3-D Laplacian
L = (lambda+2*mu)*cat(3,[0 0 0;0 1 0;0 0 0],[0 1 0;1 -6 1;0 1 0],[0 0 0;0 1 0;0 0 0]);

% we will need to use L to form two different filters
% L1 = -(lambda+2*mu)*L; L1(2,2,2) = gamma + L1(2,2,2);
% L2 = -mu*L; L2(2,2,2) = gamma + L2(2,2,2);

% construct grad div filters
GD11 = (lambda+mu)*cat(3,zeros(3,3),[0 1 0;0 -2 0;0 1 0],zeros(3,3));
GD22 = ipermute(GD11,[2 1 3]);
GD33 = ipermute(GD11,[3 2 1]);
GD23 = zeros(3,3,3);
GD23(2,1,1) = 1; GD23(2,3,3) = 1; GD23(2,1,3) = -1; GD23(2,3,1) = -1;
GD23 = GD23*(lambda+mu)/4;
GD12 = ipermute(GD23,[3 1 2]);
GD13 = ipermute(GD23,[2 3 1]);

% perform filtering
FNew(:,:,:,1) = imfilter(F(:,:,:,1),L-GD11,'replicate') + ...
    imfilter(F(:,:,:,2),-GD12,'replicate') + ...
    imfilter(F(:,:,:,3),-GD13,'replicate');
FNew(:,:,:,2) = imfilter(F(:,:,:,1),-GD12,'replicate') + ...
    imfilter(F(:,:,:,2),L-GD22,'replicate') + ...
    imfilter(F(:,:,:,3),-GD23,'replicate');
FNew(:,:,:,3) = imfilter(F(:,:,:,1),-GD13,'replicate') + ...
    imfilter(F(:,:,:,2),-GD23,'replicate') + ...
    imfilter(F(:,:,:,3),L-GD33,'replicate');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [DU,F,mu,lambda,PixSize,M,N,P,RegularizerFactor,HX,HY,HZ] = parse_inputs(varargin);

% get displacement field and check size
F = varargin{2};
PixSize = varargin{4}(1:3);
M = varargin{5};
N = varargin{6};
P = varargin{7};
mu = varargin{8};
lambda = varargin{9};
RegularizerFactor = varargin{10};
DU = varargin{11};
HX = varargin{12};
HY = varargin{13};
HZ = varargin{14};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


classdef ZDT3 < PROBLEM
% <multi> <real> <large/none> <expensive/none>
% Benchmark MOP proposed by Zitzler, Deb, and Thiele

%------------------------------- Reference --------------------------------
% E. Zitzler, K. Deb, and L. Thiele, Comparison of multiobjective
% evolutionary algorithms: Empirical results, Evolutionary computation,
% 2000, 8(2): 173-195.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    methods
        %% Default settings of the problem
        function Setting(obj)
            obj.M = 2;
            if isempty(obj.D); obj.D = 30; end
            obj.lower    = zeros(1,obj.D);
            obj.upper    = ones(1,obj.D);
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values
        function PopObj = CalObj(obj,PopDec)
            PopObj(:,1) = PopDec(:,1);
            g = 1 + 9*mean(PopDec(:,2:end),2);
            h = 1 - (PopObj(:,1)./g).^0.5 - PopObj(:,1)./g.*sin(10*pi*PopObj(:,1));
            PopObj(:,2) = g.*h;
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            R(:,1) = linspace(0,1,N)';
            R(:,2) = 1 - R(:,1).^0.5 - R(:,1).*sin(10*pi*R(:,1));
            R      = R(NDSort(R,1)==1,:);
        end
        %% Generate the image of Pareto front
        function R = GetPF(obj)
            R(:,1) = linspace(0,1,100)';
            R(:,2) = 1 - R(:,1).^0.5 - R(:,1).*sin(10*pi*R(:,1));
            R(NDSort(R,1)>1,:) = nan;
        end
    end
end


classdef UF1 < PROBLEM
% <multi> <real> <large/none>
% Unconstrained benchmark MOP

%------------------------------- Reference --------------------------------
% Q. Zhang, A. Zhou, S. Zhao, P. N. Suganthan, W. Liu, and S. Tiwari,
% Multiobjective optimization test instances for the CEC 2009 special
% session and competition, School of CS & EE, University of Essex, Working
% Report CES-487, 2009.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    methods
        %% Default settings of the problem
        function Setting(obj)
            obj.M = 2;
            if isempty(obj.D); obj.D = 30; end
            obj.lower    = [0,zeros(1,obj.D-1)-1];
            obj.upper    = ones(1,obj.D);
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values
        function PopObj = CalObj(obj,X)
            J1 = 3 : 2 : obj.D;
            J2 = 2 : 2 : obj.D;
            Y  = X - sin(6*pi*repmat(X(:,1),1,obj.D)+repmat(1:obj.D,size(X,1),1)*pi/obj.D);
            PopObj(:,1) = X(:,1)         + 2*mean(Y(:,J1).^2,2);
            PopObj(:,2) = 1-sqrt(X(:,1)) + 2*mean(Y(:,J2).^2,2);
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            R(:,1) = linspace(0,1,N)';
            R(:,2) = 1 - R(:,1).^0.5;
        end
        %% Generate the image of Pareto front
        function R = GetPF(obj)
        	R = obj.GetOptimum(100);
        end
    end
end


function suborder_num = dunavant_suborder_num ( rule )

%*****************************************************************************80
%
%% DUNAVANT_SUBORDER_NUM returns the number of suborders for a Dunavant rule.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 December 2006
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    David Dunavant,
%    High Degree Efficient Symmetrical Gaussian Quadrature Rules
%    for the Triangle,
%    International Journal for Numerical Methods in Engineering,
%    Volume 21, 1985, pages 1129-1148.
%
%    James Lyness, Dennis Jespersen,
%    Moderate Degree Symmetric Quadrature Rules for the Triangle,
%    Journal of the Institute of Mathematics and its Applications,
%    Volume 15, Number 1, February 1975, pages 19-32.
%
%  Parameters:
%
%    Input, integer RULE, the index of the rule.
%
%    Output, integer SUBORDER_NUM, the number of suborders of the rule.
%
  suborder = [ ...
     1,  1 , 2,  2,  3,  3,  4,  5,  6,  6, ...
     7,  8, 10, 10, 11, 13, 15, 17, 17, 19 ];

  if ( 1 <= rule & rule <= 20 )
    suborder_num = suborder(rule);
  else

    suborder_num = -1;
    fprintf ( 1, '\n' );
    fprintf ( 1, 'DUNAVANT_SUBORDER_NUM - Fatal error!\n' );
    fprintf ( 1, '  Illegal RULE = %d\n', rule );
    error ( 'DUNAVANT_SUBORDER_NUM - Fatal error!\n' )

  end

  return
end


function x = blend_rst_2dn ( r, s, t, n, bound_rst )

%*****************************************************************************80
%
%% BLEND_RST_2DN extends vector data on faces into a cube.
%
%  Diagram:
%
%    010-----r10-----110        011-----r11-----111
%      |       .       |          |       .       |
%      |       .       |          |       .       |
%    0s0.....rs0.....1s0        0s1.....rs1.....1s1     S
%      |       .       |          |       .       |     |
%      |       .       |          |       .       |     |
%    000-----r00-----100        001-----r01-----101     +----R
%           BOTTOM                      TOP
%
%    011-----0s1-----001        111-----1s1-----101
%      |       .       |          |       .       |
%      |       .       |          |       .       |
%    01t.....0st.....00t        11t.....1st.....10t          T
%      |       .       |          |       .       |          |
%      |       .       |          |       .       |          |
%    010-----0s0-----000        110-----1s0-----100     S----+
%           LEFT                       RIGHT
%
%    001-----r01-----101        011-----r11-----111
%      |       .       |          |       .       |
%      |       .       |          |       .       |
%    00t.....r0t.....100        01t.....r1t.....11t     T
%      |       .       |          |       .       |     |
%      |       .       |          |       .       |     |
%    000-----r00-----100        010-----r10-----110     +----R
%           FRONT                       BACK
%
%  Discussion:
%
%    BLEND_RST_2DN is NOT equivalent to a trilinear finite element
%    method, since the data is sampled everywhere along the corners,
%    edges, and faces, rather than at a finite number of nodes.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 October 2008
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    William Gordon,
%    Blending-Function Methods of Bivariate and Multivariate Interpolation
%    and Approximation,
%    SIAM Journal on Numerical Analysis,
%    Volume 8, Number 1, March 1971, pages 158-177.
%
%    William Gordon and Charles Hall,
%    Transfinite Element Methods: Blending-Function Interpolation over
%    Arbitrary Curved Element Domains,
%    Numerische Mathematik,
%    Volume 21, Number 1, 1973, pages 109-129.
%
%    William Gordon and Charles Hall,
%    Construction of Curvilinear Coordinate Systems and Application to
%    Mesh Generation,
%    International Journal of Numerical Methods in Engineering,
%    Volume 7, 1973, pages 461-477.
%
%    Joe Thompson, Bharat Soni, Nigel Weatherill,
%    Handbook of Grid Generation,
%    CRC Press, 1999.
%
%  Parameters:
%
%    Input, real R, S, T, the (R,S,T) coordinates of the point
%    to be evaluated.
%
%    Input, integer N, the dimension of the vector space.
%
%    External, BOUND_RST, is a function which is given (R,S,T)
%    coordinates and an component value I, and returns XI, the value
%    of the I-th component of the N-vector at that point.  BOUND_RST
%    will only be called for "faces", that is, for values (R,S,T) where
%    at least one of R, S and T is either 0.0 or 1.0.  BOUND_RST has
%    the form:
%      function xi = bound_rst ( r, s, t, i )
%
%    Output, real X(N), the interpolated value at the
%    point (R,S,T).
%
  for i = 1 : n
%
%  Get the I-th coordinate component at the corners.
%
    x000 = bound_rst ( 0.0, 0.0, 0.0, i );
    x001 = bound_rst ( 0.0, 0.0, 1.0, i );
    x010 = bound_rst ( 0.0, 1.0, 0.0, i );
    x011 = bound_rst ( 0.0, 1.0, 1.0, i );
    x100 = bound_rst ( 1.0, 0.0, 0.0, i );
    x101 = bound_rst ( 1.0, 0.0, 1.0, i );
    x110 = bound_rst ( 1.0, 1.0, 0.0, i );
    x111 = bound_rst ( 1.0, 1.0, 1.0, i );
%
%  Get the I-th coordinate component at the edges.
%
    xr00 = bound_rst ( r, 0.0, 0.0, i );
    xr01 = bound_rst ( r, 0.0, 1.0, i );
    xr10 = bound_rst ( r, 1.0, 0.0, i );
    xr11 = bound_rst ( r, 1.0, 1.0, i );

    x0s0 = bound_rst ( 0.0, s, 0.0, i );
    x0s1 = bound_rst ( 0.0, s, 1.0, i );
    x1s0 = bound_rst ( 1.0, s, 0.0, i );
    x1s1 = bound_rst ( 1.0, s, 1.0, i );

    x00t = bound_rst ( 0.0, 0.0, t, i );
    x01t = bound_rst ( 0.0, 1.0, t, i );
    x10t = bound_rst ( 1.0, 0.0, t, i );
    x11t = bound_rst ( 1.0, 1.0, t, i );
%
%  Get the I-th component on the faces.
%
    x0st = bound_rst ( 0.0, s, t, i );
    x1st = bound_rst ( 1.0, s, t, i );
    xr0t = bound_rst ( r, 0.0, t, i );
    xr1t = bound_rst ( r, 1.0, t, i );
    xrs0 = bound_rst ( r, s, 0.0, i );
    xrs1 = bound_rst ( r, s, 1.0, i );
%
%  Interpolate the I-th coordinate component of the interior point.
%
    x(i) = blend_123 ( r, s, t, x000, x001, x010, x011, x100, x101, x110, x111, ...
      xr00, xr01, xr10, xr11, x0s0, x0s1, x1s0, x1s1, x00t, x01t, x10t, x11t, ...
      x0st, x1st, xr0t, xr1t, xrs0, xrs1 );

  end

  return
end


function brnd = betarand(a,b,r,c)
%  BETARAND Random matrices from beta distribution.
%     R = BETARAND(A,B) returns an array of random numbers chosen from the
%     beta distribution with parameters A and B.  The size of R is the common
%     size of A and B if both are arrays.  If either parameter is a scalar,
%     the size of R is the size of the other parameter.
%
%     R = BETARAND(A,B,M,N) returns an M-by-N matrix.

% Copyright (c) 1995-1997, 2005-2007 Kurt Hornik

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.
if (nargin > 1)
  if (~isscalar(a) || ~isscalar(b))
    if (size(a,1) ~= size(b,1))
      error ('betarnd: a and b must be of common size or scalar');
    end
  end
end

if (nargin == 4)
  if (~(isscalar(r) && (r > 0) && (r == round(r))))
    error ('betarnd: r must be a positive integer');
  end
  if (~(isscalar (c) && (c > 0) && (c == round (c))))
    error ('betarnd: c must be a positive integer');
  end
  sz = [r, c];

  if (any (size (a) ~= 1) && (length (size (a)) ~= length (sz) || any (size (a) ~= sz)))
    error ('betarnd: a and b must be scalar or of size [r,c]');
  end
elseif (nargin == 3)
  if (isscalar (r) && (r > 0))
    sz = [r, r];
  elseif (isvector(r) && all (r > 0))
    sz = r(:)';
  else
    error ('betarnd: r must be a positive integer or vector');
  end

  if (any (size (a) ~= 1) && (length (size (a)) ~= length (sz) || any (size (a) ~= sz)))
    error ('betarnd: a and b must be scalar or of size sz');
  end
elseif (nargin == 2)
  sz = size(a);
else
  error('must provide atleast 2 parameters')
end

if (isscalar(a) && isscalar(b))
  if (find ((a < 0) | isinf(a) | (b < 0) | isinf(b)))
    brnd = NaN * ones (sz);
  else
    r1 = gamrand(a,2.*a,sz(1),sz(2));
    brnd = r1 ./ (r1 + gamrand(b,2.*b,sz(1),sz(2)));
  end
else
  brnd = zeros (sz);

  k = find ((a < 0) | isinf(a) | (b < 0) | isinf(b));
  if (any (k))
    brnd(k) = NaN * ones (size (k));
  end

  k = find ((a > 0) & (a < Inf) & (b > 0) & (b < Inf));
  if (any (k))
    r1 = gamrnd(a(k),1,size(k,1),size(k,2));
    brnd(k) = r1 ./ (r1 + gamrnd(b(k),1,size(k,1),size(k,2)));
  end
end

end


% LFBuild4DFreqHyperfan - construct a 4D hyperfan passband filter in the frequency domain
%
% Usage:
%
%     [H, FiltOptions] = LFBuild4DFreqHyperfan( LFSize, Slope1, Slope2, BW, FiltOptions )
%     H = LFBuild4DFreqHyperfan( LFSize, Slope1, Slope2, BW )
%
% This file constructs a real-valued magnitude response in 4D, for which the passband is a hyperfan.
% This is useful for selecting objects over a range of depths from a lightfield, i.e. volumetric
% focus.
%
% Once constructed the filter must be applied to a light field, e.g. using LFFilt4DFFT. The
% LFDemoBasicFilt* files demonstrate how to contruct and apply frequency-domain filters.
%
% A more technical discussion, including the use of filters for denoising and volumetric focus, and
% the inclusion of aliases components, is included in:
%
% [2] D.G. Dansereau, O. Pizarro, and S. B. Williams, "Linear Volumetric Focus for Light Field
% Cameras," to appear in ACM Transactions on Graphics (TOG), vol. 34, no. 2, 2015.
%
% Inputs:
%
%     LFSize : Size of the frequency-domain filter. This should match or exceed the size of the
%     light field to be filtered. If it's larger than the input light field, the input is
%     zero-padded to match the filter's size by LFFilt4DFFT.
%
%     Slope : The slope of the planar passband. If different slopes are desired in s,t and u,v,
%     the optional aspect parameter should be used.
%
%     BW : 3-db Bandwidth of the planar passband.
%
%     [optional] FiltOptions : struct controlling filter construction
%            HyperfanMethod : 'sweep' or 'direct', controls how the hyperfan is constructed. 'sweep'
%                             concatenates frequency planes, while 'direct' evaluates a single 4D
%                             equation; default 'direct'. Warning: sweep can be very slow.
%               HyperconeBW : Sets the underlying hypercone's BW separately from the dual-fan,
%                             default is to use the BW parameter for both; only applies when
%                             HyperfanMethod is 'direct'
%               SlopeMethod : 'Skew' or 'Rotate' default 'skew'
%                 Precision : 'single' or 'double', default 'single'
%                   Rolloff : 'Gaussian' or 'Butter', default 'Gaussian'
%                     Order : controls the order of the filter when Rolloff is 'Butter', default 3
%                  Aspect4D : aspect ratio of the light field, default [1 1 1 1]
%                    Window : Default false. By default the edges of the passband are sharp; this adds
%                             a smooth rolloff at the edges when used in conjunction with Extent4D or
%                             IncludeAliased.
%                  Extent4D : controls where the edge of the passband occurs, the default [1 1 1 1]
%                             is the edge of the Nyquist box. When less than 1, enabling windowing
%                             introduces a rolloff after the edge of the passband. Can be greater
%                             than 1 when using IncludeAliased.
%            IncludeAliased : default false; allows the passband to wrap around off the edge of the
%                             Nyquist box; used in conjunction with Window and/or Extent4D. This can
%                             increase processing time dramatically, e.g. Extent4D = [2,2,2,2]
%                             requires a 2^4 = 16-fold increase in time to construct the filter.
%                             Useful when passband content is aliased, see [2].
%                SweepSteps : For HyperfanMethod 'sweep', how many steps to use in the sweep.
%
% Outputs:
%
%                 H : real-valued frequency magnitude response
%       FiltOptions : The filter options including defaults, with an added PassbandInfo field
%                     detailing the function and time of construction of the filter
%
% User guide: LFToolbox.pdf
% See also:  LFDemoBasicFiltGantry, LFDemoBasicFiltIllum, LFDemoBasicFiltLytroF01,
% LFBuild2DFreqFan, LFBuild2DFreqLine, LFBuild4DFreqDualFan, LFBuild4DFreqHypercone,
% LFBuild4DFreqHyperfan, LFBuild4DFreqPlane, LFFilt2DFFT, LFFilt4DFFT, LFFiltShiftSum

% Copyright (c) 2013-2020 Donald G. Dansereau

function [H, FiltOptions] = LFBuild4DFreqHyperfan( LFSize, Slope1, Slope2, BW, FiltOptions )

FiltOptions = LFDefaultField('FiltOptions', 'HyperfanMethod', 'Direct'); % 'Direct', 'Sweep'

switch( lower(FiltOptions.HyperfanMethod ))
	case 'sweep'
		FiltOptions = LFDefaultField('FiltOptions', 'SweepSteps', 5);
		SweepVec = linspace(Slope1, Slope2, FiltOptions.SweepSteps);
		[H, FiltOptions] = LFBuild4DFreqPlane( LFSize, SweepVec(1), BW, FiltOptions );
		for( CurSlope = SweepVec(2:end) )
			H = max(H, LFBuild4DFreqPlane( LFSize, CurSlope, BW, FiltOptions ));
		end

	case 'direct'
		FiltOptions = LFDefaultField('FiltOptions', 'HyperconeBW', BW);
		[H, FiltOptions] = LFBuild4DFreqHypercone( LFSize, FiltOptions.HyperconeBW, FiltOptions );
		[Hdf, FiltOptions] = LFBuild4DFreqDualFan( LFSize, Slope1, Slope2, BW, FiltOptions );
		H = H .* Hdf;

	otherwise
		error('Unrecognized hyperfan construction method');
end

TimeStamp = datestr(now,'ddmmmyyyy_HHMMSS');
FiltOptions.PassbandInfo = struct('mfilename', mfilename, 'time', TimeStamp, 'VersionStr', LFToolboxVersion);


function [ x, status ] = p00_newton ( problem, option, nvar, x, par_index )

%*****************************************************************************80
%
%% P00_NEWTON applies Newton's method to an approximate root.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer PROBLEM, the problem index.
%
%    Input, integer OPTION, the option index.
%
%    Input, integer NVAR, the number of variables.
%
%    Input, real X(NVAR), the starting point of Newton's method.
%
%    Input, integer PAR_INDEX, the index of the parameter to be held fixed.
%    This variable should be between 1 and NVAR.  However, the user can
%    set it to 0, indicating that the program should make an intelligent
%    choice for the index.
%
%    Output, real X(NVAR), an improved estimate of the root of F(X)=0.
%
%    Output, integer STATUS, the status of the iteration.
%    -3, the full number of steps was taken without convergence.
%        (however, the output X might be CLOSE to a good solution).
%    -2, the iteration seemed to be diverging, and was halted.
%    -1, the jacobian was singular, and the iteration was halted.
%     nonnegative, the convergence test was satisfied, and this is the
%        number of steps taken (possibly 0).
%
  COND_MAX = 1.0E+10;
  FX_ABS_TOL = 0.000001;
  IT_MAX = 20;
  VERBOSE = 0;

  x = x(:);

  if ( par_index < 1 | nvar < par_index )
    par_index = p00_par_index ( problem, option, nvar, x );
    if ( VERBOSE )
      fprintf ( 1, '\n' );
      fprintf ( 1, '  Iteration will hold index %d fixed.\n', par_index );
    end
  end
  par_value = x(par_index);

  if ( VERBOSE )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'P00_NEWTON\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '      Step    ||F(X)||\n' );
    fprintf ( 1, '\n' );
  end

  for it = 0 : IT_MAX
%
%  Compute the function value.
%
    fx = p00_fun ( problem, option, nvar, x );
    fx(nvar) = x(par_index) - par_value;
%
%  Compute the norm of the function value.
%
    fx_max = max ( abs ( fx(1:nvar) ) );

    if ( VERBOSE )
      fprintf ( 1, '  %8d  %14e\n', it, fx_max );
    end

    if ( it == 0 )
      fx_max_init = fx_max;
    end
%
%  If the function norm is small enough, return.
%
    if ( abs ( fx_max ) < FX_ABS_TOL )
      status = it;
      break
    end
%
%  If the function norm seems to be exploding, halt.
%
    if ( 1000.0 * fx_max_init < abs ( fx_max ) )
      status = -2;
      break
    end

    if ( it == IT_MAX )
      status = -3;
      break
    end
%
%  Compute the jacobian.
%
    jac = p00_jac ( problem, option, nvar, x );

    jac(nvar,1:nvar) = 0.0;
    jac(nvar,par_index) = 1.0;
%
%  Solve the system JAC * DX = - FX
%
    if ( cond ( jac ) < COND_MAX )
      dx = - jac \ fx;
    else
      if ( VERBOSE )
        fprintf ( 1, '  (Using pseudoinverse.)\n' );
      end
      dx = - pinv ( jac ) * fx;
    end
%
%  Update X = X - DX.
%
    x(1:nvar) = x(1:nvar) + dx(1:nvar);

  end

  return
end


function Ainv = incremental_invert(Pinv,Q,S)
%
%   Computes the new inverse of a symmetric matrix from an old submatrix inverse and the new parts.
%
%   So if   A = [P,Q;Q',S] incremental_invert gets inv(P) , Q and S and
%   returns inv(A)
%
%

if isempty(S) && isempty(Q)
    Ainv = Pinv; return
end

Qt = Q';
M = S-Qt*Pinv*Q;
Minv = pinv(M);

Ptmp = Pinv + Pinv*Q*Minv*Qt*Pinv;
Qtmp = -Pinv*Q*Minv;

Ainv = [Ptmp,Qtmp;Qtmp',Minv];


% This is material illustrating the methods from the book
% Financial Modelling  - Theory, Implementation and Practice with Matlab
% source
% Wiley Finance Series
% ISBN 978-0-470-74489-5
%
% Date: 02.05.2012
%
% Authors:  Joerg Kienitz
%           Daniel Wetterau
%
% Please send comments, suggestions, bugs, code etc. to
% kienitzwetterau_FinModelling@gmx.de
%
% (C) Joerg Kienitz, Daniel Wetterau
%
% Since this piece of code is distributed via the mathworks file-exchange
% it is covered by the BSD license
%
% This code is being provided solely for information and general
% illustrative purposes. The authors will not be responsible for the
% consequences of reliance upon using the code or for numbers produced
% from using the code.

clear; clc;
%% Parameters
S = 100;                                   % Spot prices
T = 5;      % maturities

r = 0;                      % discount factors
d = 0;                              % dividends

titS = 'MC NIG CIR - Asset Paths';

legend_base = 'Base scenario';

alpha = 10;
beta = -3;                            % CEV exponent base scenario
delta = 1;
mu = 0;
lambda = 2;
kappa = 1;
eta = 0.5;

%% Simulation parameters
NTime = 120; NSim = 1; NBatches = 1;
NTime_clock = 10;
K = ones(NTime+1,1);
K = T*cumsum(K)/(NTime+1);
K1 = K(2:end);

rstream = RandStream('mt19937ar','Seed',12345);
rstreamstate = rstream.State;

PathS = MC_NIGCIR(S,r,d,T,alpha,beta,delta,kappa,eta,lambda,NTime,NSim,NBatches);
%% Changing lambda
lambda_low = 1;
lambda_high = 3;

    rstream.State = rstreamstate;
    PathS_low = MC_NIGCIR(S,r,d,T,alpha,beta,delta,kappa,eta,lambda_low,NTime,NSim,NBatches);
    rstream.State = rstreamstate;
    PathS_high = MC_NIGCIR(S,r,d,T,alpha,beta,delta,kappa,eta,lambda_high,NTime,NSim,NBatches);

legend_low = 'Changing \lambda low';
legend_high = 'Changing \lambda high';

createfigure_path(K,PathS_low, PathS, PathS_high, titS, legend_low, legend_base, legend_high);

% calculate the returns
ReturnsS1_low = calcreturns(PathS_low,0);
ReturnsS1 = calcreturns(PathS,0);
ReturnsS1_high = calcreturns(PathS_high,0);

createfigure_returns(K1,ReturnsS1_low, ReturnsS1, ReturnsS1_high, titS, legend_low, legend_base, legend_high);

%% Changing kappa
kappa_low = 0.5;
kappa_high = 2;

    rstream.State = rstreamstate;
    PathS_low = MC_NIGCIR(S,r,d,T,alpha,beta,delta,kappa_low,eta,lambda,NTime,NSim,NBatches);
    rstream.State = rstreamstate;
    PathS_high = MC_NIGCIR(S,r,d,T,alpha,beta,delta,kappa_high,eta,lambda,NTime,NSim,NBatches);

legend_low = 'Changing \kappa low';
legend_high = 'Changing \kappa high';

createfigure_path(K,PathS_low, PathS, PathS_high, titS, legend_low, legend_base, legend_high);

% calculate the returns
ReturnsS1_low = calcreturns(PathS_low,0);
ReturnsS1 = calcreturns(PathS,0);
ReturnsS1_high = calcreturns(PathS_high,0);

createfigure_returns(K1,ReturnsS1_low, ReturnsS1, ReturnsS1_high, titS, legend_low, legend_base, legend_high);

%% Changing eta
eta_low = 0.25;
eta_high = 0.75;

    rstream.State = rstreamstate;
    PathS_low = MC_NIGCIR(S,r,d,T,alpha,beta,delta,kappa,eta_low,lambda,NTime,NSim,NBatches);
    rstream.State = rstreamstate;
    PathS_high = MC_NIGCIR(S,r,d,T,alpha,beta,delta,kappa,eta_high,lambda,NTime,NSim,NBatches);

legend_low = 'Changing \eta low';
legend_high = 'Changing \eta high';

createfigure_path(K,PathS_low, PathS, PathS_high, titS, legend_low, legend_base, legend_high);

% calculate the returns
ReturnsS1_low = calcreturns(PathS_low,0);
ReturnsS1 = calcreturns(PathS,0);
ReturnsS1_high = calcreturns(PathS_high,0);

createfigure_returns(K1,ReturnsS1_low, ReturnsS1, ReturnsS1_high, titS, legend_low, legend_base, legend_high);

clear; clc;


function node = meshsmoothing(node,elem,step,rho,method,fixedNode)
%% MESHSMOOTHING improves the geometric mesh quality
%
% node = meshsmoothing(node,elem) improves shape regularity of
% triangles while keeping the density of vertices.
%
% node = meshsmoothing(node,elem,m) performs m steps mesh smoothing.
% The default setting is m=3.
%
% node = meshsmoothing(node,elem,m,rho) accept a non-uniform density
% given by elementwise function rho. The default choice rho = 1/|t|. The
% quasi-uniform grids corresponds to rho=1. The density function rho can be
% given by a user specified function or a posteriori error estimator in the
% setting of adaptive finite element method.
%
% node = meshsmoothing(node,elem,m,rho,method,fixedNode) accept the
% extra input arguments method and fixedNode. The string |method| is to
% specify the smoothing method: either 'CPT' or 'ODT'. The fixedNode array
% will fix certain nodes, e.g., vertices on a interface. The boundary nodes
% of the mesh will be automatically considered as fixed.
%
% The function meshsmoothing will keep the topology of the input mesh,
% i.e., the node index and connectivity of nodes are unchanged. In
% contrast, the edgeswap function will keep the node but change elem.
%
% The algorithm implemented is the simplified version of ODT smoothing; see
% ODTmesh.
%
% Example:
%     load airfoilperturbmesh
%     meshquality(node,elem);
%     node = meshsmoothing(node,elem);
%     meshquality(node,elem);
%
% See also  optmesh, bdsmoothing, edgeswap, rmisopoint
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

if ~exist('step','var'), step = 3; end
if ~exist('method','var'), method = 'ODT'; end

%% Smooth boundary nodes
% [node,elem,bdNode] = bdsmoothing(node,elem);

%% Find boundary and interior ndoes
[bdNode,bdEdge,isBdNode,isBdElem] = findboundary(elem); %#ok<*ASGLU>
N = size(node,1);  NT = size(elem,1);

%% Compute mesh quality associated to elements and nodes
qt = 1 - simpqual(node,elem);
qtp = sparse([1:NT,1:NT,1:NT], elem(1:NT,:), [qt, qt, qt], NT, N);
qp = max(qtp);
qp = qp' + 0.01*rand(N,1);  % break the equal case
qp(bdNode) = 0;             % do not include bdNode and fixed nodes
if exist('fixedNode','var'), qp(fixedNode) = 0; end

%% Decompose nodes into independent sets
t2p = sparse([1:NT,1:NT,1:NT], elem(1:NT,:), 1, NT, N);
A = t2p'*t2p;  % connectness of nodes
nodeSet = coloring(A,5,qp);

%% Move nodes one by one
for m = 1:step
    for k = 1:5
        % find elements containing nodeSet
        movingNode = nodeSet{k};
        if isempty(movingNode)
            break;
        end
        [i,j] = find(t2p(:,movingNode)); %#ok<*NASGU>
        idx = false(NT,1);
        idx(i) = true;
        idx = find(idx);
        % compute centers and areas
        switch upper(method)
          case 'CPT'
               center = (node(elem(idx,1),:)+node(elem(idx,2),:)+node(elem(idx,3),:))/3;
          case 'ODT'
               center = circumcenter(node,elem(idx,:));
               % modification neary boundary elements: using barycenter to replace circumcenter
               center(isBdElem(idx),:) = (node(elem(idx(isBdElem(idx)),1),:) ...
                                        + node(elem(idx(isBdElem(idx)),2),:) ...
                                        + node(elem(idx(isBdElem(idx)),3),:))/3;
        end
        % compute the weight
        if exist('rho','var') && ~isempty(rho)
            weight = simplexvolume(node,elem(idx,:));
            if (rho~=1)
                weight = rho(idx).*weight;
            end
        end
        % update to new averaging center
        oldpi = node(movingNode,:);     % keep the location before moving
        if exist('rho','var') && ~isempty(rho) % weighted average
            newnode(:,1) = accumarray([elem(idx,1);elem(idx,2);elem(idx,3)],...
                                repmat(weight.*center(:,1),3,1),[N,1]);
            newnode(:,2) = accumarray([elem(idx,1);elem(idx,2);elem(idx,3)],...
                                repmat(weight.*center(:,2),3,1),[N,1]);
            valence = accumarray([elem(idx,1);elem(idx,2);elem(idx,3)], ...
                                 [weight; weight; weight],[N 1]);
        else % simple average of centers
            newnode(:,1) = accumarray([elem(idx,1);elem(idx,2);elem(idx,3)],...
                                      [center(:,1);center(:,1);center(:,1)],[N,1]);
            newnode(:,2) = accumarray([elem(idx,1);elem(idx,2);elem(idx,3)],...
                                      [center(:,2);center(:,2);center(:,2)],[N,1]);
            valence = accumarray([elem(idx,1);elem(idx,2);elem(idx,3)],...
                                  ones(3*length(idx),1),[N 1]);
        end
        node(movingNode,:) = newnode(movingNode,:)./[valence(movingNode) valence(movingNode)];
        % check if the moving is valid
        ve2 = node(elem(idx,1),:)-node(elem(idx,3),:);
        ve3 = node(elem(idx,2),:)-node(elem(idx,1),:);
        area = 0.5*(-ve3(:,1).*ve2(:,2)+ve3(:,2).*ve2(:,1));
        invalidElem = idx(area<0);
        if any(invalidElem)
            isNotmoving = false(N,1);
            isNotmoving(elem(invalidElem,:)) = true;
            pidx = isNotmoving(movingNode);
            node(movingNode(pidx),:) = oldpi(pidx,:);
        end
    end
end


classdef prtKernelRbfNeighborhoodScaled < prtKernel
    % prtKernelRbfNeighborhoodScaled  Radial basis function kernel where
    % each entry is scaled according to the distance to neighbors in the
    % training set.
    %
    %  KERNOBJ = prtKernelRbfNeighborhoodScaled Generates a kernel object
    %  implementing a radial basis function.  Kernel objects are widely
    %  used in several prt classifiers, such as prtClassRvm and
    %  prtClassSvm.  RBF kernels implement the following function for 1 x N
    %  vectors x1 and x2:
    %
    %   k(x1,x2) = exp(-sum((x1-x2).^2)./sigma1.^2);
    %
    %  sigma1 is learned based on the neighboord of the data in
    %  feature space.
    %
    %  KERNOBJ = prtKernelRbfNeighborhoodScaled(PROPERTY1, VALUE1, ...) constructs a
    %  prtKernelRbfNeighborhoodScaled object KERNOBJ with properties as specified by
    %  PROPERTY/VALUE pairs. prtKernelRbfNeighborhoodScaled objects have the following
    %  user-settable properties:
    %
    %   neighborhoodPercentile - Quantile distance that is used to define
    %       the neighboorhood. THis is a value between 1 and 100. Smaller
    %       values will make more local kernels. (Default value is 5)
    %
    %   prtKernelRbf objects inherit the TRAIN and RUN methods from prtKernel.
    %
    %   % Example
    %   ds = prtDataGenMoon;                     % Generate a dataset
    %   k1 = prtKernelRbfNeighborhoodScaled;    % Create a prtKernel object with
    %                                            % default value of neighborhoodPercentile
    %   k2 = prtKernelRbfNeighborhoodScaled('neighborhoodPercentile',2); % Create a prtKernel object with
    %                                                                     % the specified value of neighborhoodPercentile
    %
    %   k1 = k1.train(ds); % Train
    %   g1 = k1.run(ds); % Evaluate
    %
    %   k2 = k2.train(ds); % Train
    %   g2 = k2.run(ds); % Evaluate
    %
    %   subplot(2,1,1); imagesc(g1.getObservations);  %Plot the results
    %   subplot(2,1,2); imagesc(g2.getObservations);
    %
    %   See also: prtKernel,prtKernelSet, prtKernelDc, prtKernelRbf, prtKernelDirect,
    %   prtKernelHyperbolicTangent, prtKernelPolynomial,
    %   prtKernelRbfNdimensionScale,

    properties (SetAccess = private)
        name = 'RBF Kernel Scaled'; % RBF Kernel Scaled
        nameAbbreviation = 'RBF'; % RBF
    end

    properties
        neighborhoodPercentile = 5;
        sigmas = []; % The inverse kernel width for each dimension
    end

    methods (Access = protected, Hidden = true)
        function Obj = trainAction(Obj,ds)
            Obj.internalDataSet = ds;

            D = prtDistanceEuclidean(ds,ds);
            D = sort(D,'ascend');

            nPointsAway = min(max(round(size(D,1)*Obj.neighborhoodPercentile/100),1),size(D,1));

            Obj.sigmas = sqrt(D(nPointsAway,:))';
            Obj.sigmas(Obj.sigmas<=0) = 1; % Put weird values to 1

            Obj.isTrained = true;
        end

        function dsOut = runAction(Obj,ds)
            if ~Obj.isTrained
                error('prtKernelRbfNeighboorhoodScaled:run','Attempt to run an untrained kernel; use kernel.train(ds) to train');
            end
            if Obj.internalDataSet.nObservations == 0
                dsOut = prtDataSetClass;
            else
                gram = prtKernelRbfNeighborhoodScaled.kernelFn(ds.getObservations,Obj.internalDataSet.getObservations,Obj.sigmas);
                dsOut = ds.setObservations(gram);
            end
        end
    end

    methods
        function Obj = prtKernelRbfNeighborhoodScaled(varargin)
            Obj = prtUtilAssignStringValuePairs(Obj,varargin{:});
        end
    end

    methods(Hidden = true)
        function Obj = retainKernelDimensions(Obj,keepLogical)
            Obj.sigmas = Obj.sigmas(keepLogical);
            Obj = retainKernelDimensions@prtKernel(Obj,keepLogical);
        end

        function varargout = plot(obj)
            x = obj.internalDataSet.getObservations;

            if size(x,2) <= 3
                if size(x,2) == 1 && obj.internalDataSet.isLabeled
                    xy = cat(2,x,obj.internalDataSet.getTargets);
                    h = prtPlotUtilScatter(xy, {}, obj.plotOptions.symbol, obj.plotOptions.markerFaceColor, obj.plotOptions.color, obj.plotOptions.symbolLineWidth, obj.plotOptions.symbolSize);
                else
                    h = prtPlotUtilScatter(x, {}, obj.plotOptions.symbol, obj.plotOptions.markerFaceColor, obj.plotOptions.color, obj.plotOptions.symbolLineWidth, obj.plotOptions.symbolSize);
                end
            else
                h = nan;
            end

            varargout = {};
            if nargout
                varargout = {h};
            end
        end
    end

    methods (Static, Hidden = true)
        function gram = kernelFn(x,y,sigmas)
            [n1, d] = size(x);
            [n2, nin] = size(y);
            if d ~= nin
                error('size(x,2) must equal size(y,2)');
            end

            %dist2 = prtDistanceLNorm(x,y,2);
            dist2 = repmat(sum((x.^2), 2), [1 n2]) + repmat(sum((y.^2),2), [1 n1]).' - 2*x*(y.');

            if numel(sigmas) == 1
                gram = exp(-dist2/(sigmas.^2));
            else
                gram = exp(-bsxfun(@rdivide,dist2,(sigmas.^2)'));
            end
        end
    end
end


function [mGal] = mmps22mGal(mmps2)
% Convert acceleration from millimeters per square-second to milligalileos
% Chad A. Greene 2012
mGal = mmps2*1e+2;


function fused = Ying_2017_CAIP(I, mu, k, a, b) % camera a, b
%%
% @inproceedings{ying2017new,
%   title={A New Image Contrast Enhancement Algorithm Using Exposure Fusion Framework},
%   author={Ying, Zhenqiang and Li, Ge and Ren, Yurui and Wang, Ronggang and Wang, Wenmin},
%   booktitle={International Conference on Computer Analysis of Images and Patterns},
%   pages={36--46},
%   year={2017},
%   organization={Springer}
% }
%
% Please feel free to contact me (yingzhenqiang-at-gmail-dot-com) if you
% have any questions or concerns.

if  ~exist( 'mu', 'var' )
    mu = 0.5;
end

if ~exist( 'a', 'var' )
    a = -0.3293;
end

if ~exist( 'b', 'var' )
    b = 1.1258;
end

if ~isfloat(I)
    I = im2double( I );
end

lambda = 0.5;
sigma = 5;

%% t: scene illumination map
t_b = max( I, [], 3 ); % also work for single-channel image
t_our =  imresize( tsmooth( imresize( t_b, 0.5 ), lambda, sigma ), size( t_b ) );

%% k: exposure ratio
if  ~exist( 'k', 'var' ) || isempty(k)
    isBad = t_our < 0.5;
    J = maxEntropyEnhance(I, isBad);
else
    J = applyK(I, k, a, b); %k
    J = min(J, 1); % fix overflow
end

%% W: Weight Matrix
t = repmat(t_our, [1 1 size(I,3)]);
W = t.^mu;

I2 = I.*W;
J2 = J.*(1-W);

fused = I2 + J2;

    function J = maxEntropyEnhance(I, isBad)
        Y = rgb2gm(real(max(imresize(I, [50 50]), 0))); % max - avoid complex number

        if exist('isBad', 'var')
            isBad = (imresize(isBad, [50 50]));
            Y = Y(isBad);
        end

        if isempty(Y)
           J = I; % no enhancement k = 1
           return;
        end

        opt_k = fminbnd(@(k) ( -entropy(applyK(Y, k)) ),1, 7);
        J = applyK(I, opt_k, a, b) - 0.01;

    end
end

function I = rgb2gm(I)
if size(I,3) == 3
    I = im2double(max(0,I)); % negative double --> complex double
    I = ( I(:,:,1).*I(:,:,2).*I(:,:,3) ).^(1/3);
end
end

function J = applyK(I, k, a, b)

if ~exist( 'a', 'var' )
    a = -0.3293;
end

if ~exist( 'b', 'var' )
    b = 1.1258;
end

f = @(x)exp((1-x.^a)*b);
beta = f(k);
gamma = k.^a;
J = I.^gamma.*beta;
end

function S = tsmooth( I, lambda, sigma, sharpness)
if ( ~exist( 'lambda', 'var' ) )
    lambda = 0.01;
end
if ( ~exist( 'sigma', 'var' ) )
    sigma = 3.0;
end
if ( ~exist( 'sharpness', 'var' ) )
    sharpness = 0.001;
end
I = im2double( I );
x = I;
[ wx, wy ] = computeTextureWeights( x, sigma, sharpness);
S = solveLinearEquation( I, wx, wy, lambda );
end

function [ W_h, W_v ] = computeTextureWeights( fin, sigma, sharpness)

dt0_v = [diff(fin,1,1);fin(1,:)-fin(end,:)];
dt0_h = [diff(fin,1,2)';fin(:,1)'-fin(:,end)']';

gauker_h = filter2(ones(1,sigma),dt0_h);
gauker_v = filter2(ones(sigma,1),dt0_v);
W_h = 1./(abs(gauker_h).*abs(dt0_h)+sharpness);
W_v = 1./(abs(gauker_v).*abs(dt0_v)+sharpness);

end

function OUT = solveLinearEquation( IN, wx, wy, lambda )
[ r, c, ch ] = size( IN );
k = r * c;
dx =  -lambda * wx( : );
dy =  -lambda * wy( : );
tempx = [wx(:,end),wx(:,1:end-1)];
tempy = [wy(end,:);wy(1:end-1,:)];
dxa = -lambda *tempx(:);
dya = -lambda *tempy(:);
tempx = [wx(:,end),zeros(r,c-1)];
tempy = [wy(end,:);zeros(r-1,c)];
dxd1 = -lambda * tempx(:);
dyd1 = -lambda * tempy(:);
wx(:,end) = 0;
wy(end,:) = 0;
dxd2 = -lambda * wx(:);
dyd2 = -lambda * wy(:);

Ax = spdiags( [dxd1,dxd2], [-k+r,-r], k, k );
Ay = spdiags( [dyd1,dyd2], [-r+1,-1], k, k );

D = 1 - ( dx + dy + dxa + dya);
A = (Ax+Ay) + (Ax+Ay)' + spdiags( D, 0, k, k );

if exist( 'ichol', 'builtin' )
    L = ichol( A, struct( 'michol', 'on' ) );
    OUT = IN;
    for ii = 1:ch
        tin = IN( :, :, ii );
        [ tout, ~ ] = pcg( A, tin( : ), 0.1, 50, L, L' );
        OUT( :, :, ii ) = reshape( tout, r, c );
    end
else
    OUT = IN;
    for ii = 1:ch
        tin = IN( :, :, ii );
        tout = A\tin( : );
        OUT( :, :, ii ) = reshape( tout, r, c );
    end
end
end


function [P,Uinit,output] = cp_als(X,R,varargin)
%CP_ALS Compute a CP decomposition of any type of tensor.
%
%   P = CP_ALS(X,R) computes an estimate of the best rank-R
%   CP model of a tensor X using an alternating least-squares
%   algorithm.  The input X can be a tensor, sptensor, ktensor, or
%   ttensor. The result P is a ktensor.
%
%   P = CP_ALS(X,R,'param',value,...) specifies optional parameters and
%   values. Valid parameters and their default values are:
%      'tol' - Tolerance on difference in fit {1.0e-4}
%      'maxiters' - Maximum number of iterations {50}
%      'dimorder' - Order to loop through dimensions {1:ndims(A)}
%      'init' - Initial guess [{'random'}|'nvecs'|cell array]
%      'printitn' - Print fit every n iterations; 0 for no printing {1}
%
%   [P,U0] = CP_ALS(...) also returns the initial guess.
%
%   [P,U0,out] = CP_ALS(...) also returns additional output that contains
%   the input parameters.
%
%   Note: The "fit" is defined as 1 - norm(X-full(P))/norm(X) and is
%   loosely the proportion of the data described by the CP model, i.e., a
%   fit of 1 is perfect.
%
%   Examples:
%   X = sptenrand([5 4 3], 10);
%   P = cp_als(X,2);
%   P = cp_als(X,2,'dimorder',[3 2 1]);
%   P = cp_als(X,2,'dimorder',[3 2 1],'init','nvecs');
%   U0 = {rand(5,2),rand(4,2),[]}; %<-- Initial guess for factors of P
%   [P,U0,out] = cp_als(X,2,'dimorder',[3 2 1],'init',U0);
%   P = cp_als(X,2,out.params); %<-- Same params as previous run
%
%   See also KTENSOR, TENSOR, SPTENSOR, TTENSOR.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

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

%% Extract number of dimensions and norm of X.
N = ndims(X);
normX = norm(X);

%% Set algorithm parameters from input or by using defaults
params = inputParser;
params.addParamValue('tol',1e-4,@isscalar);
params.addParamValue('maxiters',50,@(x) isscalar(x) & x > 0);
params.addParamValue('dimorder',1:N,@(x) isequal(sort(x),1:N));
params.addParamValue('init', 'random', @(x) (iscell(x) || ismember(x,{'random','nvecs'})));
params.addParamValue('printitn',1,@isscalar);
params.parse(varargin{:});

%% Copy from params object
fitchangetol = params.Results.tol;
maxiters = params.Results.maxiters;
dimorder = params.Results.dimorder;
init = params.Results.init;
printitn = params.Results.printitn;

%% Error checking

%% Set up and error checking on initial guess for U.
if iscell(init)
    Uinit = init;
    if numel(Uinit) ~= N
        error('OPTS.init does not have %d cells',N);
    end
    for n = dimorder(2:end);
        if ~isequal(size(Uinit{n}),[size(X,n) R])
            error('OPTS.init{%d} is the wrong size',n);
        end
    end
else
    % Observe that we don't need to calculate an initial guess for the
    % first index in dimorder because that will be solved for in the first
    % inner iteration.
    if strcmp(init,'random')
        Uinit = cell(N,1);
        for n = dimorder(2:end)
            Uinit{n} = rand(size(X,n),R);
        end
    elseif strcmp(init,'nvecs') || strcmp(init,'eigs')
        Uinit = cell(N,1);
        for n = dimorder(2:end)
            Uinit{n} = nvecs(X,n,R);
        end
    else
        error('The selected initialization method is not supported');
    end
end

%% Set up for iterations - initializing U and the fit.
U = Uinit;
fit = 0;

if printitn>0
  fprintf('\nCP_ALS:\n');
end

%% Main Loop: Iterate until convergence

if (isa(X,'sptensor') || isa(X,'tensor')) && (exist('cpals_core','file') == 3)

    %fprintf('Using C++ code\n');
    [lambda,U] = cpals_core(X, Uinit, fitchangetol, maxiters, dimorder);
    P = ktensor(lambda,U);

else

    for iter = 1:maxiters

        fitold = fit;

        % Iterate over all N modes of the tensor
        for n = dimorder(1:end)

            % Calculate Unew = X_(n) * khatrirao(all U except n, 'r').
            Unew = mttkrp(X,U,n);

            % Compute the matrix of coefficients for linear system
            Y = ones(R,R);
            for i = [1:n-1,n+1:N]
                Y = Y .* (U{i}'*U{i});
            end

            % Need to figure out which of the following lines works better.
            % Meanwhile, we'll stick witht he line from TTB 2.2 since that is
            % what seems to work best based on preliminary testing.
            %Unew = Unew * pinv(Y); %<- Line from TTB 2.3.
            Unew = (Y \ Unew')'; %<- Line from TTB 2.2.

            % Normalize each vector to prevent singularities in coefmatrix
            if iter == 1
                lambda = sqrt(sum(Unew.^2,1))'; %2-norm
            else
                lambda = max( max(Unew,[],1), 1 )'; %max-norm
            end
            Unew = Unew * spdiags(1./lambda,0,R,R);
            if issparse(Unew)
                U{n} = full(Unew);   % for the case R=1
            else
                U{n} = Unew;
            end
        end

        P = ktensor(lambda,U);
        normresidual = sqrt( normX^2 + norm(P)^2 - 2 * innerprod(X,P) );
        fit = 1 - (normresidual / normX); %fraction explained by model
        fitchange = abs(fitold - fit);

        if mod(iter,printitn)==0
            fprintf(' Iter %2d: fit = %e fitdelta = %7.1e\n', iter, fit, fitchange);
        end

        % Check for convergence
        if (iter > 1) && (fitchange < fitchangetol)
            break;
        end
    end
end

%% Clean up final result
% Arrange the final tensor so that the columns are normalized.
P = arrange(P);
% Fix the signs
P = fixsigns(P);

if printitn>0
  normresidual = sqrt( normX^2 + norm(P)^2 - 2 * innerprod(X,P) );
  fit = 1 - (normresidual / normX); %fraction explained by model
  fprintf(' Final fit = %e \n', fit);
end

output = struct;
output.params = params.Results;
output.iters = iter;