function UNew = fluidPeriodic3D(varargin)
% fluidPeriodic3D: solve fluid registraion in 3D with Periodic
%        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 Fourier transform of new force field
FS = discreteFourierTransform(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 FFT
V = discreteFourierTransformInverse(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 = discreteFourierTransformInverse(F,M,N,P);
% compute inverse DFT of 3-D vector field

% initialize resulting array
FS = F;

% first perform sine transform down columns
for p=1:P
    for n=1:N
        FS(:,n,p,:) = ifft(FS(:,n,p,:),M,1,'symmetric');
    end
end

% next perform sine transform across rows
for p=1:P
    for m=1:M
        FS(m,:,p,:) = ifft(FS(m,:,p,:),N,2,'symmetric');
    end
end

% finally perform sine transform across pages
for n=1:N
    for m=1:M
        FS(m,n,:,:) = ifft(FS(m,n,:,:),P,3,'symmetric');
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function FS = discreteFourierTransform(F,M,N,P);
% compute DFT of 3-D vector field

% initialize resulting array
FS = complex(F);

% first perform sine transform down columns
for p=1:P
    for n=1:N
        FS(:,n,p,:) = fft(FS(:,n,p,:),M,1);
    end
end

% next perform sine transform across rows
for p=1:P
    for m=1:M
        FS(m,:,p,:) = fft(FS(m,:,p,:),N,2);
    end
end

% finally perform sine transform across pages
for n=1:N
    for m=1:M
        FS(m,n,:,:) = fft(FS(m,n,:,:),P,3);
    end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


close all;
num = size(AllFeature1,2);
F1 = AllFeature1' / 4000;
% F1 = max(AllFeature1(1:512,:)', AllFeature1(513:1024,:)');%(1:512,:)
% F1 = bsxfun(@minus, F1, mean(F1,1));
% F1 = bsxfun(@rdivide, F1, sqrt(sum(F1.^2,2)));

F2 = AllFeature2' / 4000;
% F2 = max(AllFeature2(1:512,:)', AllFeature2(513:1024,:)');%(1:512,:)
% F2 = bsxfun(@minus, F2, mean(F2,1));
% F2 = bsxfun(@rdivide, F2, sqrt(sum(F2.^2,2)));

thresh2 = zeros(num,1);
for i = 1:num
%     thresh2(i) = F1(i,:) * mapping.A * F1(i,:)' + F2(i,:) * mapping.A * F2(i,:)' - 2 * F1(i,:) * mapping.G * F2(i,:)';
    thresh2(i) = pdist2(F1(i,:) ./ norm(F1(i,:)),F2(i,:) ./ norm(F2(i,:)));
%     thresh2(i) = F1(i,:) * F2(i,:)';
end;
figure;
hist(thresh2(1:3000),500);
figure;
hist(thresh2(3001:end),500);

accuracies = zeros(10,1);
for i=1:10
    test_idx = [(i-1) * 300 + 1 : i*300, (i-1) * 300 + 3001 : i*300 + 3000];
    train_idx = 1:6000;
    train_idx(test_idx) = [];
    bestc=256;
    same_label = ones(6000,1);
    same_label(3001:6000) = 0;

    mean_feature = mean([F1(train_idx,:); F2(train_idx,:)]);
    std_feature = std([F1(train_idx,:); F2(train_idx,:)]);
    F1_mu = bsxfun(@minus, F1, mean_feature);
    F2_mu = bsxfun(@minus, F2, mean_feature);
%     F1_mu = bsxfun(@rdivide, F1_mu, std_feature);
%     F2_mu = bsxfun(@rdivide, F2_mu, std_feature);
    F1_mu = bsxfun(@rdivide, F1_mu, sqrt(sum(F1_mu.^2,2)));
    F2_mu = bsxfun(@rdivide, F2_mu, sqrt(sum(F2_mu.^2,2)));
    F1_mu = F1;
    F2_mu = F2;

    [U,mu,vars] = pca( [F1_mu(train_idx,:); F2_mu(train_idx,:)]' );
    sum_var = cumsum(vars);
    sum_var = sum_var / sum_var(end);
    dims = find(sum_var > 0.995, 1, 'first');
    [F1PCA,F1PCAHat,~] = pcaApply( F1_mu', U, mu, dims );
    [F2PCA,F2PCAHat,~] = pcaApply( F2_mu', U, mu, dims );
    F1PCA = bsxfun(@rdivide, F1PCA, sqrt(sum(F1PCA.^2)));
    F2PCA = bsxfun(@rdivide, F2PCA, sqrt(sum(F2PCA.^2)));

    thresh1 = zeros(num,1);
    for n = 1:num
%         thresh1(n) = pdist2(F1_mu(n,:),F2_mu(n,:));
%         thresh1(n) = pdist2(F1(n,:),F2(n,:));
        thresh1(n) = pdist2(F1PCA(:,n)',F2PCA(:,n)');
%         thresh1(n) = F1PCA(:,n)' * F2PCA(:,n);
%         thresh1(n) = F1(n,:) * F2(n,:)';
    end;
    cmd = [' -t 0 -h 0'];
    model = svmtrain(same_label(train_idx),thresh1(train_idx),cmd);
    [class, accuracy, deci] = svmpredict(same_label(test_idx),thresh1(test_idx),model);
%     [~, threshold_fold] = Sys_accuracy(thresh1(train_idx(1:2700)), thresh1(train_idx(2701:5400)));
%     accuracy = (sum(thresh1(test_idx(1:300)) < threshold_fold) + sum(thresh1(test_idx(301:600)) >= threshold_fold)) / 600;
    fprintf('%d th-fold accuracy:%.4f\n', i, accuracy(1));
    accuracies(i) = accuracy(1);
end;
fprintf('(PCA)accuracy by 10-fold evalution:%.4f\r\n', mean(accuracies));
cmd = [' -t 0 -h 0'];
model = svmtrain(same_label,thresh2,cmd);
[class, accuracy, deci] = svmpredict(same_label,thresh2,model);
% mean(thresh2(same_label==1)) / 4 + mean(max(0,1 - thresh2(same_label==0))) / 4
% sum((thresh2<0.22) == same_label) / 6000
% [accuracy, threshold] = Sys_accuracy(thresh2(same_label==1), thresh2(same_label==0));
% fprintf('(Without PCA)accuracy by direct evalution:%.4f, threshold:%.4f\r\n', accuracy, threshold);


% rigid registration of frames with offsets ds
function dreg = rigidRegFrames(data, ops, ds)

% compute maximum batch size for GPU
[h, w, nFrames] = size(data);
if getOr(ops, 'useGPU', 0)
    nFramesPerBatch = getBatchSize(w*h);
else
    nFramesPerBatch = 1000; % if not on GPU, should have plenty of RAM available
end
%%
nFramesPerBatch = 8;

nBatches = ceil(nFrames/nFramesPerBatch);
startFrame = 1:nFramesPerBatch:nFrames;
endFrame = min(startFrame+nFramesPerBatch-1, nFrames);
dreg = zeros(size(data), 'single');

for iBatch = 1:nBatches
    idx = startFrame(iBatch):endFrame(iBatch);
    if ops.useGPU
        dataBatch = gpuArray(single(data(:,:,idx)));
    else
        dataBatch = single(data(:,:,idx));
    end
    [Ly, Lx, NT] = size(dataBatch);

    Ny = ifftshift([-fix(Ly/2):ceil(Ly/2)-1]);
    Nx = ifftshift([-fix(Lx/2):ceil(Lx/2)-1]);
    [Nx,Ny] = meshgrid(Nx,Ny);
    Nx = Nx / Lx;
    Ny = Ny / Ly;

    if ops.useGPU
        dsBatch = gpuArray(permute(ds(idx, :), [3, 2, 1]));
        Nx = gpuArray(single(Nx));
        Ny = gpuArray(single(Ny));
    else
        dsBatch = ds(idx, :);
    end

    if ops.useGPU % do it batch-by-batch
        dph         = 2*pi*(bsxfun(@times, dsBatch(1,1,:), Ny) + ...
            bsxfun(@times, dsBatch(:,2,:), Nx));
        fdata       = fft2(dataBatch);
        dregBatch   = gather_try(real(ifft2(fdata .* exp(1i * dph))));
    else % do it frame-by-frame
        dregBatch = zeros(size(dataBatch), 'single');
        for i = 1:NT
            dph         = 2*pi*(dsBatch(i,1)*Ny + dsBatch(i,2)*Nx);
            fdata       = fft2(single(dataBatch(:,:,i)));
            dregBatch(:,:,i) = real(ifft2(fdata .* exp(1i * dph)));
        end
    end

    dreg(:,:,idx) = dregBatch;
end


classdef PnormDescriptor < NormDescriptor

    properties (Access = protected)
        pnorm
    end

    properties (Access = protected, Abstract)
       pos
    end

    methods (Access = protected)

        function computeDistance(obj)
            x = obj.pos;
            p = obj.pnorm;
            xnorm = zeros(size(x,1),1);
            for idim = 1:size(x,2)
               xnorm = xnorm + abs(x(:,idim)).^p;
            end
            d = xnorm.^(1./p);
            obj.dist = d;
        end

    end

end


%% Copyright (C) 2016, 2019 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy 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 software 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 software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod  @@sym airy (@var{k}, @var{x})
%% @defmethodx @@sym airy (@var{x})
%% Symbolic Airy functions of first/second kind and their derivatives.
%%
%% @var{k} can be 0, 1, 2, or 3; as in the documentation for the
%% non-symbolic Airy function, @pxref{airy}.
%%
%% Examples:
%% @example
%% @group
%% syms z
%% @c doctest: +SKIP_UNLESS(pycall_sympy__ ('return Version(spver) > Version("1.4")'))
%% Ai = airy(0, z)
%%   @result{} Ai = (sym) Ai(z)
%%
%% @c doctest: +SKIP_UNLESS(pycall_sympy__ ('return Version(spver) > Version("1.4")'))
%% Bi = airy(2, z)
%%   @result{} Bi = (sym) Bi(z)
%%
%% @c doctest: +SKIP_UNLESS(pycall_sympy__ ('return Version(spver) > Version("1.4")'))
%% Bi_prime = airy(3, z)
%%   @result{} Bi_prime = (sym) Bi'(z)
%%
%% @c doctest: +SKIP_UNLESS(pycall_sympy__ ('return Version(spver) > Version("1.4")'))
%% diff(Bi, z)
%%   @result{} (sym) Bi'(z)
%%
%% @c doctest: +SKIP_UNLESS(pycall_sympy__ ('return Version(spver) > Version("1.4")'))
%% diff(Bi, z, z)
%%   @result{} (sym) z⋅Bi(z)
%% @end group
%% @end example
%%
%% @seealso{@@sym/besselj, @@sym/bessely, @@sym/besseli, @@sym/besselk, @@sym/besselh}
%% @end defmethod

function A = airy(k, x)

  if (nargin == 2)
    % no-op
  elseif (nargin == 1)
    x = k;
    k = 0;
  else
    print_usage ();
  end

  assert(isscalar(k))

  if (logical(k == 0))
    A = elementwise_op ('airyai', sym(x));
  elseif (logical(k == 1))
    A = elementwise_op ('airyaiprime', sym(x));
  elseif (logical(k == 2))
    A = elementwise_op ('airybi', sym(x));
  elseif (logical(k == 3))
    A = elementwise_op ('airybiprime', sym(x));
  else
    error('airy: expecting K = 0, 1, 2, or 3')
  end

end

%!test
%! syms z
%! a = airy(0, z);
%! ap = airy(1, z);
%! assert (isequal (diff (a), ap))
%! assert (isequal (diff (ap), z*a))

%!test
%! syms z
%! b = airy(2, z);
%! bp = airy(3, z);
%! assert (isequal (diff (b), bp))
%! assert (isequal (diff (bp), z*b))

%!test
%! % default to k=0
%! syms z
%! a = airy(0, z);
%! a2 = airy(z);
%! assert (isequal (a, a2))

%!error airy(0, sym('x'), 2)
%!error <expecting K = 0, 1, 2, or 3> airy(4, sym('z'))
%!error <expecting K = 0, 1, 2, or 3> airy(-1, sym('z'))

%!test
%! % symbolic k
%! syms z
%! b1 = airy(2, z);
%! b2 = airy(sym(2), z);
%! assert (isequal (b1, b2))

%!test
%! % doubles, relative error
%! X = [1 2 pi; 4i 5 6+6i];
%! Xs = sym(X);
%! for k = 0:3
%!   A = double(airy(k, Xs));
%!   B = airy(k, X);
%!   assert (all (all (abs(A - B) < 500*eps*abs(A))))
%! end

%!test
%! % round-trip
%! syms x
%! for k = 0:3
%!   A = airy(k, 10);
%!   q = airy(k, x);
%!   h = function_handle(q);
%!   B = h(10);
%!   assert (abs(A-B) < 500*eps*abs(A))
%! end


%% This function will generate the simulation data of an ODE function.
%You could determine the noise level by input variable "Noise". If you do
%not want any noise, set noise to zero. Please indicate whether your ODE
%function have control input, if the answer is yes, please set the
%"Control" as 1.

% Last Update: 2019/04/21
% Coded By: K

function [d_Data,Data]=Get_Sim_Data(ODE,state0,u,tspan,Noise,Control,Shuffle)
%% Get the size of the state and control
[N1,M1]=size(state0);
[N2,M2]=size(u);

%% Get simulation data by simulating the system using ODE113

% Determine the left hand side derivative
if Control==1
    y_list(1,:)=state0;
    d_y_list(1,:)=ODE(0,y_list(1,:),u(1,:));
    for i=2:length(u)
        [t_1,y_1] = ode113(@(t_1,y_1)ODE(t_1,y_1,u(i-1,:)),tspan(1,i-1:i),state0);
        y_list(i,:)=y_1(end,:);
        d_y_list(i,:)=ODE(0,y_list(i,:),u(i,:));
        state0=y_list(i,:)';
    end
else
    %Simulate the system ODE
    [t,y]=ode45(@(t,y)ODE(t,y),tspan,state0);
    y_list=y;
    % Get the derivative data
    d_y_list=ODE(0,y_list')';
end

%% Add some noise to the system
for i=1:N1
    Data(:,i)=y_list(:,i)+Noise*randn(size(y_list(:,i)));
end
%
for i=1:N1
    d_Data(:,i)=d_y_list(:,i)+Noise*randn(size(d_y_list(:,i)));
end

%% Shuffle the data
if Shuffle==1
    Sequence=randperm(size(Data,1));
    Data=Data(Sequence,:);
    d_Data=d_Data(Sequence,:);
end


% PLOTFRAME - plots a coordinate frame specified by a homogeneous transform
%
% Usage: function plotframe(T, len, label)
%
% Arguments:
%    T     - 4x4 homogeneous transform
%    len   - length of axis arms to plot (defaults to 1)
%    label - text string to append to x,y,z labels on axes
%
%  len and label are optional and default to 1 and '' respectively
%
% See also: ROTX, ROTY, ROTZ, TRANS, INVHT

% Copyright (c) 2001 Peter Kovesi
% School of Computer Science & Software Engineering
% The University of Western Australia
% pk at csse uwa edu au
% http://www.csse.uwa.edu.au/

function plotframe(T, len, label, colr)

    if ~all(size(T) == [4,4])
        error('plotframe: matrix is not 4x4')
    end

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

    if ~exist('label','var')
        label = '';
    end

    if ~exist('colr','var')
        colr = [0 0 1];
    end

    % Assume scale specified by T(4,4) == 1

    origin = T(1:3, 4);             % 1st three elements of 4th column
    X = origin + len*T(1:3, 1);     % point 'len' units out along x axis
    Y = origin + len*T(1:3, 2);     % point 'len' units out along y axis
    Z = origin + len*T(1:3, 3);     % point 'len' units out along z axis

    line([origin(1),X(1)], [origin(2), X(2)], [origin(3), X(3)], 'color', colr);
    line([origin(1),Y(1)], [origin(2), Y(2)], [origin(3), Y(3)], 'color', colr);
    line([origin(1),Z(1)], [origin(2), Z(2)], [origin(3), Z(3)], 'color', colr);

    text(X(1), X(2), X(3), ['x' label], 'color', colr);
    text(Y(1), Y(2), Y(3), ['y' label], 'color', colr);
    text(Z(1), Z(2), Z(3), ['z' label], 'color', colr);


function [ r, s, area ] = node_reference ( code )

%*****************************************************************************80
%
%% NODE_REFERENCE returns the basis nodes for any available element.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 February 2006
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, character CODE(*), identifies the element desired.
%    Legal values include 'Q4', 'Q8', 'Q9', 'Q12', 'Q16', 'QL',
%    'T3', 'T4', 'T6' and 'T10'.
%
%    Output, real R(N), S(N), the coordinates of the basis nodes.
%
%    Output, real AREA, the area of the element.
%
  if ( s_eqi ( code, 'Q4' ) )
    [ r, s, area ] = node_reference_q4 ( );
  elseif ( s_eqi ( code, 'Q8' ) )
    [ r, s, area ] = node_reference_q8 ( );
  elseif ( s_eqi ( code, 'Q9' ) )
    [ r, s, area ] = node_reference_q9 ( );
  elseif ( s_eqi ( code, 'Q12' ) )
    [ r, s, area ] = node_reference_q12 ( );
  elseif ( s_eqi ( code, 'Q16' ) )
    [ r, s, area ] = node_reference_q16 ( );
  elseif ( s_eqi ( code, 'QL' ) )
    [ r, s, area ] = node_reference_ql ( );
  elseif ( s_eqi ( code, 'T3' ) )
    [ r, s, area ] = node_reference_t3 ( );
  elseif ( s_eqi ( code, 'T4' ) )
    [ r, s, area ] = node_reference_t4 ( );
  elseif ( s_eqi ( code, 'T6' ) )
    [ r, s, area ] = node_reference_t6 ( );
  elseif ( s_eqi ( code, 'T10' ) )
    [ r, s, area ] = node_reference_t10 ( );
  else
    fprintf ( 1, '\n' );
    fprintf ( 1, 'NODE_REFERENCE - Fatal error!\n' );
    fprintf ( 1, '  Illegal value of CODE = "%s"\n', code );
    error ( 'NODE_REFERENCE - Fatal error!' );
  end

  return
end


function G = gradient8(DEM,unit,varargin)

%GRADIENT8 8-connected neighborhood gradient of a digital elevation model
%
% Syntax
%
%     G = gradient8(DEM)
%     G = gradient8(DEM,unit)
%     G = gradient8(DEM,unit,pn,pv,...)
%
% Description
%
%     gradient8 returns the numerical steepest downward gradient and aspect
%     of a digital elevation model using an 8-connected neighborhood.
%
% Input
%
%     DEM       digital elevation model (class: GRIDobj)
%     unit      'tan' --> tangent (default)
%               'rad' --> radian
%               'deg' --> degree
%               'sin' --> sine
%               'per' --> percent
%
%     Parameter name value/pairs (pn,pv,...)
%
%     'useblockproc'    true or {false}: use block processing
%                       (see function blockproc)
%     'useparallel'     true or {false}: use parallel computing toolbox
%     'blocksize'       blocksize for blockproc (default: 5000)
%
% Output
%
%     G         gradient (class: GRIDobj)
%
% Example
%
%     DEM = GRIDobj('srtm_bigtujunga30m_utm11.tif');
%     G = gradient8(DEM,'degree');
%     subplot(2,1,1)
%     imagesc(DEM)
%     subplot(2,1,2)
%     imagesc(G)
%
%
% See also: GRIDobj, GRIDobj/CURVATURE, GRIDobj/ASPECT, GRIDobj/arcslope
%
% Author: Wolfgang Schwanghart (w.schwanghart[at]geo.uni-potsdam.de)
% Date: 18. August, 2017

if nargin == 1;
    unit = 'tangent';
else
    unit = validatestring(unit,{'tangent' 'degree' 'radian' 'percent' 'sine'},'gradient8','unit',2);
end

p = inputParser;
p.FunctionName = 'GRIDobj/gradient8';
addParamValue(p,'useblockproc',false,@(x) isscalar(x));
addParamValue(p,'blocksize',5000,@(x) isscalar(x));
addParamValue(p,'useparallel',false,@(x) isscalar(x));
parse(p,varargin{:});

% create a copy of the DEM instance
G = DEM;
c = class(DEM.Z);
switch c
    case 'double'
        G.Z = double.empty(0,0);
    otherwise
        G.Z = single.empty(0,0);
        c   = 'single';
end

% I found Large matrix support using blockproc inefficient for gradient8.
% Matrix dimensions have thus been increased to an out-of-range value to
% avoid calling blockproc.
% Large matrix support. Break calculations in chunks using blockproc.

if p.Results.useblockproc
    blksiz = bestblk(size(DEM.Z),p.Results.blocksize);
    c   = class(DEM.Z);

    switch c
        case {'double', 'single'}
            padval = inf;
        case 'logical'
            padval = true;
        otherwise
            padval = intmax(c);
    end
    cs  = G.cellsize;
    fun = @(x) steepestgradient(x,cs,c);
    G.Z = blockproc(DEM.Z,blksiz,fun,...
           'BorderSize',[1 1],...
           'Padmethod',padval,...
           'UseParallel',p.Results.useparallel);
else
    G.Z = steepestgradient(DEM.Z,G.cellsize,c);
end

G.name = 'gradient';
G.zunit = unit;

switch unit
    case 'tangent'
        % do nothing
    case 'degree'
        G.Z = atand(G.Z);
    case 'radian'
        G.Z = atan(G.Z);
    case 'sine'
        G.Z = sin(atan(G.Z));
    case 'percent'
        G.Z = G.Z*100;
end
end

function G = steepestgradient(z,cellsize,c)

if isstruct(z);
    z = z.data;
end

% check for nans;
I = isnan(z);
flagnan = any(I(:));
if flagnan
    z(I) = inf;
end

NEIGH = false(3);
% calculate along orthogonal neighbors
NEIGH(2,:) = true;
NEIGH(:,2) = true;

switch c
    case 'double'
        G = (z-imerode(z,NEIGH))/cellsize;
    case 'single'
        G = single(z-imerode(z,NEIGH))/cellsize;
end

% calculate along diagonal neighbors
NEIGH(:,:) = false;
NEIGH([1 5 9 3 7]) = true;

switch c
    case 'double'
        G = max(G,(z-imerode(z,NEIGH))/norm([cellsize cellsize]));
    case 'single'
        G = max(G,single(z-imerode(z,NEIGH))/single(norm([cellsize cellsize])));
end

if flagnan
    G(I) = nan;
end
end


function boolVal=allElementsAreInts(x)
%%ALLELEMENTSAREINTS Given a vector or a matrix, this function returns true
%            if all of the elements in the matrix are exactly integers
%            (including complex integers. This differs from the isinteger
%            function that is built into Matlab as this actually checks the
%            values of the data, whereas isinteger only tells whether the
%            data type is an integer. THis function can handle floating
%            point numbers.
%
%INPUTS: x A scalar or matrix/hypermatrix where one wants to determine
%          whether all elements are integers.
%
%OUTPUTS: boolVal This is true if all elements of x are integer values
%               (regardless of data type) and this is false otherwise.
%
%March 2017 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

boolVal=all(x(:)==fix(x(:)));

end

%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


% Fixed-budget kernel least mean squares (FB-KLMS) algorithm.
%
% D. Rzepka, "Fixed-budget kernel least mean squares," 2012 IEEE 17th
% Conference on Emerging Technologies & Factory Automation (ETFA), Krakow,
% Poland, Sept. 2012, http://dx.doi.org/10.1109/ETFA.2012.6489767
%
% Remark: code contributed by Dominik Rzepka
%
% This file is part of the Kernel Adaptive Filtering Toolbox for Matlab.
% https://github.com/steven2358/kafbox/

classdef fbklms < kernel_adaptive_filter

    properties (GetAccess = 'public', SetAccess = 'private') % parameters
        nu = .05; % growth criterion threshold
        M = 500; % dictionary size
        eta = .5; % learning rate
        kerneltype = 'gauss'; % kernel type
        kernelpar = 1; % kernel parameter
    end

    properties (GetAccess = 'private', SetAccess = 'private') % variables
        dict = []; % dictionary
        diagkdict = []; % diagonal of kernel matrix for dictionary
        alpha = []; % expansion coefficients
    end

    methods
        function kaf = fbklms(parameters) % constructor
            if (nargin > 0) % copy valid parameters
                for fn = fieldnames(parameters)'
                    if ismember(fn,fieldnames(kaf))
                        kaf.(fn{1}) = parameters.(fn{1});
                    end
                end
            end
        end

        function y_est = evaluate(kaf,x) % evaluate the algorithm
            if size(kaf.dict,1)>0
                k = kernel(kaf.dict,x,kaf.kerneltype,kaf.kernelpar);
                y_est = k'*kaf.alpha;
            else
                y_est = zeros(size(x,1),1);
            end
        end

        function train(kaf,x,y) % train the algorithm
            if size(kaf.dict,2)==0 % initialize
                kaf.dict = x;
                k = kernel(kaf.dict,x,kaf.kerneltype,kaf.kernelpar);
                kaf.diagkdict(1) = k;
                kaf.alpha = kaf.eta*y*k/(k'*k);
            else

                kt = kernel([kaf.dict;x],x,kaf.kerneltype,kaf.kernelpar);
                k = kt(1:end-1);
                y_est = k'*kaf.alpha;
                e = y - y_est;

                kaf.alpha = kaf.alpha + kaf.eta*e*k/(k'*k);

                % growth criterion
                kx = kt(end);
                dependency = kx - k./kaf.diagkdict;
                if min(dependency) >= kaf.nu % expand dictionary
                    kaf.dict = [kaf.dict; x];
                    kaf.diagkdict = [kaf.diagkdict; kx];
                    kaf.alpha = [kaf.alpha; kaf.eta*e/(k'*k)];

                    if length(kaf.alpha) > kaf.M % prune dictionary
                        [~, id] = min(abs(kaf.alpha));
                        kaf.dict(id,:) = [];
                        kaf.diagkdict(id) = [];
                        kaf.alpha(id) = [];
                    end
                end
            end
        end
    end
end


function [qrs_amp_raw,qrs_i_raw,delay]=pan_tompkin(ecg,fs,gr)

%% function [qrs_amp_raw,qrs_i_raw,delay]=pan_tompkin(ecg,fs)
% Complete implementation of Pan-Tompkins algorithm

%% Inputs
% ecg : raw ecg vector signal 1d signal
% fs : sampling frequency e.g. 200Hz, 400Hz and etc
% gr : flag to plot or not plot (set it 1 to have a plot or set it zero not
% to see any plots
%% Outputs
% qrs_amp_raw : amplitude of R waves amplitudes
% qrs_i_raw : index of R waves
% delay : number of samples which the signal is delayed due to the
% filtering
%% Method :

%% PreProcessing
% 1) Signal is preprocessed , if the sampling frequency is higher then it is downsampled
% and if it is lower upsampled to make the sampling frequency 200 Hz
% with the same filtering setups introduced in Pan
% tompkins paper (a combination of low pass and high pass filter 5-15 Hz)
% to get rid of the baseline wander and muscle noise.

% 2) The filtered signal
% is derivated using a derivating filter to high light the QRS complex.

% 3) Signal is squared.4)Signal is averaged with a moving window to get rid
% of noise (0.150 seconds length).

% 5) depending on the sampling frequency of your signal the filtering
% options are changed to best match the characteristics of your ecg signal

% 6) Unlike the other implementations in this implementation the desicion
% rule of the Pan tompkins is implemented completely.

%% Decision Rule
% At this point in the algorithm, the preceding stages have produced a roughly pulse-shaped
% waveform at the output of the MWI . The determination as to whether this pulse
% corresponds to a QRS complex (as opposed to a high-sloped T-wave or a noise artefact) is
% performed with an adaptive thresholding operation and other decision
% rules outlined below;

% a) FIDUCIAL MARK - The waveform is first processed to produce a set of weighted unit
% samples at the location of the MWI maxima. This is done in order to localize the QRS
% complex to a single instant of time. The w[k] weighting is the maxima value.

% b) THRESHOLDING - When analyzing the amplitude of the MWI output, the algorithm uses
% two threshold values (THR_SIG and THR_NOISE, appropriately initialized during a brief
% 2 second training phase) that continuously adapt to changing ECG signal quality. The
% first pass through y[n] uses these thresholds to classify the each non-zero sample
% (CURRENTPEAK) as either signal or noise:
% If CURRENTPEAK > THR_SIG, that location is identified as a QRS complex
% candidate?and the signal level (SIG_LEV) is updated:
% SIG _ LEV = 0.125 CURRENTPEAK + 0.875?SIG _ LEV

% If THR_NOISE < CURRENTPEAK < THR_SIG, then that location is identified as a
% Noise peak?and the noise level (NOISE_LEV) is updated:
% NOISE _ LEV = 0.125CURRENTPEAK + 0.875?NOISE _ LEV
% Based on new estimates of the signal and noise levels (SIG_LEV and NOISE_LEV,
% respectively) at that point in the ECG, the thresholds are adjusted as follows:
% THR _ SIG = NOISE _ LEV + 0.25 ?(SIG _ LEV-NOISE _ LEV )
% THR _ NOISE = 0.5?(THR _ SIG)
% These adjustments lower the threshold gradually in signal segments that are deemed to
% be of poorer quality.

% c) SEARCHBACK FOR MISSED QRS COMPLEXES - In the thresholding step above, if
% CURRENTPEAK < THR_SIG, the peak is deemed not to have resulted from a QRS
% complex. If however, an unreasonably long period has expired without an abovethreshold
% peak, the algorithm will assume a QRS has been missed and perform a
% searchback. This limits the number of false negatives. The minimum time used to trigger
% a searchback is 1.66 times the current R peak to R peak time period (called the RR
% interval). This value has a physiological origin - the time value between adjacent
% heartbeats cannot change more quickly than this. The missed QRS complex is assumed
% to occur at the location of the highest peak in the interval that lies between THR_SIG and
% THR_NOISE. In this algorithm, two average RR intervals are stored,the first RR interval is
% calculated as an average of the last eight QRS locations in order to adapt to changing heart
% rate and the second RR interval mean is the mean
% of the most regular RR intervals . The threshold is lowered if the heart rate is not regular
% to improve detection.

% d) ELIMINATION OF MULTIPLE DETECTIONS WITHIN REFRACTORY PERIOD - It is
% impossible for a legitimate QRS complex to occur if it lies within 200ms after a previously
% detected one. This constraint is a physiological one ?due to the refractory period during
% which ventricular depolarization cannot occur despite a stimulus[1]. As QRS complex
% candidates are generated, the algorithm eliminates such physically impossible events,
% thereby reducing false positives.

% e) T WAVE DISCRIMINATION - Finally, if a QRS candidate occurs after the 200ms
% refractory period but within 360ms of the previous QRS, the algorithm determines
% whether this is a genuine QRS complex of the next heartbeat or an abnormally prominent
% T wave. This decision is based on the mean slope of the waveform at that position. A slope of
% less than one half that of the previous QRS complex is consistent with the slower
% changing behaviour of a T wave ?otherwise, it becomes a QRS detection.
% Extra concept : beside the points mentioned in the paper, this code also
% checks if the occured peak which is less than 360 msec latency has also a
% latency less than 0,5*mean_RR if yes this is counted as noise

% f) In the final stage , the output of R waves detected in smoothed signal is analyzed and double
% checked with the help of the output of the bandpass signal to improve
% detection and find the original index of the real R waves on the raw ecg
% signal

%% References :

%[1]PAN.J, TOMPKINS. W.J,"A Real-Time QRS Detection Algorithm" IEEE
%TRANSACTIONS ON BIOMEDICAL ENGINEERING, VOL. BME-32, NO. 3, MARCH 1985.

%% Author : Hooman Sedghamiz
% Linkoping university
% email : hoose792@student.liu.se
% hooman.sedghamiz@medel.com

% Any direct or indirect use of this code should be referenced
% Copyright march 2014
%%
if ~isvector(ecg)
  error('ecg must be a row or column vector');
end

if nargin < 3
    gr = 1;   % on default the function always plots
end
ecg = ecg(:); % vectorize

%% Initialize
qrs_c =[]; %amplitude of R
qrs_i =[]; %index
SIG_LEV = 0;
nois_c =[];
nois_i =[];
delay = 0;
skip = 0; % becomes one when a T wave is detected
not_nois = 0; % it is not noise when not_nois = 1
selected_RR =[]; % Selected RR intervals
m_selected_RR = 0;
mean_RR = 0;
qrs_i_raw =[];
qrs_amp_raw=[];
ser_back = 0;
test_m = 0;
SIGL_buf = [];
NOISL_buf = [];
THRS_buf = [];
SIGL_buf1 = [];
NOISL_buf1 = [];
THRS_buf1 = [];

%% Plot differently based on filtering settings
if gr
 if fs == 200
  figure,  ax(1)=subplot(321);plot(ecg);axis tight;title('Raw ECG Signal');
 else
  figure,  ax(1)=subplot(3,2,[1 2]);plot(ecg);axis tight;title('Raw ECG Signal');
 end
end
%% Noise cancelation(Filtering) % Filters (Filter in between 5-15 Hz)
if fs == 200
%% Low Pass Filter  H(z) = ((1 - z^(-6))^2)/(1 - z^(-1))^2
b = [1 0 0 0 0 0 -2 0 0 0 0 0 1];
a = [1 -2 1];
h_l = filter(b,a,[1 zeros(1,12)]);
ecg_l = conv (ecg ,h_l);
ecg_l = ecg_l/ max( abs(ecg_l));
delay = 6; %based on the paper
if gr
ax(2)=subplot(322);plot(ecg_l);axis tight;title('Low pass filtered');
end
%% High Pass filter H(z) = (-1+32z^(-16)+z^(-32))/(1+z^(-1))
b = [-1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 -32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1];
a = [1 -1];
h_h = filter(b,a,[1 zeros(1,32)]);
ecg_h = conv (ecg_l ,h_h);
ecg_h = ecg_h/ max( abs(ecg_h));
delay = delay + 16; % 16 samples for highpass filtering
if gr
ax(3)=subplot(323);plot(ecg_h);axis tight;title('High Pass Filtered');
end
else
%% bandpass filter for Noise cancelation of other sampling frequencies(Filtering)
f1=5; %cuttoff low frequency to get rid of baseline wander
f2=15; %cuttoff frequency to discard high frequency noise
Wn=[f1 f2]*2/fs; % cutt off based on fs
N = 3; % order of 3 less processing
[a,b] = butter(N,Wn); %bandpass filtering
ecg_h = filtfilt(a,b,ecg);
ecg_h = ecg_h/ max( abs(ecg_h));
if gr
ax(3)=subplot(323);plot(ecg_h);axis tight;title('Band Pass Filtered');
end
end
%% derivative filter H(z) = (1/8T)(-z^(-2) - 2z^(-1) + 2z + z^(2))
h_d = [-1 -2 0 2 1]*(1/8);%1/8*fs
ecg_d = conv (ecg_h ,h_d);
ecg_d = ecg_d/max(ecg_d);
delay = delay + 2; % delay of derivative filter 2 samples
if gr
ax(4)=subplot(324);plot(ecg_d);axis tight;title('Filtered with the derivative filter');
end
%% Squaring nonlinearly enhance the dominant peaks
ecg_s = ecg_d.^2;
if gr
ax(5)=subplot(325);plot(ecg_s);axis tight;title('Squared');
end

%% Moving average Y(nt) = (1/N)[x(nT-(N - 1)T)+ x(nT - (N - 2)T)+...+x(nT)]
ecg_m = conv(ecg_s ,ones(1 ,round(0.150*fs))/round(0.150*fs));
delay = delay + 15;

if gr
ax(6)=subplot(326);plot(ecg_m);axis tight;title('Averaged with 30 samples length,Black noise,Green Adaptive Threshold,RED Sig Level,Red circles QRS adaptive threshold');
axis tight;
end

%% Fiducial Mark
% Note : a minimum distance of 40 samples is considered between each R wave
% since in physiological point of view no RR wave can occur in less than
% 200 msec distance
[pks,locs] = findpeaks(ecg_m,'MINPEAKDISTANCE',round(0.2*fs));

%% initialize the training phase (2 seconds of the signal) to determine the THR_SIG and THR_NOISE
THR_SIG = max(ecg_m(1:2*fs))*1/3; % 0.25 of the max amplitude
THR_NOISE = mean(ecg_m(1:2*fs))*1/2; % 0.5 of the mean signal is considered to be noise
SIG_LEV= THR_SIG;
NOISE_LEV = THR_NOISE;

%% Initialize bandpath filter threshold(2 seconds of the bandpass signal)
THR_SIG1 = max(ecg_h(1:2*fs))*1/3; % 0.25 of the max amplitude
THR_NOISE1 = mean(ecg_h(1:2*fs))*1/2; %
SIG_LEV1 = THR_SIG1; % Signal level in Bandpassed filter
NOISE_LEV1 = THR_NOISE1; % Noise level in Bandpassed filter
%% Thresholding and online desicion rule

for i = 1 : length(pks)

   %% locate the corresponding peak in the filtered signal
    if locs(i)-round(0.150*fs)>= 1 && locs(i)<= length(ecg_h)
          [y_i x_i] = max(ecg_h(locs(i)-round(0.150*fs):locs(i)));
       else
          if i == 1
            [y_i x_i] = max(ecg_h(1:locs(i)));
            ser_back = 1;
          elseif locs(i)>= length(ecg_h)
            [y_i x_i] = max(ecg_h(locs(i)-round(0.150*fs):end));
          end

     end

  %% update the heart_rate (Two heart rate means one the moste recent and the other selected)
    if length(qrs_c) >= 9

        diffRR = diff(qrs_i(end-8:end)); %calculate RR interval
        mean_RR = mean(diffRR); % calculate the mean of 8 previous R waves interval
        comp =qrs_i(end)-qrs_i(end-1); %latest RR
        if comp <= 0.92*mean_RR || comp >= 1.16*mean_RR
            % lower down thresholds to detect better in MVI
                THR_SIG = 0.5*(THR_SIG);
                %THR_NOISE = 0.5*(THR_SIG);
               % lower down thresholds to detect better in Bandpass filtered
                THR_SIG1 = 0.5*(THR_SIG1);
                %THR_NOISE1 = 0.5*(THR_SIG1);

        else
            m_selected_RR = mean_RR; %the latest regular beats mean
        end

    end

      %% calculate the mean of the last 8 R waves to make sure that QRS is not
       % missing(If no R detected , trigger a search back) 1.66*mean

       if m_selected_RR
           test_m = m_selected_RR; %if the regular RR availabe use it
       elseif mean_RR && m_selected_RR == 0
           test_m = mean_RR;
       else
           test_m = 0;
       end

    if test_m
          if (locs(i) - qrs_i(end)) >= round(1.66*test_m)% it shows a QRS is missed
              [pks_temp,locs_temp] = max(ecg_m(qrs_i(end)+ round(0.200*fs):locs(i)-round(0.200*fs))); % search back and locate the max in this interval
              locs_temp = qrs_i(end)+ round(0.200*fs) + locs_temp -1; %location

              if pks_temp > THR_NOISE
               qrs_c = [qrs_c pks_temp];
               qrs_i = [qrs_i locs_temp];

               % find the location in filtered sig
               if locs_temp <= length(ecg_h)
                [y_i_t x_i_t] = max(ecg_h(locs_temp-round(0.150*fs):locs_temp));
               else
                [y_i_t x_i_t] = max(ecg_h(locs_temp-round(0.150*fs):end));
               end
               % take care of bandpass signal threshold
               if y_i_t > THR_NOISE1

                      qrs_i_raw = [qrs_i_raw locs_temp-round(0.150*fs)+ (x_i_t - 1)];% save index of bandpass
                      qrs_amp_raw =[qrs_amp_raw y_i_t]; %save amplitude of bandpass
                      SIG_LEV1 = 0.25*y_i_t + 0.75*SIG_LEV1; %when found with the second thres
               end

               not_nois = 1;
               SIG_LEV = 0.25*pks_temp + 0.75*SIG_LEV ;  %when found with the second threshold
             end

          else
              not_nois = 0;

          end
    end

    %%  find noise and QRS peaks
    if pks(i) >= THR_SIG

                 % if a QRS candidate occurs within 360ms of the previous QRS
                 % ,the algorithm determines if its T wave or QRS
                 if length(qrs_c) >= 3
                      if (locs(i)-qrs_i(end)) <= round(0.3600*fs)
                        Slope1 = mean(diff(ecg_m(locs(i)-round(0.075*fs):locs(i)))); %mean slope of the waveform at that position
                        Slope2 = mean(diff(ecg_m(qrs_i(end)-round(0.075*fs):qrs_i(end)))); %mean slope of previous R wave
                             if abs(Slope1) <= abs(0.5*(Slope2))  % slope less then 0.5 of previous R
                                 nois_c = [nois_c pks(i)];
                                 nois_i = [nois_i locs(i)];
                                 skip = 1; % T wave identification
                                 % adjust noise level in both filtered and
                                 % MVI
                                 NOISE_LEV1 = 0.125*y_i + 0.875*NOISE_LEV1;
                                 NOISE_LEV = 0.125*pks(i) + 0.875*NOISE_LEV;
                             else
                                 skip = 0;
                             end

                      end
                 end

        if skip == 0  % skip is 1 when a T wave is detected
        qrs_c = [qrs_c pks(i)];
        qrs_i = [qrs_i locs(i)];

        % bandpass filter check threshold
         if y_i >= THR_SIG1
                        if ser_back
                           qrs_i_raw = [qrs_i_raw x_i];  % save index of bandpass
                        else
                           qrs_i_raw = [qrs_i_raw locs(i)-round(0.150*fs)+ (x_i - 1)];% save index of bandpass
                        end
                           qrs_amp_raw =[qrs_amp_raw y_i];% save amplitude of bandpass
          SIG_LEV1 = 0.125*y_i + 0.875*SIG_LEV1;% adjust threshold for bandpass filtered sig
         end

        % adjust Signal level
        SIG_LEV = 0.125*pks(i) + 0.875*SIG_LEV ;
        end

    elseif THR_NOISE <= pks(i) && pks(i)<THR_SIG

         %adjust Noise level in filtered sig
         NOISE_LEV1 = 0.125*y_i + 0.875*NOISE_LEV1;
         %adjust Noise level in MVI
         NOISE_LEV = 0.125*pks(i) + 0.875*NOISE_LEV;

    elseif pks(i) < THR_NOISE
        nois_c = [nois_c pks(i)];
        nois_i = [nois_i locs(i)];

        % noise level in filtered signal
        NOISE_LEV1 = 0.125*y_i + 0.875*NOISE_LEV1;
        %end

         %adjust Noise level in MVI
        NOISE_LEV = 0.125*pks(i) + 0.875*NOISE_LEV;

    end

    %% adjust the threshold with SNR
    if NOISE_LEV ~= 0 || SIG_LEV ~= 0
        THR_SIG = NOISE_LEV + 0.25*(abs(SIG_LEV - NOISE_LEV));
        THR_NOISE = 0.5*(THR_SIG);
    end

    % adjust the threshold with SNR for bandpassed signal
    if NOISE_LEV1 ~= 0 || SIG_LEV1 ~= 0
        THR_SIG1 = NOISE_LEV1 + 0.25*(abs(SIG_LEV1 - NOISE_LEV1));
        THR_NOISE1 = 0.5*(THR_SIG1);
    end

% take a track of thresholds of smoothed signal
SIGL_buf = [SIGL_buf SIG_LEV];
NOISL_buf = [NOISL_buf NOISE_LEV];
THRS_buf = [THRS_buf THR_SIG];

% take a track of thresholds of filtered signal
SIGL_buf1 = [SIGL_buf1 SIG_LEV1];
NOISL_buf1 = [NOISL_buf1 NOISE_LEV1];
THRS_buf1 = [THRS_buf1 THR_SIG1];

 skip = 0; %reset parameters
 not_nois = 0; %reset parameters
 ser_back = 0;  %reset bandpass param
end

if gr
hold on,scatter(qrs_i,qrs_c,'m');
hold on,plot(locs,NOISL_buf,'--k','LineWidth',2);
hold on,plot(locs,SIGL_buf,'--r','LineWidth',2);
hold on,plot(locs,THRS_buf,'--g','LineWidth',2);
if ax(:)
linkaxes(ax,'x');
zoom on;
end
end

%% overlay on the signals
if gr
figure,az(1)=subplot(311);plot(ecg_h);title('QRS on Filtered Signal');axis tight;
hold on,scatter(qrs_i_raw,qrs_amp_raw,'m');
hold on,plot(locs,NOISL_buf1,'LineWidth',2,'Linestyle','--','color','k');
hold on,plot(locs,SIGL_buf1,'LineWidth',2,'Linestyle','-.','color','r');
hold on,plot(locs,THRS_buf1,'LineWidth',2,'Linestyle','-.','color','g');
az(2)=subplot(312);plot(ecg_m);title('QRS on MVI signal and Noise level(black),Signal Level (red) and Adaptive Threshold(green)');axis tight;
hold on,scatter(qrs_i,qrs_c,'m');
hold on,plot(locs,NOISL_buf,'LineWidth',2,'Linestyle','--','color','k');
hold on,plot(locs,SIGL_buf,'LineWidth',2,'Linestyle','-.','color','r');
hold on,plot(locs,THRS_buf,'LineWidth',2,'Linestyle','-.','color','g');
az(3)=subplot(313);plot(ecg-mean(ecg));title('Pulse train of the found QRS on ECG signal');axis tight;
line(repmat(qrs_i_raw,[2 1]),repmat([min(ecg-mean(ecg))/2; max(ecg-mean(ecg))/2],size(qrs_i_raw)),'LineWidth',2.5,'LineStyle','-.','Color','r');
linkaxes(az,'x');
zoom on;
end
end


function [transformationMatrix] = ...
    optical_flow_linear_registration3d(moving, fixed, varargin)
% OPTICAL_FLOW_LINEAR_REGISTRATION3D Estimates a transformation matrix using optical flow
%
% INPUT ARGUMENTS
% moving                - Moving iamge
% fixed                 - Fixed image
%
% OUTPUT ARGUMENTS
% transformationMatrix  - Estimated displacement field
%
% OPTIONAL INPUT ARGUMENTS
% 'transformationModel'     - Transformation model for estimating the
%                             displacement field
%                             'translation', 'affine', 'non-rigid' (default)
%
% 'multiModal'              - Set whether to perform multi-modal or
%                             uni-modal image registration
%                             false (default), true
%
% 'numberOfChannels'        - Number of channels to use in when computing
%                             the entropy (based on channel coding). This
%                             is only relevant if multiModal is set to
%                             true.
%                             Default value is 8

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

%% Setup default parameters
% translation, affine
transformationModel = 'affine';

% multi-modal
multiModal = false;

% number of channels, only valid for multi-modal registration
numberOfChannels = 8;

% Overwrites default parameter
for k=1:2:length(varargin)
    eval([varargin{k},'=varargin{',int2str(k+1),'};']);
end;

% Initialize transformation matrix
transformationMatrix = eye(4);

[b_moving(:,:,:,1) b_moving(:,:,:,2) b_moving(:,:,:,3)] = gradient(moving);
[b_fixed(:,:,:,1) b_fixed(:,:,:,2) b_fixed(:,:,:,3)] = gradient(fixed);

if multiModal
    b = b_fixed(:,:,:,2);
    b(:,:,:,2) = b_fixed(:,:,:,1);
    b(:,:,:,3) = b_fixed(:,:,:,3);

    [delta_c mask] = estimate_delta_c(fixed,moving,numberOfChannels);
    delta_c(mask ~= 1) = 0;
    mask = repmat(mask,[1 1 3]);
    b(mask ~= 1) = 0;
else
    b = (b_moving(:,:,:,2) + b_fixed(:,:,:,2))/2;
    b(:,:,:,2) = (b_moving(:,:,:,1) + b_fixed(:,:,:,1))/2;
    b(:,:,:,3) = (b_moving(:,:,:,3) + b_fixed(:,:,:,3))/2;

    delta_c = fixed - moving;
end

[G, h] = build_G_h_linear3d(b, delta_c, transformationModel);

% Solve the equation system
switch transformationModel
    case 'translation'
        d = G \ h;
        transformationMatrix(1:3,4) = d;
    case {'rigid','affine'}
        p = G \ h;
        transformationMatrix(1:3,1:4) = [1+p(1) p(2) p(3) p(10);...
                                         p(4) 1+p(5) p(6) p(11);...
                                         p(7) p(8) 1+p(9) p(12)];
end


function [vals, c_index_1, c_index_2, y_1, y_2] = price_2d_ctmc( S_0s, T, r, rho, sigmas, qs, params, contractParams, M)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% About: Pricing Function for European/Bermudan/Barrier Options using CTMC approximation method
% Models Supported: 2D Diffusions
% Returns: price of contract
% Author: Justin Lars Kirkby
%
% References:  (1) A General Continuous Time Markov Chain Approximation for
%               Multi-Asset option pricing with systems of correlated diffusions,
%               Applied Math. and Comput., 2020 (JL Kirkby, Duy Nguyen, Dang Nguyen)
%
% ----------------------
% Model Params
% ----------------------
% S_0s   = initial asset prices
% T      = time remaining until maturity (in years, e.g. T=1)
% r      = interest rate (e.g. 0.05)
% rho    = correlation between brownian motions
% sigmas = volatilities per asset
% qs     = div yeilds per asset
% M      = num monitoring points for Barrier/Bermudan (also controls num steps for multi-step European pricing)
%
% ----------------------
% Contract Params  (contractParams)
% ----------------------
%
% contractParams.payoff_type:
%
% 1: Linear, G = S_1  (linear payoff in first underlying)
% 2: Linear, G = S_2  (linear payoff in second underlying)
% 3: Exchange, G = (S_1 - S_2)^+
% 4: Spread,  G = (S_1 - S_2 - K)^+   (NOTE: must set strike, K)
% 5: Geometric Basket Call / Put,  G = (sqrt(S_1) * sqrt(S_2) - K)^+  (for the call)
% 6: Arithmetic Basket Call / Put,  G = (sqrt(S_1) * sqrt(S_2) - K)^+  (for the call)
% 7: Call-on-Max and Put-on-Min, Gcall = (max(S_1,S_2) - K)^+ , Gput = (K - min(S_1,S_2))^+
% 8: Call/put on just S_2, G = (S_2 - K)^+  (for the call)
% 9: Best-of / Worst-of,  G = max(S_1,S_2), G = min(S_1,S_2)
%
% contractParams.contract:
%
% 1: European, Single Step Pricing
% 2: European, Multi Step Pricing (M above controls number of steps)
% 3: Bermudan (M above controls number of monitoring points)
% 4: Barrier (M above controls number of monitoring points)
%
% Note: for barrier option, set:
%       contractParams.barriers_1 = lower/upper barriers on first asset  (e.g. [0 50])
%       contractParams.barriers_2 = lower/upper barriers on second asset  (e.g. [0 50000000000] to disable barrier on S_2)
%
% ----------------------
% Numerical (CTMC) Params
% ----------------------
% params = CTMC parameters
% params.m_0 = num CTCM states
% params.num_devs = num std devs used in the grid
% params.gridMethod = choose the grid method (several RnD versions)
% params.GridMultParam = non-uniformity param, in (0,1)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin < 9
    M = 1; % M is only needed for
end
dt = T/M;

contract = contractParams.contract;

if contract == 1  % European
    dt = 1; M = 1;
end

method = 4;
num_devs = params.num_devs;
m_0 = params.m_0;
GridMultParam = params.GridMultParam;
gridMethod = params.gridMethod;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

drifts = r - qs;

R = [1 rho; rho 1];  % Correlation Matrix
[ L, D, C, Cinv ] = get_transform_matrices_2d( R, method );

% Now Define New Uncorrelated System  (the dc underscore)
[drift_dc, sigma_dc ] = decorrelate(sigmas, drifts, C, D );

[Ls_dc, Rs_dc ] = get_CTMC_decorr_boundaries(sigmas, C, T, 0, sigma_dc, num_devs);
Y_0s = [0 0];

% Form CTMC 1
center = Y_0s(1);
mu_func = @(s) drift_dc(1)*[s>-100000];
sig_func = @(s) sigma_dc(1)*[s>-100000];
[Q, y_1, c_index_1] = Q_Matrix(m_0, mu_func,sig_func,Ls_dc(1),Rs_dc(1),gridMethod,center, GridMultParam);
P1 = expm(Q*dt);

% Form CTMC 2
center = Y_0s(2);
mu_func = @(s) drift_dc(2)*[s>-100000];
sig_func = @(s) sigma_dc(2)*[s>-100000];
[Q, y_2, c_index_2] = Q_Matrix(m_0, mu_func,sig_func,Ls_dc(2),Rs_dc(2),gridMethod,center, GridMultParam);
P2 = expm(Q*dt);

G = get_payoff_G_matrix_from_ygrid_2d( y_1, y_2, S_0s, sigmas, rho, contractParams);

if contract == 1  % European, Price by single step
    vals = exp(-r*T)*P1*G*P2.';

elseif contract == 2  % European, Price By Multi Step
    vals = G;
    for m=M-1:-1:0
        vals = exp(-r*dt)*P1*vals*P2.';
    end

elseif contract == 3  % Bermudan
    vals = G;
    for m=M-1:-1:0
        vals = max(exp(-r*dt)*P1*vals*P2.', G);
    end

elseif contract == 4 % Barrier
    b1 = contractParams.barriers_1; L1 = b1(1); U1 = b1(2);
    b2 = contractParams.barriers_2; L2 = b2(1); U2 = b2(2);
    B = ones(m_0, m_0);
    for i = 1:m_0
        y1 = y_1(i);
        S1 = S_0s(1)*exp(sigmas(1)*y1);
        if S1 < L1 || S1 > U1
            B(i,:) = 0;
        else
            for j = 1:m_0
                y2 = y_2(j);
                S2 = S_0s(2)*exp(sigmas(2)*(y2 + rho*y1));
                if S2 < L2 || S2 > U2
                    B(i,j) = 0;
                end
            end
        end
    end
    vals = G.*B;
    for m=M-1:-1:0
        vals = exp(-r*dt)*(B.*P1*vals*P2.');
    end
end

end


data = dlmread('iris.dat'); % data file
%Dividing it to testing and learning sets to this example.
datalearn=[data(1:25,:);data(51:75,:);data(101:125,:)];
datatest=[data(26:50,:);data(76:100,:);data(126:150,:)];
v=[1:4];
c=5;
measure = 1; % Used measure (see classifier.m)
p = [0.1:0.25:4]; % p parameter range
m = [0.25:0.25:8]; % m parameter range
pl=1; % Do we use plotting w.r.t. parameters p and m or not pl=0 no plotting pl=1 plotting.

[Classification_accuracy,p1,m1,classes]=simclass1(datalearn, datatest,v,c, measure, p, m,pl);
Classification_accuracy

disp('Or if you just want to classify with one parameter values i.e. p=1,m=1')
[Classification_accuracy,p1,m1,classes]=simclass1(datalearn, datatest,v,c, measure, 1, 1,0);
Classification_accuracy


function [ value, ifault ] = ppchi2 ( p, v, g )

%*****************************************************************************80
%
%% PPCHI2 evaluates the percentage points of the Chi-squared PDF.
%
%  Discussion
%
%    Incorporates the suggested changes in AS R85 (vol.40(1),
%    pages 233-5, 1991) which should eliminate the need for the limited
%    range for P, though these limits have not been removed
%    from the routine.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 February 2008
%
%  Author:
%
%    Original FORTRAN77 version by Donald Best, DE Roberts.
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Donald Best, DE Roberts,
%    Algorithm AS 91:
%    The Percentage Points of the Chi-Squared Distribution,
%    Applied Statistics,
%    Volume 24, Number 3, 1975, pages 385-390.
%
%  Parameters:
%
%    Input, real P,  value of the chi-squared cumulative
%    probability density function.
%    0.000002 <= P <= 0.999998.
%
%    Input, real V, the parameter of the chi-squared probability
%    density function.
%    0 < V.
%
%    Input, real G, the value of log ( Gamma ( V / 2 ) ).
%
%    Output, real VALUE, the value of the chi-squared random
%    deviate with the property that the probability that a chi-squared random
%    deviate with parameter V is less than or equal to PPCHI2 is P.
%
%    Output, integer IFAULT, is nonzero if an error occurred.
%    0, no error.
%    1, P is outside the legal range.
%    2, V is not positive.
%    3, an error occurred in GAMMAD.
%    4, the result is probably as accurate as the machine will allow.
%
  aa = 0.6931471806;
  c1 = 0.01;
  c2 = 0.222222;
  c3 = 0.32;
  c4 = 0.4;
  c5 = 1.24;
  c6 = 2.2;
  c7 = 4.67;
  c8 = 6.66;
  c9 = 6.73;
  c10 = 13.32;
  c11 = 60.0;
  c12 = 70.0;
  c13 = 84.0;
  c14 = 105.0;
  c15 = 120.0;
  c16 = 127.0;
  c17 = 140.0;
  c18 = 175.0;
  c19 = 210.0;
  c20 = 252.0;
  c21 = 264.0;
  c22 = 294.0;
  c23 = 346.0;
  c24 = 420.0;
  c25 = 462.0;
  c26 = 606.0;
  c27 = 672.0;
  c28 = 707.0;
  c29 = 735.0;
  c30 = 889.0;
  c31 = 932.0;
  c32 = 966.0;
  c33 = 1141.0;
  c34 = 1182.0;
  c35 = 1278.0;
  c36 = 1740.0;
  c37 = 2520.0;
  c38 = 5040.0;
  e = 0.5E-06;
  maxit = 20;
  pmax = 0.999998;
  pmin = 0.000002;
%
%  Test arguments and initialize.
%
  value = - 1.0;

  if ( p < pmin || pmax < p )
    ifault = 1;
    return
  end

  if ( v <= 0.0 )
    ifault = 2;
    return
  end

  ifault = 0;
  xx = 0.5 * v;
  c = xx - 1.0;
%
%  Starting approximation for small chi-squared
%
  if ( v < - c5 * log ( p ) )

    ch = ( p * xx * exp ( g + xx * aa ) )^( 1.0 / xx );

    if ( ch < e )
      value = ch;
      return
    end
%
%  Starting approximation for V less than or equal to 0.32
%
  elseif ( v <= c3 )

    ch = c4;
    a = log ( 1.0 - p );

    while ( 1 )

      q = ch;
      p1 = 1.0 + ch * ( c7 + ch );
      p2 = ch * ( c9 + ch * ( c8 + ch ) );

      t = - 0.5 + (c7 + 2.0 * ch ) / p1 ...
        - ( c9 + ch * ( c10 + 3.0 * ch ) ) / p2

      ch = ch - ( 1.0 - exp ( a + g + 0.5 * ch + c * aa ) * p2 / p1) / t;

      if ( abs ( q / ch - 1.0 ) <= c1 )
        break
      end

    end

  else
%
%  Call to algorithm AS 111 - note that P has been tested above.
%  AS 241 could be used as an alternative.
%
   [ x, ifault ] = ppnd ( p );
%
%  Starting approximation using Wilson and Hilferty estimate
%
    p1 = c2 / v;
    ch = v * ( x * sqrt ( p1 ) + 1.0 - p1)^3;
%
%  Starting approximation for P tending to 1.
%
    if ( c6 * v + 6.0 < ch )
       ch = - 2.0 * ( log ( 1.0 - p ) - c * log ( 0.5 * ch ) + g );
    end

  end
%
%  Call to algorithm AS 239 and calculation of seven term
%  Taylor series
%
  for i = 1 : maxit

    q = ch;
    p1 = 0.5 * ch;
    [ temp, if1 ] = gammad ( p1, xx );
    p2 = p - temp;

    if ( if1 ~= 0 )
      ifault = 3;
      return
    end

    t = p2 * exp ( xx * aa + g + p1 - c * log ( ch ) );
    b = t / ch;
    a = 0.5 * t - b * c;
    s1 = ( c19 + a * ( c17 + a * ( c14 + a * ( c13 + a * ( c12 + ...
      c11 * a ))))) / c24;
    s2 = ( c24 + a * ( c29 + a * ( c32 + a * ( c33 + c35 * a )))) / c37;
    s3 = ( c19 + a * ( c25 + a * ( c28 + c31 * a ))) / c37;
    s4 = ( c20 + a * ( c27 + c34 * a) + c * ( c22 + a * ( c30 + c36 * a ))) ...
      / c38;
    s5 = ( c13 + c21 * a + c * ( c18 + c26 * a )) / c37;
    s6 = ( c15 + c * ( c23 + c16 * c )) / c38;
    ch = ch + t * ( 1.0 + 0.5 * t * s1 - b * c * ( s1 - b * ...
      ( s2 - b * ( s3 - b * ( s4 - b * ( s5 - b * s6 ))))));

    if ( e < abs ( q / ch - 1.0 ) )
       value = ch;
       return
    end

  end

  ifault = 4;
  value = ch;

  return
end


function imf = bwtfilter(im,f)
% function imf = bwtfilter(im,f)
%
% BWT decimated filtering
% Version 1.2
%
% This is faster than doing the complete filtering operation with conv2 and
% then decimating the result
%
% Arguments:
%  im: A square image, with side length a multiple of 3
%  f:  A 3x3 filter
%
% Result:
%  imf: im is filtered with f, and the result is decimated, taking every
%       3rd value in x and y. This code is equivalent to:
%       imf = conv2(im, rot90(rot90(f)),'same');
%       imf = imf(2:3:end,2:3:end);
%
% Citation:
%  Willmore B, Prenger RJ, Wu MC and Gallant JL (2008). The Berkeley
%  Wavelet Transform: A biologically-inspired orthogonal wavelet transform.
%  Neural Computation 20:6, 1537-1564
%
% The article is available at:
%  <http://dx.doi.org/10.1162/neco.2007.05-07-513>
%
% Copyright (c) 2008 Ben Willmore
%
% Permission is hereby granted, free of charge, to any person
% obtaining a copy of this software and associated documentation
% files (the "Software"), to deal in the Software without
% restriction, including without limitation the rights to use,
% copy, modify, merge, publish, distribute, sublicense, and/or sell
% copies of the Software, and to permit persons to whom the
% Software is furnished to do so, subject to the following
% conditions:
%
% The above copyright notice and this permission notice shall be
% included in all copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
% OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
% HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
% WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
% OTHER DEALINGS IN THE SOFTWARE.

sz = size(im);

if (length(sz) ~= 2) || (sz(1) ~= sz(2))
  disp('Input must be square');
  decomp = nan;
  return;
end

sz = sz(1);
ssz = sz/3;

if ( (ssz-floor(ssz)) > abs(ssz)*eps )
  fprintf('Side length must be a multiple of 3');
  decomp = nan;
  return;
end

f_rep = repmat(f,ssz,ssz);

imdot = im .* f_rep;

imf = zeros(ssz);

for yy = 1:3
  for xx = 1:3
    imf = imf + imdot(yy:3:end,xx:3:end);
  end
end


% Generate time points for evaluating spline.
%
%  The convex-combination of the endpoitns with
%  five controls points are 80 percent the last cpt
%  and 20 percent the control point after that.
%
% Input
%   nland: number of landmarks
%   neval: number of evaluations
%
% Output
%   s: the time points used to evaluate spline
function [s,lb,ub] = bspline_gen_s(nland,neval)
    if nargin < 2
       neval = 200;
    end

    lb = 2;
    ub = nland+1;
    epts = [lb ub];

    len = epts(2)-epts(1);
    int = len/(neval-1);
    s = epts(1):int:epts(2);
end


%function [] = test_fig2u3d_contour_surf

clf

res = [30, 31];
q = domain2vec([-2, 2, -2, 2], res);

x = q(1, :);
y = q(2, :);
z = -sin(x) .*cos(y);

ax = gca;
hold(ax, 'on')
%vcontourf(ax, q, z, res);
vcontour(ax, q, z, res);
vsurf(ax, q, z, res);
plot_scalings(ax, 0)

%{
h = get(gca, 'children');
hp = get(h(2), 'Children');
fc = get(hp(1), 'Faces');

x = v(:, 1);
y = v(:, 2);
x(isnan(x) ) = [];
y(isnan(y) ) = [];

dt = DelaunayTri(x, y);
triplot(dt, 'Parent', newax)
%}
fig2u3d(ax, 'test')

axis(ax, 'equal')


function demoRevolutionSurface
%DEMOREVOLUTIONSURFACE Demo of revolutionSurface
%
%   Example
%     demoRevolutionSurface
%
%   See also
%

% ------
% Author: David Legland
% e-mail: david.legland@inra.fr
% Created: 2007-04-20
% Copyright 2007 INRA - BIA PV Nantes - MIAJ Jouy-en-Josas.

%% Draw a torus with vertical axis as revolution axis

circle  = circleToPolygon([10 0 3], 50);
[x, y, t] = revolutionSurface(circle, linspace(0, 4*pi/3, 50));

figure;
surf(x, y, t);
axis equal;

%% Draw a torus with horizontal axis as revolution axis

circle  = circleToPolygon([0 10 3], 50);
[x, y, t] = revolutionSurface(circle, [0 0 1 0], linspace(0, pi/3, 50));

figure;
surf(x, y, t);
axis equal;
drawnow;

end

%% Inner function to avoid call to geom2d module
function varargout = circleToPolygon(circle, varargin)
%CIRCLETOPOLYGON Convert a circle into a series of points
%
%   P = circleToPolygon(CIRC, N);
%   Converts the circle CIRC into an array of  (N+1)-by-2 of double,
%   containing x and y positions of vertices.
%   CIRC is given as [x0 y0 r], where x0 and y0 are coordinate of center,
%   and r is the radius.
%   The resulting polygon is closed (first and last vertices are the same).
%
%   P = circleToPolygon(CIRCLE);
%   uses a default value of N=64 vertices.
%
%   Example
%   circle = circleToPolygon([10 0 5], 16);
%   figure;
%   drawPolygon(circle);
%
%   See also:
%   circles2d, polygons2d, circleArcToPolyline, ellipseToPolygon
%
%
% ---------
% author : David Legland
% created the 06/04/2005.
% Copyright 2010 INRA - Cepia Software Platform.
%

% HISTORY
% 2007-04-20 return a closed polygon with N+1 vertices, use default N=64
% 2011-12-09 rename to 'circleToPolygon'

% determines number of points
N = 64;
if ~isempty(varargin)
    N = varargin{1};
end

% create circle
t = linspace(0, 2*pi, N+1)';
x = circle(1) + circle(3) * cos(t);
y = circle(2) + circle(3) * sin(t);

if nargout == 1
    varargout{1} = [x y];
elseif nargout == 2
    varargout{1} = x;
    varargout{2} = y;
end

end


% A program of type function
% Program name is def611.m
% To accompany the textbook:
% Applications of MATLAB: Numerical Solutions.
% By Yasin A. Shiboul
% This function defines the differential equation required to be solved in  question 11 of chapter 6
% the differential equation  " dy/dt = y+t".
%
function dy=def611(t,y)
dy=[y+t]


function [Hn,Xn] = myHist(Data)

nBins = round(length(Data) / 15);

[H,X] = hist(Data, nBins);

[Max,IMax] = max(H);

sumH = sum(H);
curSum = 0.0;

T = 0.990;

i1 = IMax;
i2 = IMax;
I1 = i1;
I2 = i2;
stop1 = 0;
stop2 = 0;
while ((i1>=1) || (i2<=length(X)))
    if (i1~=i2)
        if (stop1~=1) curSum = curSum + H(i1); end
        if (stop2~=1) curSum = curSum + H(i2); end
    else
        curSum = curSum + H(i1);
    end
    if (curSum <= sumH * T)
        I1 = i1;
        I2 = i2;
        if (i1>1)
            i1 = i1 - 1;
        else
            stop1 = 1;
        end
        if (i2<length(X))
            i2 = i2 + 1;
        else
            stop2 = 1;
        end
    else
        break;
    end
end

Xn = X(I1:I2);
Hn = H(I1:I2);

%plot(Xn,Hn + max(H));
%hold on;
%plot(X,H,'r')


% test code for tt_qlaplace_dd()
%
% September 22, 2010
% Vladimir Kazeev
% vladimir.kazeev@gmail.com
% INM RAS
% Moscow, Russia
%
% Look for details in the Preprint No. 75, 2010 of
% Max-Planck Institute for Mathematics in the Sciences
% Vladimir A. Kazeev and Boris N. Khoromskij
% On explicit QTT representation of Laplace operator and its inverse
% http://www.mis.mpg.de/publications/preprints/2010/prepr2010-75.html

% d is the only parameter
d=[3,4,5];
%

D=size(d,2);
tt=tt_qlaplace_dd(d);
tt=tt_mat_to_vec(tt);

full=nd_to_full(tt);

Z=zeros(2^sum(d));
for k=1 : D
	L=2*eye(2^d(k));
	for i=1 : 2^d(k)-1
		L(i,i+1)=-1;
		L(i+1,i)=-1;
	end
	for m=k-1 : -1: 1
		L=kron(eye(2^d(m)),L);
	end
	for m=k+1 : D
		L=kron(L,eye(2^d(m)));
	end
	Z=Z+L;
end
err=norm(full-Z,'fro');
fprintf('fro err = %e\n', err);


%% Test constant objective

%% LP
clc
% Linear Objective & Bias
f = -[6 5]';
objbias = 5;
% Linear Constraints
A = ([1,4; 6,4; 2, -5]);
b = [16;28;6];
lb = [0;0]; ub = [10;10];
%Build Object
Opt = opti('f',f,'objbias',objbias,'ineq',A,b,'bounds',lb,ub)
%Build & Solve
[x,fval,exitflag,info] = solve(Opt)
%Plot
plot(Opt)

%% QP
P = coinRead('testQP.qps')

O = opti(P,optiset('solver','scip','display','iter'))
[x,f] = solve(O)
plot(O)

%% MILP2
clc
%Objective & Constraints
f = -[1 2 3 1]';
A = [-1 1 1 10; 1 -3 1 0];
b = [20;30];
Aeq = [0 1 0 -3.5];
beq = 0;
%Setup Options
opts = optiset('solver','cbc','display','iter');
%Build & Solve
Opt = opti('grad',f,'ineq',A,b,'eq',Aeq,beq,'bounds',[0 0 0 2]',[40 inf inf 3]','int','CCCI','options',opts,'objbias',10)
[x,fval,exitflag,info] = solve(Opt)
plot(Opt)

%% QCQP 1
clc
%Objective & Constraints
H = [33 6    0;
     6  22   11.5;
     0  11.5 11];
f = [-1;-2;-3];
A = [-1 1 1; 1 -3 1];
b = [20;30];
Q = eye(3);
l = [2;2;2];
r = 0.5;
lb = [0;0;0];
ub = [40;inf;inf];
%Build & Solve
Opt = opti('H',H,'f',f,'ineq',A,b,'qc',Q,l,r,'bounds',lb,ub,'objbias',10,'options',optiset('display','iter','solver','ipopt'))
[x,fval,exitflag,info] = solve(Opt)


function  [alpha, beta, Tau1]    =  Cal_Parameters( im, par, Dict, blk_arr, wei_arr )
[h w ch]   =   size(im);
A          =   Dict.D0;
PCA_idx    =   Dict.cls_idx;
s_idx      =   Dict.s_idx;
seg        =   Dict.seg;

b          =   par.win;
b2         =   b*b*ch;
k          =   0;
s          =   par.step;

N     =  h-b+1;
M     =  w-b+1;
L     =  N*M;
r     =  [1:s:N];
r     =  [r r(end)+1:N];
c     =  [1:s:M];
c     =  [c c(end)+1:M];
X     =  zeros(b*b,L,'single');
for i  = 1:b
    for j  = 1:b
        k    =  k+1;
        blk  =  im(i:h-b+i,j:w-b+j);
        blk  =  blk(:);
        X(k,:) =  blk';
    end
end

m_X       =   zeros(length(r)*length(c),b*b,'single');
X1        =   X';

for i = 1:par.nblk
   v            =   wei_arr(:,i);
   m_X(:,:)     =   m_X(:,:) + X1(blk_arr(:,i),:) .*v(:, ones(1,b2));
end
m_X          =   m_X';

N            =   length(r);
M            =   length(c);
L            =   N*M;
ind          =   zeros(N,M);
ind(r,c)     =   1;

X1           =   X(:, ind~=0);

alpha        =   zeros(b2, L, 'single' );
beta         =   zeros(b2, L, 'single' );
s0           =   zeros(b2, L, 'single' );

idx            =   s_idx(seg(1)+1:seg(2));
L0             =   length(idx);
alpha(:,idx)   =   A*X1(:,idx);
beta(:,idx)    =   A*m_X(:,idx);
for  k  =  1 : L0
    i           =   idx(k);
    a           =   A*( X(:, blk_arr(i, 1:par.nblk)) - repmat( m_X(:, i), 1, par.nblk ));
    s0(:,i)     =   mean(a.^2, 2);
end

for   i  = 2:length(seg)-1
    idx            =   s_idx(seg(i)+1:seg(i+1));
    cls            =   PCA_idx(idx(1));
    P              =   reshape(Dict.PCA_D(:, cls), b2, b2);
    alpha(:,idx)   =   P*X1(:,idx);
    beta(:,idx)    =   P*m_X(:,idx);
    for  j  =  1 : length(idx)
        k           =   idx(j);
        a           =   P*( X(:,blk_arr(k, 1:par.nblk)) - repmat( m_X(:, k), 1, par.nblk ));
        s0(:,k)     =   mean(a.^2, 2);
    end
end
s0       =   max(0, s0-par.nSig^2);
Tau1     =   (par.c1*sqrt(2)*par.nSig^2)./(sqrt(s0) + eps);
return;


function M = stiefelfactory(n, p, k, gpuflag)
% Returns a manifold structure to optimize over orthonormal matrices.
%
% function M = stiefelfactory(n, p)
% function M = stiefelfactory(n, p, k)
% function M = stiefelfactory(n, p, k, gpuflag)
%
% The Stiefel manifold is the set of orthonormal nxp matrices. If k
% is larger than 1, this is the Cartesian product of the Stiefel manifold
% taken k times. The metric is such that the manifold is a Riemannian
% submanifold of R^nxp equipped with the usual trace inner product, that
% is, it is the usual metric.
%
% Points are represented as matrices X of size n x p x k (or n x p if k=1,
% which is the default) such that each n x p matrix is orthonormal,
% i.e., X'*X = eye(p) if k = 1, or X(:, :, i)' * X(:, :, i) = eye(p) for
% i = 1 : k if k > 1. Tangent vectors are represented as matrices the same
% size as points.
%
% The default retraction is QR-based: it is only a first-order retraction.
% To use the polar retraction (which is second order), run
%    M.retr = M.retr_polar;
% after creating M with this factory. This can be reverted with
%    M.retr = M.retr_qr;
% If used, you may also want to update M.invretr similarly.
%
% Set gpuflag = true to have points, tangent vectors and ambient vectors
% stored on the GPU. If so, computations can be done on the GPU directly.
%
% By default, k = 1 and gpuflag = false.
%
% See also: grassmannfactory rotationsfactory

% This file is part of Manopt: www.manopt.org.
% Original author: Nicolas Boumal, Dec. 30, 2012.
% Contributors:
% Change log:
%  July  5, 2013 (NB) : Added ehess2rhess.
%  Jan. 27, 2014 (BM) : Bug in ehess2rhess corrected.
%  June 24, 2014 (NB) : Added true exponential map and changed the randvec
%                       function so that it now returns a globally
%                       normalized vector, not a vector where each
%                       component is normalized (this only matters if k>1).
%  July 17, 2018 (NB) : Now both QR (default) and polar retractions are
%                       directly accessible, and their inverses are also
%                       implemented.
%  Aug.  2, 2018 (NB) : Added GPU support: just set gpuflag = true.
%  June 18, 2019 (NB) : Using qr_unique for retr and rand.
%  July  9, 2019 (NB) : Added a comment about QR retraction being first
%                       order only.
%  Jan.  8, 2021 (NB) : Added tangent2ambient+tangent2ambient_is_identity.

    assert(n >= p, 'The dimension n must be larger than the dimension p.');

    if ~exist('k', 'var') || isempty(k)
        k = 1;
    end
    if ~exist('gpuflag', 'var') || isempty(gpuflag)
        gpuflag = false;
    end

    % If gpuflag is active, new arrays (e.g., via rand, randn, zeros, ones)
    % are created directly on the GPU; otherwise, they are created in the
    % usual way (in double precision).
    if gpuflag
        array_type = 'gpuArray';
    else
        array_type = 'double';
    end

    if k == 1
        M.name = @() sprintf('Stiefel manifold St(%d, %d)', n, p);
    elseif k > 1
        M.name = @() sprintf('Product Stiefel manifold St(%d, %d)^%d', n, p, k);
    else
        error('k must be an integer no less than 1.');
    end

    M.dim = @() k*(n*p - .5*p*(p+1));

    M.inner = @(x, d1, d2) d1(:).'*d2(:);

    M.norm = @(x, d) norm(d(:));

    M.dist = @(x, y) error('stiefel.dist not implemented yet.');

    M.typicaldist = @() sqrt(p*k);

    M.proj = @projection;
    function Up = projection(X, U)

        XtU = multiprod(multitransp(X), U);
        symXtU = multisym(XtU);
        Up = U - multiprod(X, symXtU);

% The code above is equivalent to, but faster than, the code below.
%
%     Up = zeros(size(U));
%     function A = sym(A), A = .5*(A+A'); end
%     for i = 1 : k
%         Xi = X(:, :, i);
%         Ui = U(:, :, i);
%         Up(:, :, i) = Ui - Xi*sym(Xi'*Ui);
%     end

    end

    M.tangent = M.proj;

    M.tangent2ambient_is_identity = true;
    M.tangent2ambient = @(X, U) U;

    % For Riemannian submanifolds, converting a Euclidean gradient into a
    % Riemannian gradient amounts to an orthogonal projection.
    M.egrad2rgrad = M.proj;

    M.ehess2rhess = @ehess2rhess;
    function rhess = ehess2rhess(X, egrad, ehess, H)
        XtG = multiprod(multitransp(X), egrad);
        symXtG = multisym(XtG);
        HsymXtG = multiprod(H, symXtG);
        rhess = projection(X, ehess - HsymXtG);
    end

    M.retr_qr = @retraction_qr;
    function Y = retraction_qr(X, U, t)
        % It is necessary to call qr_unique rather than simply qr to ensure
        % this is a retraction, to avoid spurious column sign flips.
        if nargin < 3
            Y = qr_unique(X + U);
        else
            Y = qr_unique(X + t*U);
        end
    end

    M.invretr_qr = @invretr_qr;
    function U = invretr_qr(X, Y)
        XtY = multiprod(multitransp(X), Y);
        R = zeros(p, p, k, array_type);
        H = 2*eye(p, array_type);
        for kk = 1 : k
            % For each slice, assuming the inverse retraction is well
            % defined for the given inputs, we have:
            %   X + U = YR
            % Left multiply with X' to get
            %   I + X'U = X'Y R
            % Since X'U is skew symmetric for a tangent vector U at X, add
            % up this equation with its transpose to get:
            %   2I = (X'Y) R + R' (X'Y)'
            % Contrary to the polar factorization, here R is not symmetric
            % but it is upper triangular. As a result, this is not a
            % Sylvester equation and we must solve it differently.
            R(:, :, kk) = solve_for_triu(XtY(:, :, kk), H);
            % Then,
            %   U = YR - X
            % which is what we compute below.
        end
        U = multiprod(Y, R) - X;
    end

    M.retr_polar = @retraction_polar;
    function Y = retraction_polar(X, U, t)
        if nargin < 3
            Y = X + U;
        else
            Y = X + t*U;
        end
        for kk = 1 : k
            [u, s, v] = svd(Y(:, :, kk), 'econ'); %#ok
            Y(:, :, kk) = u*v';
        end
    end

    M.invretr_polar = @invretr_polar;
    function U = invretr_polar(X, Y)
        XtY = multiprod(multitransp(X), Y);
        MM = zeros(p, p, k, array_type);
        H = 2*eye(p, array_type);
        for kk = 1 : k
            % For each slice, assuming the inverse retraction is well
            % defined for the given inputs, we have:
            %   X + U = YM
            % Left multiply with X' to get
            %   I + X'U = X'Y M
            % Since X'U is skew symmetric for a tangent vector U at X, add
            % up this equation with its transpose to get:
            %   2I = (X'Y) M + M' (X'Y)'
            %      = (X'Y) M + M (X'Y)'   since M is symmetric.
            % Solve for M symmetric with a call to sylvester:
            MM(:, :, kk) = sylvester_nochecks(XtY(:, :, kk), XtY(:, :, kk)', H);
            % Note that the above is really a Lyapunov equation: it could
            % be solved faster by exploiting the fact the same matrix
            % appears twice on the left, with one the transpose of the
            % other. Then,
            %   U = YM - X
            % which is what we compute below.
        end
        U = multiprod(Y, MM) - X;
    end

    % By default, we use the QR retraction
    M.retr = M.retr_qr;
    M.invretr = M.invretr_qr;

    M.exp = @exponential;
    function Y = exponential(X, U, t)
        if nargin == 2
            tU = U;
        else
            tU = t*U;
        end
        Y = zeros(size(X), array_type);
        I = eye(p, array_type);
        Z = zeros(p, array_type);
        for kk = 1 : k
            % From a formula by Ross Lippert, Example 5.4.2 in AMS08.
            Xkk = X(:, :, kk);
            Ukk = tU(:, :, kk);
            Y(:, :, kk) = [Xkk Ukk] * ...
                         expm([Xkk'*Ukk , -Ukk'*Ukk ; I , Xkk'*Ukk]) * ...
                         [ expm(-Xkk'*Ukk) ; Z ];
        end

    end

    M.hash = @(X) ['z' hashmd5(X(:))];

    M.rand = @() qr_unique(randn(n, p, k, array_type));

    M.randvec = @randomvec;
    function U = randomvec(X)
        U = projection(X, randn(n, p, k, array_type));
        U = U / norm(U(:));
    end

    M.lincomb = @matrixlincomb;

    M.zerovec = @(x) zeros(n, p, k, array_type);

    M.transp = @(x1, x2, d) projection(x2, d);

    M.vec = @(x, u_mat) u_mat(:);
    M.mat = @(x, u_vec) reshape(u_vec, [n, p, k]);
    M.vecmatareisometries = @() true;

    % Automatically convert a number of tools to support GPU.
    if gpuflag
        M = factorygpuhelper(M);
    end

end


%ISVEC Test if vector
%
% ISVEC(V) is true (1) if the argument V is a 3-vector, else false (0).
%
% ISVEC(V, L) is true (1) if the argument V is a vector of length L,
% either a row- or column-vector.  Otherwise false (0).
%
% Notes::
% - Differs from MATLAB builtin function ISVECTOR, the latter returns true
%   for the case of a scalar, ISVEC does not.
% - Gives same result for row- or column-vector, ie. 3x1 or 1x3 gives true.
%
% See also ISHOMOG, ISROT.

% Copyright (C) 1993-2014, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

function h = isvec(v, l)
    if nargin == 1
            l = 3;
    end
    d = size(v);
    h = logical( length(d) == 2 && min(d) == 1 && numel(v) == l );


% book : Signals and Systems Laboratory with MATLAB
% authors : Alex Palamides & Anastasia Veloni
%
%
%

% even or odd
 t1=0:4
 t2=0:-1:-4

 %even
 x1=t1.^2
 x2=t2.^2

%  odd
 y1=t1.^3
 y2=t2.^3

 %analysis in even and odd parts
 n=-5:5;
 u=(n>=0);
 stem(n,u);

 figure
 u_n=(n<=0)
 ue=1/2*(u+ u_n);
 stem(n,ue);

 figure
 uo=1/2*(u- u_n);
 stem(n,uo);

 figure
 stem(n,ue+uo)


function [itrfin] = multisvm( T,C,test )
%MULTISVM(3.0) classifies the class of given training vector according to the
% given group and gives us result that which class it belongs.
% We have also to input the testing matrix

%Inputs: T=Training Matrix, C=Group, test=Testing matrix
%Outputs: itrfin=Resultant class(Group,USE ROW VECTOR MATRIX) to which tst set belongs

%----------------------------------------------------------------------%
% IMPORTANT: DON'T USE THIS PROGRAM FOR CLASS LESS THAN 3,             %
%            OTHERWISE USE svmtrain,svmclassify DIRECTLY or            %
%            add an else condition also for that case in this program. %
%            Modify required data to use Kernel Functions and Plot also%
%----------------------------------------------------------------------%
%                       Date:11-08-2011(DD-MM-YYYY)                    %
% This function for multiclass Support Vector Machine is written by
% ANAND MISHRA (Machine Vision Lab. CEERI, Pilani, India)
% and this is free to use. email: anand.mishra2k88@gmail.com

% Updated version 2.0 Date:14-10-2011(DD-MM-YYYY)
% Updated version 3.0 Date:04-04-2012(DD-MM-YYYY)

itrind=size(test,1);
itrfin=[];
Cb=C;
Tb=T;
for tempind=1:itrind
    tst=test(tempind,:);
    C=Cb;
    T=Tb;
    u=unique(C);
    N=length(u);
    c4=[];
    c3=[];
    j=1;
    k=1;
    if(N>2)
        itr=1;
        classes=0;
        cond=max(C)-min(C);
        while((classes~=1)&&(itr<=length(u))&& size(C,2)>1 && cond>0)
        %This while loop is the multiclass SVM Trick
            c1=(C==u(itr));
            newClass=c1;
            svmStruct = svmtrain(T,newClass,'kernel_function','rbf');   % I am using rbf kernel function, you must change it also
            classes = svmclassify(svmStruct,tst);

            % This is the loop for Reduction of Training Set
            for i=1:size(newClass,2)
                if newClass(1,i)==0;
                    c3(k,:)=T(i,:);
                    k=k+1;
                end
            end
        T=c3;
        c3=[];
        k=1;

            % This is the loop for reduction of group
            for i=1:size(newClass,2)
                if newClass(1,i)==0;
                    c4(1,j)=C(1,i);
                    j=j+1;
                end
            end
        C=c4;
        c4=[];
        j=1;

        cond=max(C)-min(C); % Condition for avoiding group
                            %to contain similar type of values
                            %and the reduce them to process

            % This condition can select the particular value of iteration
            % base on classes
            if classes~=1
                itr=itr+1;
            end
        end
    end

valt=Cb==u(itr);		% This logic is used to allow classification
val=Cb(valt==1);		% of multiple rows testing matrix
val=unique(val);
itrfin(tempind,:)=val;
end

end

% Give more suggestions for improving the program.


%% meshDistMarch
% Below is a demonstration of the features of the |meshDistMarch| function

%%
clear; close all; clc;

%% Syntax
% |[d,seedIndex]=meshDistMarch(F,V,indStart,optionStruct);|

%% Description
% The meshDistMarch function can be used to compute distances on meshes.
% The distances can be used for points sampling on the mesh or for
% remeshing.
% The function can operate on edge descriptions or face descriptions.
% Therefore for volumetric meshes (e.g. consisting of tetrahedra or
% hexahedra) appropriate face or edge data should be computed first to
% formulate the input.
%
% Input:
% E: the edges or faces for the mesh. E.g. an nx2 edge matrix or an nxm
% face matrix (n faces, m corners per face)
% V: the vertices for the mesh
% indStart: indices for one or more points to compute distances from
% optionStruct.toleranceLevel : The tolerance level for convergence. 0 is
% the default.
% optionStruct.numSeeds: Defines the number of seeds to generate on the mesh. Default is equal to startInd.
% optionStruct.waitBarOn=0; %Turn on/off waitbar
% optionStruct.unitEdgeOn=1; %Turn on/off the use of unit edge lengths
%
% Output:
% d: distances (from the start/seed points) on the mesh vertices
% seedIndex: nearest seed (or start) point indices for each vertex, forming
% a quasi-Voronoi tesselation.
% If the second output is not requested the performance is enhanced.

%% Examples

%%
% Plot settings
cMapDist=flipud(igviridis(250));
[cMapIndices,scrambleIndices]=scramble(viridis(250),1); %Colormap

faceAlpha1=1;
faceAlpha2=0.65;
fontSize=25;
markerSize=50;

%% Example: Edge or graph data

%%
% Create branching example. E defines edges and V is a vertex array

n=75;
x=linspace(0,0.9*pi,n);
y=sin(x);
V=[x(:) y(:) zeros(size(x(:)))];
V=evenlySampleCurve(V,n,'pchip',0);
x=V(:,1);
y=V(:,2);
dV=vecnormalize(diff(V,1,1));
VdV=V(1:1:end-1,:);
placePoints=1:3:n-1;
E=[(1:1:n-1)' (2:1:n)'];
numSteps=numel(placePoints);
l=linspace(0.75,0.25,numSteps);
a=linspace(0.25*pi,0.25*pi,numSteps);
for q=1:1:numSteps
    R=euler2DCM([0 0 a(q)]);
    vr1=dV(placePoints(q),:)*R.*l(q);
    vr2=dV(placePoints(q),:)*R'.*l(q);
    Vb=linspacen([x(placePoints(q)) y(placePoints(q)) 0],vr1+[x(placePoints(q)) y(placePoints(q)) 0],n)';
    Eb=[(1:1:n-1)' (2:1:n)'];
    E=[E; Eb+size(V,1)];
    V=[V; Vb];
    Vb=linspacen([x(placePoints(q)) y(placePoints(q)) 0],vr2+[x(placePoints(q)) y(placePoints(q)) 0],n)';
    Eb=[(1:1:n-1)' (2:1:n)'];
    E=[E; Eb+size(V,1)];
    V=[V; Vb];
end
E=[E;E+size(V,1);];
V2=V;
V2(:,2)=-V2(:,2);
V2(:,1)=-V2(:,1);
V=[V;V2];
E=[E;E+size(V,1);];
V2=V;
V2(:,2)=-V2(:,2);
V=[V;V2];
[E,V]=mergeVertices(E,V);

%%
% Compute distances on mesh

%Option set
indStart=1; %Index of the start point
optionStruct.toleranceLevel=0; %Tolerance for convergence
optionStruct.numSeeds=1; %Number of seeds
optionStruct.waitBarOn=0; %Turn on/off waitbar

%Compute distances on mesh description
d=meshDistMarch(E,V,indStart,optionStruct);

%%
% Visualization

cFigure; hold on;
title('Distances on an edge / graph model','fontSize',fontSize);
hp(1)=gpatch(E,V,'none',d,1,4);
hp(2)=plotV(V(indStart,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Start point(s)'},'Location','SouthOutSide');
axisGeom;
view(2);
colorbar;
drawnow;

%% Example: Triangulated data

%%
% Get example triangulated mesh data
[F,V]=stanford_bunny;%graphicsModels(1);

%%
% Compute distances on mesh

%Option set
[~,indStart]=min(V(:,1)); %Index of the start point
optionStruct.toleranceLevel=0; %Tolerance for convergence
optionStruct.numSeeds=1; %Number of seeds
optionStruct.waitBarOn=0; %Turn on/off waitbar

%Compute distances on mesh description
d=meshDistMarch(F,V,indStart,optionStruct);

%%
% Visualization

cFigure;
subplot(1,2,1);hold on;
title('Distances on a triangulated surface model','fontSize',fontSize);
gpatch(F,V,'kw',d,1);
hp(1)=gpatch(F,V,'none',d,1,2);
hp(2)=plotV(V(indStart,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Start point(s)'},'Location','SouthOutSide');
axisGeom;
colorbar;
camlight headlight;

subplot(1,2,2);hold on;
title('Distances on a triangulated surface model','fontSize',fontSize);
hp(1)=gpatch(F,V,d,'none',1);
hp(2)=plotV(V(indStart,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Start point(s)'},'Location','SouthOutSide');
axisGeom;
camlight headlight;
colorbar;
drawnow;

%% Example: Quadrangulated data

%%
% Get example quadrangulated mesh data
n=4;
r=1;
[F,V]=quadSphere(n,r);

%%
% Compute distances on mesh

%Option set
[~,indStart]=min(V(:,1)); %Index of the start point
optionStruct.toleranceLevel=0; %Tolerance for convergence
optionStruct.numSeeds=1; %Number of seeds
optionStruct.waitBarOn=0; %Turn on/off waitbar

%Compute distances on mesh description
d=meshDistMarch(F,V,indStart,optionStruct);

%%
% Visualization

cFigure;
subplot(1,2,1);hold on;
title('Distances on a quad surface model','fontSize',fontSize);
gpatch(F,V,'kw',d,1);
hp(1)=gpatch(F,V,'none',d,1,2);
hp(2)=plotV(V(indStart,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Start point(s)'},'Location','SouthOutSide');
axisGeom;
colorbar;
camlight headlight;

subplot(1,2,2);hold on;
title('Distances on a quad surface model','fontSize',fontSize);
hp(1)=gpatch(F,V,d,'none',1);
hp(2)=plotV(V(indStart,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Start point(s)'},'Location','SouthOutSide');
axisGeom;
camlight headlight;
colorbar;
drawnow;

%% Example: Hexahedral mesh data

%%
% Get example hexahedral mesh data
cubeDimensions=[1 1 1];
cubeElementNumbers=[10 10 10];
outputStructType=2; %A structure compatible with mesh view
[meshStruct]=hexMeshBox(cubeDimensions,cubeElementNumbers,outputStructType);

%Access elements, nodes, and faces from the structure
HEX=meshStruct.elements; %The elements
F=meshStruct.faces; %The faces
V=meshStruct.nodes; %The nodes (vertices)

%Get edges for mesh marching
E=patchEdges(F); %Mesh edges

%%
% Compute distances on mesh

%Option set
[~,indStart]=min(V(:,1)); %Index of the start point
optionStruct.toleranceLevel=0; %Tolerance for convergence
optionStruct.numSeeds=1; %Number of seeds
optionStruct.waitBarOn=0; %Turn on/off waitbar

%Compute distances on mesh description
d=meshDistMarch(E,V,indStart,optionStruct);

%%
% Plotting model boundary surfaces and a cut view

cFigure; hold on
title('Distances on a hexahedral mesh','FontSize',fontSize);
hp(1)=gpatch(E,V,'none',d,1,3);
hp(2)=plotV(V(indStart,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Start point(s)'},'Location','SouthOutSide');
colorbar;
axisGeom(gca,fontSize);
drawnow;

%% Example: Tetrahedral mesh data

%%
% Get example tetrahedral mesh data
[TET,V]=hex2tet(HEX,V,[],2);
F=element2patch(TET,V); %Element faces

%Get edges for mesh marching
E=patchEdges(F); %Mesh edges

%%
% Compute distances on mesh

%Option set
[~,indStart]=min(abs(V(:,1)-min(V(:,1)))+abs(V(:,2)-max(V(:,2)))+abs(V(:,3)-min(V(:,3)))); %Index of the start point
optionStruct.toleranceLevel=0; %Tolerance for convergence
optionStruct.numSeeds=1; %Number of seeds
optionStruct.waitBarOn=0; %Turn on/off waitbar

%Compute distances on mesh description
d=meshDistMarch(E,V,indStart,optionStruct);

%%
% Plotting model boundary surfaces and a cut view

cFigure; hold on
title('Distances on a tetrahedral mesh','FontSize',fontSize);
hp(1)=gpatch(E,V,'none',d,1,3);
hp(2)=plotV(V(indStart,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Start point(s)'},'Location','SouthOutSide');
colorbar;
axisGeom(gca,fontSize);
drawnow;

%% Example: Mesh types effecting marching based distance computation
% In this example 3 mesh variations for a sphere are created. For each the
% start point is the point with the minimum x coordinate, i.e. a point on
% the far left of the plot. For each the true distance should be a smooth
% gradient with a maximum which equals pi.
% The marching algorithm uses the mesh to march and compute distances. One
% can imaging that straight paths (geodesically speaking) yeild the
% shortest distances. Hence zig-zag pattern (geodesically speaking) create
% false increased distances. This is not compensated for in this algorithm.
% Therefore the distance map depends on the mesh type and mesh
% connectivity. In the below example the regular quadrilateral mesh
% contains a straight path to the farthest point allong the equator. With
% mesh refinement the maximum distance would therefore converge on pi.
% However, other directions for the quadrilateral mesh produce zig-zag
% patterns causing distance to be altered. Hence the distance map departs
% from the smooth gradient allong the x-direction, one would expect. The
% triangulated mesh converted from the quadrilateral mesh contains both a
% straight path at the equator and also improved connectivity for other
% directions. The uniform geodesic triangulation contains the most smooth
% distance map.

%%
% Getting 3 different mesh types for a sphere.

n=3;
r=1;
[F1,V1]=quadSphere(n,r);
[F2,V2]=quad2tri(F1,V1);
[F3,V3]=geoSphere(n,r);

%%
% Compute distances on mesh

% -> Surface 1
%Option set
[~,indStart1]=min(V1(:,1)); %Index of the start point
optionStruct.toleranceLevel=0; %Tolerance for convergence
optionStruct.numSeeds=1; %Number of seeds
optionStruct.waitBarOn=0; %Turn on/off waitbar

%Compute distances on mesh description
[d1,i1]=meshDistMarch(F1,V1,indStart1,optionStruct);

% -> Surface 2
%Option set
[~,indStart2]=min(V2(:,1)); %Index of the start point
optionStruct.toleranceLevel=0; %Tolerance for convergence
optionStruct.numSeeds=1; %Number of seeds
optionStruct.waitBarOn=0; %Turn on/off waitbar

%Compute distances on mesh description
[d2,i2]=meshDistMarch(F2,V2,indStart2,optionStruct);

% -> Surface 3
%Option set
[~,indStart3]=min(V3(:,1)); %Index of the start point
optionStruct.toleranceLevel=0; %Tolerance for convergence
optionStruct.numSeeds=1; %Number of seeds
optionStruct.waitBarOn=0; %Turn on/off waitbar

%Compute distances on mesh description
[d3,i3]=meshDistMarch(F3,V3,indStart3,optionStruct);

%%
% Visualization

cFigure;
subplot(1,3,1);hold on;
title('Regular quad mesh','fontSize',fontSize);
hp(1)=gpatch(F1,V1,d1,d1);
hp(2)=plotV(V1(indStart1,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Start point(s)'},'Location','SouthOutSide');
axisGeom;
colorbar; caxis([0 pi]);
camlight headlight;
view(2);

subplot(1,3,2);hold on;
title('Irregular quad mesh','fontSize',fontSize);
hp(1)=gpatch(F2,V2,d2,d2);
hp(2)=plotV(V2(indStart2,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Start point(s)'},'Location','SouthOutSide');
axisGeom;
colorbar; caxis([0 pi]);
camlight headlight;
view(2);

subplot(1,3,3);hold on;
title('Geodesic triangulated mesh','fontSize',fontSize);
hp(1)=gpatch(F3,V3,d3,d3);
hp(2)=plotV(V3(indStart3,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Start point(s)'},'Location','SouthOutSide');
axisGeom;
colorbar; caxis([0 pi]);
camlight headlight;
view(2);

drawnow;

%% Example: Using |meshDistMarch| for geodesic point sampling

%%
% Get example triangulated mesh data
[F,V]=graphicsModels(7);

%%
% Compute distances on mesh

numSeeds=250;

%Option set
[~,indStart]=min(V(:,1)); %Index of the start point
optionStruct.toleranceLevel=0; %Tolerance for convergence
optionStruct.numSeeds=numSeeds; %Number of seeds
optionStruct.waitBarOn=1; %Turn on/off waitbar

%Use weigths based on z-direction
% W=V(:,3);
% W=W-min(W);
% W=W./max(W);
% W=(W*9)+1;
% optionStruct.W=W;

%Compute distances on mesh description
[d,seedIndex]=meshDistMarch(F,V,indStart,optionStruct);
[indSeeds,~,ind2]=unique(seedIndex);

%%
% Visualization

cFigure;
subplot(1,2,1); hold on;
title('Distances on a triangulated surface model','fontSize',fontSize);
hp(1)=gpatch(F,V,d,'none',1); hp(1).FaceColor='Interp';
hp(2)=plotV(V(indSeeds,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Seed point(s)'},'Location','SouthOutSide');
axisGeom;
camlight headlight;
colormap(gca,cMapDist); colorbar;

subplot(1,2,2); hold on;
title('Seed indices','fontSize',fontSize);
hp(1)=gpatch(F,V,'kw',ind2,1);
hp(2)=plotV(V(indSeeds,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Seed point(s)'},'Location','SouthOutSide');
axisGeom;
camlight headlight;
colormap(gca,cMapIndices); %icolorbar;
drawnow;

%% Example: Using |meshDistMarch| for geodesic surface resampling
% See also: |remeshTriSurfDistMap|

[Fd,Vd,indSeed]=seedIndex2triangulation(F,V,seedIndex);

%%
% Visualization

cFigure;
subplot(1,2,1); hold on;
title('Distances on a triangulated surface model','fontSize',fontSize);
hp(1)=gpatch(F,V,d,'none',1); hp(1).FaceColor='Interp';
hp(2)=plotV(V(indSeeds,:),'k.','MarkerSize',markerSize);
legend(hp,{'Mesh distances','Seed point(s)'},'Location','SouthOutSide');
axisGeom;
camlight headlight;
colormap(gca,cMapDist); colorbar;

subplot(1,2,2); hold on;
title('Resampled surface model','fontSize',fontSize);
plotV(V(indSeed,:),'k.','MarkerSize',50);
hp(1)=gpatch(F,V,'kw','none',0.5);
hp(2)=gpatch(Fd,Vd,'gw','k',1,2);
legend(hp,{'Original mesh','Resampled mesh'},'Location','SouthOutSide');

axisGeom;
camlight headlight;
drawnow;

%% Example: Using unit edge lengths
% Forcing unit edge lenghts means each edge is considered equally long i.e.
% a length of 1. Hence when used in combination with resampling, this
% causes the algorithm to resample dense regions in a dense fashion and
% coarse regions in a coarse fashion. Therefore using
% optionStruct.unitEdgeOn=1; one can force the resampling to have similar
% degrees of relative density differences. In the example below a dinosaur
% mesh with a fine mesh at the limbs and a coarse mesh on the main body is
% resampled using unit edge lengths. The output can be seen to remain
% refined at the limbs.

%%
% Get example triangulated mesh data
[F,V]=graphicsModels(4);
[F,V]=subtri(F,V,2);

%%
% Compute distances on mesh

%Option set
[~,indStart]=min(V(:,1)); %Index of the start point
optionStruct.toleranceLevel=0; %Tolerance for convergence
optionStruct.numSeeds=1000; %Number of seeds
optionStruct.waitBarOn=1; %Turn on/off waitbar
optionStruct.unitEdgeOn=1;

%Compute distances on mesh description
[d,seedIndex]=meshDistMarch(F,V,indStart,optionStruct);
[indSeeds,~,ind2]=unique(seedIndex);

%Compute resampled surface
[Fd,Vd,indSeed]=seedIndex2triangulation(F,V,seedIndex);

%%
% Visualization

cFigure;
subplot(1,2,1); hold on;
title('Distances on a triangulated surface model','fontSize',fontSize);
hp(1)=gpatch(F,V,d,'none',1); hp(1).FaceColor='Interp';
hp(2)=plotV(V(indSeeds,:),'k.','MarkerSize',25);
legend(hp,{'Mesh distances','Seed point(s)'},'Location','SouthOutSide');
axisGeom;
camlight headlight;
colormap(gca,cMapDist); colorbar;

subplot(1,2,2); hold on;
title('Resampled surface model','fontSize',fontSize);
plotV(V(indSeed,:),'k.','MarkerSize',25);
hp(1)=gpatch(F,V,'kw','none',0.5);
hp(2)=gpatch(Fd,Vd,'gw','k',1,2);
legend(hp,{'Original mesh','Resampled mesh'},'Location','SouthOutSide');

axisGeom;
camlight headlight;
drawnow;

%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


% CLASSIF_RECOG Calculates the average recognition rate
%
% Usage
%    [rr_mean,recog_rate] =  CLASSIF_RECOG(labels,test_set,truth)
%
% Input
%    labels (int): The labels attributed to the testing instances.
%    test_set (int): The object indices of the testing instances.
%    truth: the actual labels of the testing instances
%
% Output
%    rr_mean (real): The mean recognition rate
%    recog_rate(real): array containing the individual recognition rates of
%       each class.
%
% Description
%    This function computes the average recognition rate of each class.
%    It is a widely used measure of the performance of the classifier when the
%    data set is highly unbalanced.
%
% See also
%    SVM_TEST, CLASSIF_ERR, CLASSIF_RECOG

function [rg_mean,recog_rate]=classif_recog(labels,test_set,truth)
    if isstruct(truth)
        src=truth;
        truth = [src.objects.class];
    end

    % Normally, the test_set contains samples of all classes
    recog_rate=zeros(1,max(truth));
    gdTruth=truth(:,test_set);

    for k=1:max(truth)
        mask=k==gdTruth;
        good_elts=find(labels==k & mask);

        mask1=numel(find(mask==1));
        recog_rate(k)=numel(good_elts)/mask1;
    end

    rg_mean=mean(recog_rate);
end