%MDS Trainale mapping for multidimensional scaling, a variant of Sammon mapping
%
%   [W,J,STRESS] = MDS(DT,Y,OPTIONS)
%   [W,J,STRESS] = MDS(DT,K,OPTIONS)
%   [W,J,STRESS] = DT*MDS([],K,OPTIONS)
%   [W,J,STRESS] = DT*MDS(K,OPTIONS)
%              X = DS*W
%
%
% INPUT
%   DT      Square (M x M) dissimilarity matrix used for training
%   DS      N x M dissimilarity matrix between testset and trainset
%   Y       M x K matrix containing starting target configuration, or
%   K       Desired output dimensionality (default 2)
%   OPTIONS Various parameters of the  minimization procedure put into
%           a structure consisting of the following fields: 'q', 'optim',
%           'init','etol','maxiter', 'isratio', 'itmap', 'st' and 'inspect'
%           (default:
%
%              OPTIONS.q       = 0
%              OPTIONS.optim   = 'pn'
%              OPTIONS.init    = 'cs'
%              OPTIONS.etol    = 1e-6 (the precise value depends on q)
%              OPTIONS.maxiter = 100
%              OPTIONS.isratio = 0
%              OPTIONS.itmap   = 'yes'
%              OPTIONS.st      = 1
%              OPTIONS.inspect = 2).
%
% OUTPUT
%   W       Multidimensional scaling mapping
%   J       Index of points removed before optimization
%   STRESS  Vector of stress values
%   X       N x K dataset with output configuration
%
% DESCRIPTION
% Finds a nonlinear MDS map (a variant of the Sammon map) of objects
% represented by a symmetric distance matrix D with zero diagonal, given
% either the dimensionality K or the initial configuration Y. This is done
% in an iterative manner by minimizing the Sammon stress between the given
% dissimilarities D (DT or DS) and the distances DY in the K-dimensional
% target space:
%
%   E = 1/(sum_{i<j} D_{ij}^(Q+2)) sum_{i<j} (D_{ij} - DY_{ij})^2 * D_{ij}^Q
%
% If D(i,j) = 0 for any different points i and j, then one of them is
% superfluous. The indices of these points are returned in J.
%
% There is a simplified interface to MDS, called SAMMONM. The main
% differences are that SAMMONM operates on feature based datasets, while MDS
% expects dissimilarity matrices; MDS maps new objects by a second
% optimization procedures minimizing the stress for the test objects, while
% SAMMONM uses a linear mapping between dissimilarities and the target
% space. See also PREX_MDS for examples.
%
% OPTIONS is an optional variable, using which the parameters for the mapping
% can be controlled. It may contain the following fields:
%
%   Q        Stress measure to use (see above): -2,-1,0,1 or 2.
%   INIT     Initialisation method for Y: 'randp', 'randnp', 'maxv', 'cs'
%            or 'kl'. See MDS_INIT for an explanation.
%   OPTIM    Minimization procedure to use: 'pn' for Pseudo-Newton or
%            'scg' for Scaled Conjugate Gradients.
%   ETOL     Tolerance of the minimization procedure. Usually, it should be
%   MAXITER  in the order of 1e-6. If MAXITER is given (see below), then the
%            optimization is stopped either when the error drops below ETOL or
%            MAXITER iterations are reached.
%   ISRATIO  Indicates whether a ratio MDS should be performed (1) or not (0).
%            If ISRATIO is 1, then instead of fitting the dissimilarities
%            D_{ij}, A*D_{ij} is fitted in the stress function. The value A
%            is estimated analytically in each iteration.
%   ITMAP    Determines the way new points are mapped, either in an iterative
%            manner ('yes') by minimizing the stress; or by a linear projection
%            ('no').
%   ST       Status, determines whether after each iteration the stress should
%   INSPECT  be printed on the screen (1) or not (0). When INSPECT > 0,
%            ST = 1 and the mapping is onto 2D or larger, then the progress
%            is plotted during the minimization every INSPECT iterations.
%
% Important:
% - It is assumed that D either is or approximates a Euclidean distance
%     matrix, i.e:
%            D_{ij} = sqrt (sum_k(x_i - x_j)^2).
% - Missing values can be handled; they should be marked by 'NaN' in D.
%
% EXAMPLES:
% opt.optim = 'scg';
% opt.init  = 'cs';
% D  = sqrt(distm(a)); % Compute the Euclidean distance dataset of A
% w1 = mds(D,2,opt);   % An MDS map onto 2D initialized by Classical Scaling,
%                      % optimized by a Scaled Conjugate Gradients algorithm
% n  = size(D,1);
% y  = rand(n,2);
% w2 = mds(D,y,opt);   % An MDS map onto 2D initialized by random vectors
%
% z = rand(n,n);       % Set around 40% of the random distances to NaN, i.e.
% z = (z+z')/2;        % not used in the MDS mapping
% z = find(z <= 0.6);
% D(z) = NaN;
% D(1:n+1:n^2) = 0;    % Set the diagonal to zero
% opt.optim = 'pn';
% opt.init  = 'randnp';
% opt.etol  = 1e-8;    % Should be high, as only some distances are used
% w3 = mds(D,2,opt);   % An MDS map onto 2D initialized by a random projection
%
% REFERENCES
% 1. M.F. Moler, A Scaled Conjugate Gradient Algorithm for Fast Supervised
%    Learning', Neural Networks, vol. 6, 525-533, 1993.
% 2. W.H. Press, S.A. Teukolsky, W.T. Vetterling and B.P. Flannery,
%    Numerical Recipes in C, Cambridge University Press, Cambridge, 1992.
% 3. I. Borg and P. Groenen, Modern Multidimensional Scaling, Springer
%    Verlag, Berlin, 1997.
% 4. T.F. Cox and M.A.A. Cox, Multidimensional Scaling, Chapman and Hall,
%    London, 1994.
%
% SEE ALSO (PRTools Guide)
% DATASETS, MAPPINGS, PREX_MDS, MDS_CS, SAMMONM, TSNEM

%
% Copyright: E. Pekalska, R.P.W. Duin, e.pekalska@37steps.com
%

function [w,J,err,opt,y] = mds(varargin)

  mapname = 'MDS';
	argin = shiftargin(varargin,{'scalar'});
  argin = setdefaults(argin,[],2,[]);

  if mapping_task(argin,'definition')
    w = define_mapping(argin,'untrained',mapname);

  else % Train, evaluate or extend a mapping.

    [D,y,options] = deal(argin{:});
    opt = mds_setopt(options);

  % YREP contains representative objects in the projected MDS space, i.e.
  % for which the mapping exists. YREP is empty for the original MDS, since
  %  no projection is available yet.

    yrep = [];

    if (isdataset(D) | isa(D,'double'))
      [m,mm] = size(D);

      % Convert D to double, but retain labels in LAB.
      if (isdataset(D)), lab = getlab(D); D = +D; else, lab = ones(m,1); end;

      if (ismapping(y))

        % The MDS mapping exists; this means that YREP has already been stored.
        pars = getdata(y); [k,c] = size(y);

        y     = [];        % Empty, should now be found.
        yrep  = pars{1};  % There exists an MDS map, hence YREP is stored.
        opt   = pars{2};  % Options used for the mapping.
        II    = pars{3};  % Index of non-repeated points in YREP.
        winit = pars{4};  % The Classical Scaling map, if INIT = 'cs'.
        v     = pars{5};  % Weights used for adding new points if ITMAP = 'no'.
        n = c;            % Number of dimensions of the projected space.

        % Initialization by 'cs' is not possible when there is no winit
        % (i.e. the CS map) and new points should be added.
        if (strcmp(opt.init,'cs')) & (isempty(winit))
          prwarning(2,'OPTIONS.init = cs is not possible when adding points; using kl.');
          opt.init = 'kl';
        end

        % If YREP is a scalar, we have an empty mapping.
        if (max(size(yrep)) == 1)
          y    = yrep;
          yrep = [];
        end

        % Check whether D is a matrix with the zero diagonal for the existing map.
        if (m == mm) & (length(intersect(find(D(:)<eps),1:m+1:(m*mm))) >= m)
          w = yrep;         % D is the same matrix as in the projection process;
          return            % YREP is then the solution
        end

        if (length(pars) < 6) | (isempty(pars{6}))
          yinit = [];
        else
          yinit = pars{6};   % Possible initial configuration for points to
                            % be added to an existing map
          if (size(yinit,1) ~= size(D,1))
            prwarning(2,'the size of the initial configuration does not match that of the dissimilarity matrix, using random initialization.')
            yinit =[];
          end
        end

      else

        % No MDS mapping available yet; perform the checks.

        if (~issym(D,1e-12))
          prwarning(2,'D is not a symmetric matrix; will average.');
          D = (D+D')/2;
        end

        % Check the number of zeros on the diagonal

        if (any(abs(diag(D)) > 0))
          error('D should have a zero diagonal');
        end
      end

    else    % D is neither a dataset nor a matrix of doubles
      error('D should be a dataset or a matrix of doubles.');
    end

    if (~isempty(y))

      % Y is the initial configuration or N, no MDS map exists yet;
      % D is a square matrix.

      % Remove identical points, i.e. points for which D(i,j) = 0 for i ~= j.
      % I contains the indices of points left for the MDS mapping, J those
      % of the removed points and P those of the points left in I which were
      % identical to those removed.

      [I,J,P] = mds_reppoints(D);
      D = D(I,I);
      [ni,nc] = size(D);

      % NANID is an extra field in the OPTIONS structure, containing the indices
      % of NaN values (= missing values) in distance matrix D.

      opt.nanid = find(isnan(D(:)) == 1);

      % Initialise Y.

      [m2,n] = size(y);
      if (max(m2,n) == 1)    % Y is a scalar, hence really is a dimensionality N.
        n = y;
        [y,winit] = mds_init(D,n,opt.init);
      else
        if (mm ~= m2)
          error('The matrix D and the starting configuration Y should have the same number of columns.');
        end
        winit = [];
        y = +y(I,:);
      end

      % The final number of true distances is:
      no_dist = (ni*(ni-1) - length(opt.nanid))/2;

    else

      % This happens only if we add extra points to an existing MDS map.
      % Remove identical points, i.e. points for which D(i,j) = 0 for i ~= j.
      % I contains the indices of points left for the MDS mapping, J those
      % of the removed points and P those of the points left in I which were
      % identical to those removed.

      [I,J,P] = mds_reppoints(D(:,II));
      D = D(I,II);
      [ni,nc] = size(D);
      yrep = yrep(II,:);
      n = size(yrep,2);

      % NANID is an extra field in the OPTIONS structure, containing the indices
      % of NaN values (= missing values) in distance matrix D.

      opt.nanid = find(isnan(D(:)));

      % Initialise Y. if the new points should be added in an iterative manner.

      [m2,n] = size(yrep);
      if (~isempty(yinit))             % An initial configuration exists.
        y = yinit;
      elseif (strcmp(opt.init, 'cs')) & (~isempty(winit))
        y = D*winit;
      else
        y = mds_init(D,n,opt.init);
      end

      if (~isempty(opt.nanid))         % Rescale.
        scale = (max(yrep)-min(yrep))./(max(y)-min(y));
        y = y .* repmat(scale,ni,1);
      end

      % The final number of true distances is:
      no_dist = (ni*nc - length(opt.nanid));
    end

    % Check whether there is enough data left.

    if (~isempty(opt.nanid))
      if (n*ni+2 > no_dist),
        error('There are too many missing distances: it is not possible to determine the MDS map.');
      end
      if (strcmp (opt.itmap,'no'))
        opt.itmap = 'yes';
        prwarning(1,'Due to the missing values, the projection can only be iterative. OPTIONS are changed appropriately.')
      end
    end

    if (opt.inspect > 0)
      opt.plotlab = lab(I,:);  % Labels to be used for plotting in MDS_SAMMAP.
    else
      opt.plotlab = [];
    end

    if (isempty(yrep)) | (~isempty(yrep) & strcmp(opt.itmap, 'yes'))

      % Either no MDS exists yet OR new points should be mapped in an iterative manner.

      printinfo(opt);
      [yy,err] = mds_sammap(D,y,yrep,opt);

      % Define the linear projection of distances.

      v = [];
      if (isempty(yrep)) & (isempty(opt.nanid))
        if (rank(D) < m)
          v = prpinv(D)*yy;
        else
          v = D \ yy;
        end
      end
    else
      % New points should be added by a linear projection of dissimilarity data.
      yy = D*v;
    end

    % Establish the projected configuration including the removed points.

    y = zeros(m,n); y(I,:) = +yy;
    if (~isempty(J))
      if (~isempty(yrep))
        y(J,:) = +yrep(II(P),:);
      else
        for k=length(J):-1:1        % J: indices of removed points.
          y(J(k),:) = y(P(k),:);    % P: indices of points equal to points in J.
        end
      end
    end

    % In the definition step: shift the obtained configuration such that the
    % mean lies at the origin.

    if (isempty(yrep))
      y = y - ones(length(y),1)*mean(y);
      y = prdataset(y,lab);
    else
      w = prdataset(y,lab);
      return;
    end

    % In the definition step: the mapping should be stored.

    opt = rmfield(opt,'nanid');   % These fields are to be used internally only;
    opt = rmfield(opt,'plotlab'); % not to be set up from outside
    w   = prmapping(mfilename,'trained',{y,opt,I,winit,v,[]},[],m,n);
    w   = setname(w,mapname);

  end

return

% **********************************************************************************
%                             Extra functions
% **********************************************************************************

% PRINTINFO(OPT)
%
% Prints progress information to the file handle given by OPT.ST.

function printinfo(opt)

  if opt.st < 1
    return
  end
  %fprintf(opt.st,'Sammon mapping, error function with the parameter q=%d\n',opt.q);

  switch (opt.optim)
    case 'pn',
      %fprintf(opt.st,'Minimization by Pseudo-Newton algorithm\n');
    case 'scg',
      %fprintf(opt.st,'Minimization by Scaled Conjugate Gradients algorithm\n');
    otherwise
      error(strcat('Possible initialization methods: pn (Pseudo-Newton), ',...
                   'or scg (Scaled Conjugate Gradients).'));
  end

return

% **********************************************************************************

% [I,J,P] = MDS_REPPOINTS(D)
%
% Finds the indices of repeated/left points. J contains the indices of
% repeated points in D. This means that for each j in J, there is a point
% k ~= j such that D(J(j),k) = 0. I contains the indices of the remaining
% points, and P those of the points in I that were identical to those in J.
% Directly used in MDS routine.

function [I,J,P] = mds_reppoints(D)

  epsilon = 1e-20;      % Differences smaller than this are assumed to be zero.

  [m,mm] = size(D);

  I = 1:m; J = []; P = [];

  if (m == mm) & (all(abs(D(1:m+1:end)) <= epsilon))
    K = intersect (find (triu(ones(m),1)), find(D < epsilon));
    if (~isempty(K))
      P = mod(K,m);
      J = fix(K./m) + 1;
      I(J) = [];
    end
  else
    [J,P] = find(D<=epsilon);
    I(J)  = [];
  end

return;

% **********************************************************************************

% MDS_SETOPT  Sets parameters for the MDS mapping
%
%   OPT = MDS_SETOPT(OPT_GIVEN)
%
% INPUT
%   OPT_GIVEN Parameters for the MDS mapping, described below (default: [])
%
% OUTPUT
%   OPT       Structure of chosen options; if OPT_GIVEN is empty, then
%               OPT.q       = 0
%               OPT.optim   = 'pn'
%               OPT.init    = 'cs'
%               OPT.etol    = 1e-6 (the precise value depends on q)
%               OPT.maxiter = 100
%               OPT.itmap   = 'yes'
%               OPT.isratio = 0
%               OPT.st      = 1
%               OPT.inspect = 2
%
% DESCRIPTION
% Parameters for the MDS mapping can be set or changed. OPT_GIVEN consists
% of the following fields: 'q', 'init', 'optim', 'etol', 'maxiter','itmap',
% 'isratio', 'st' and 'inspect'. OPTIONS can include all the fields or some
% of them only. The fields of OPT have some default values, which can be
% changed by the OPT_GIVEN field values. If OPT_GIVEN is empty, then OPT
% contains all default values. For a description of the fields, see MDS.

%
% Copyright: Elzbieta Pekalska, ela@ph.tn.tudelft.nl, 2000-2003
% Faculty of Applied Sciences, Delft University of Technology
%

function opt = mds_setopt (opt_given)

  opt.q       = 0;
  opt.init    = 'cs';
  opt.optim   = 'pn';
  opt.st      = 1;
  opt.itmap   = 'yes';
  opt.maxiter = 100;
  opt.inspect = 2;
  opt.etol    = inf;
  opt.isratio = 0;
  opt.nanid   = [];    % Here are some extra values; set up in the MDS routine.
  opt.plotlab = [];    % Not to be changed by the user.

  if (~isempty(opt_given))
    if (~isstruct(opt_given))
      error('OPTIONS should be a structure with at least one of the following fields: q, init, etol, optim, maxiter, itmap, isratio, st or inspect.');
    end
    fn = fieldnames(opt_given);
    if (~all(ismember(fn,fieldnames(opt))))
      error('Wrong field names; valid field names are: q, init, optim, etol, maxiter, itmap, isratio, st or inspect.')
    end
    for i = 1:length(fn)
      opt = setfield(opt,fn{i},getfield(opt_given,fn{i}));
    end
  end

  if (isempty(intersect(opt.q,-2:1:2)))
    error ('OPTIONS.q should be -2, -1, 0, 1 or 2.');
  end

  if (opt.maxiter < 2)
    error ('OPTIONS.iter should be at least 1.');
  end

  if (isinf(opt.etol))
    switch (opt.q)                 % Different defaults for different stresses.
      case -2,
        opt.etol = 1e-6;
      case {-1,0}
        opt.etol = 10*sqrt(eps);
      case {1,2}
        opt.etol = sqrt(eps);
      end
  elseif (opt.etol <= 0) | (opt.etol >= 0.1)
    error ('OPTIONS.etol should be positive and smaller than 0.1.');
  end

  if (~ismember(opt.optim, {'pn','scg'}))
    error('OPTIONS.optim should be pn or scg.');
  end

  if (~ismember(opt.itmap, {'yes','no'}))
    error('OPTIONS.itmap should be yes or no.');
  end

return

% MDS_SAMMAP Sammon iterative nonlinear mapping for MDS
%
%   [YMAP,ERR] = MDS_SAMMAP(D,Y,YREP,OPTIONS)
%
% INPUT
%   D       Square (M x M) dissimilarity matrix
%   Y       M x N matrix containing starting configuration, or
%   YREP    Configuration of the representation points
%   OPTIONS Various parameters of the  minimization procedure put into
%           a structure consisting of the following fields: 'q', 'optim',
%           'init','etol','maxiter', 'isratio', 'itmap', 'st' and 'inspect'
%           (default:
%             OPTIONS.q       = 0
%             OPTIONS.optim   = 'pn'
%             OPTIONS.init    = 'cs'
%             OPTIONS.etol    = 1e-6 (the precise value depends on q)
%             OPTIONS.maxiter = 100
%             OPTIONS.isratio = 0
%             OPTIONS.itmap   = 'yes'
%             OPTIONS.st      = 1
%             OPTIONS.inspect = 2).
%
% OUTPUT
%   YMAP     Mapped configuration
%   ERR     Sammon stress
%
% DESCRIPTION
% Maps the objects given by a symmetric distance matrix D (with a zero
% diagonal) onto, say, an N-dimensional configuration YMAP by an iterative
% minimization of a variant of the Sammon stress. The minimization starts
% from the initial configuration Y; see MDS_INIT.
%
% YREP is the Sammon configuration of the representation set. It is used
% when new points have to be projected. In other words, if D is an M x M
% symmetric distance matrix, then YREP is empty; if D is an M x N matrix,
% then YMAP is sought such that D can approximate the distances between YMAP
% and YREP.
%
% Missing values can be handled by marking them by NaN in D.
%
% SEE ALSO (PRTools Guide)
% MAPPINGS, MDS, MDS_CS, MDS_INIT, MDS_SETOPT

%
% Copyright: Elzbieta Pekalska, ela@ph.tn.tudelft.nl, 2000-2003
% Faculty of Applied Sciences, Delft University of Technology
%

function [y,err] = mds_sammap(Ds,y,yrep,opt)

  if (nargin < 4)
    opt = [];                 % Will be filled by MDS_SETOPT, below.
  end
  if isempty(opt), opt = mds_setopt(opt); end
  if (nargin < 3)
    yrep = [];
  end

  % Extract labels and calculate distance matrix.

  [m,n] = size(y);
  if (~isempty(yrep))
    replab = getlab(yrep);
    yrep = +yrep;
    D = sqrt(distm(y,yrep));
  else
    D = sqrt(distm(y));
    yrep = [];
    replab = [];
  end

%   if (isempty(opt.plotlab))
%     opt.plotlab = ones(m,1);
%   end

  it   = 0;           % Iteration number.
  eold = inf;         % Previous stress (error).

  % Calculate initial stress.

  [e,a]= mds_samstress(opt.q,y,yrep,Ds,D,opt.nanid,opt.isratio); err = e;

  %if opt.st > 0, fprintf(opt.st,'iteration: %4i   stress: %3.8d\n',it,e); end

  tt = sprintf('Processing %i iterations: ',opt.maxiter);
  prwaitbar(opt.maxiter,tt)

  switch (opt.optim)
    case 'pn',        % Pseudo-Newton minimization.

      epr   = e;      % Previous values of E, EOLD for line search algorithm.
      eepr  = e;
      add   = 1e-4;   % Avoid G2 equal 0; see below.

      BETA   = 1e-3;   % Parameter for line search algorithm.
      lam1   = 0;
      lam2   = 1;      % LAM (the step factor) lies in (LAM1, LAM2).
      LMIN   = 1e-10;  % Minimum acceptable value for LAM in line search.
      lambest = 1e-4; % LAM = LAMBEST, if LAM was not found.

      % Loop until the error change falls below the tolerance or until
      % the maximum number of iterations is reached.

      while (abs(e-eold) >= opt.etol*(1 + abs(e))) & (it < opt.maxiter)

        % Plot progress if requested.

%        if (opt.st > 0) & (opt.inspect > 0) & (mod(it,opt.inspect) == 0)
%          if (it == 0), figure(1); clf; end
%          mds_plot(y,yrep,opt.plotlab,replab,e);
%        end

        yold = y; eold = e;

        % Calculate the stress.

        [e,a]      = mds_samstress (opt.q,yold,yrep,Ds,[],opt.nanid,opt.isratio);

        % Calculate gradients and pseudo-Newton update P.

        [g1,g2,cc] = mds_gradients (opt.q,yold,yrep,a*Ds,[],opt.nanid);
        p        = (g1/cc)./(abs(g2/cc) + add);
        slope    = g1(:)' * p(:);

        lam = 1;

        % Search for a suitable step LAM using a line search.

        while (1)

          % Take a step and calculate the delta error DE.

          y      = yold + lam .* p;
          [e,a]  = mds_samstress(opt.q,y,yrep,Ds,[],opt.nanid,opt.isratio);
          de     = e - eold;

          % Stop if the condition for a suitable lam is fulfilled.

          if (de < BETA * lam * slope)
            break;
          end

          % Try to find a suitable step LAM.

          if (lam ~= 1)
            r1 = de - lam*slope;
            r2 = epr - eepr - lam2*slope;
            aa = (2*de + r1/lam^2 - r2/lam2^2)/(lam2-lam1)^3;
            bb = ((-lam2*r1)/lam^2 +(lam*r2)/lam2^2)/(lam2-lam1)^2;

            if (abs(aa) <= eps)
              lamtmp = -0.5 * slope/bb;
            else
              lamtmp = (-bb + sqrt(max(0,(bb^2 - 3*aa*slope))))/(3*aa);
            end

            % Prevent LAM from becoming too large.

            if (lamtmp > 0.5 * lam), lamtmp = 0.5 * lam; end

          else
            lamtmp = -0.5 * slope/(e - eold - slope);
          end

          % Prevent LAM from becoming too small.

          lam2 = lam;
          lam  = max(lamtmp, 0.1*lam);
          epr  = e;
          eepr = eold;

          if (lam < LMIN)
            y = yold + lambest .* p;
            [e,a] = mds_samstress(opt.q,y,yrep,Ds,[],opt.nanid,opt.isratio);
            break;
          end
        end

        it  = it + 1;
        err = [err; e];

        prwaitbar(opt.maxiter,it,[tt num2str(it) ', error: ' num2str(e)]);
        %if opt.st > 0, fprintf(opt.st,'iteration: %4i   stress: %3.8d\n',it,e); end

      end

    case 'scg',              % Scaled Conjugate Gradient minimization.

      sigma0  = 1e-8;
      lambda  = 1e-8;       % Regularization parameter.
      lambda1 = 0;

      % Calculate initial stress and direction of decrease P.

      [e,a]   = mds_samstress(opt.q,y,yrep,Ds,D,opt.nanid,opt.isratio);
      g1      = mds_gradients(opt.q,y,yrep,a*Ds,D,opt.nanid);   % Gradient
      p       = -g1;                                            % Direction of decrease
      gnorm2  = g1(:)' * g1(:);
      success = 1;

      % Sanity check.

      if (gnorm2 < 1e-15)
        prwarning(2,['Gradient is nearly zero: ' gnorm2 ' (unlikely); initial configuration is the right one.']);
        return
      end

      % Loop until the error change falls below the tolerance or until
      % the maximum number of iterations is reached.

      while (abs(eold - e) > opt.etol * (1 + e)) & (it < opt.maxiter)

        g0     = g1;            % Previous gradient
        pnorm2 = p(:)' * p(:);
        eold   = e;

        % Plot progress if requested.

%        if (opt.inspect > 0) & (mod(it,opt.inspect) == 0)
%          if (it == 0), figure(1); clf; end
%          mds_plot(y,yrep,opt.plotlab,replab,e);
%        end

        if (success)
          sigma = sigma0/sqrt(pnorm2);      % SIGMA: a small step from y to yy
          yy    = y + sigma .*p;
          [e,a] = mds_samstress(opt.q,yy,yrep,Ds,[],opt.nanid,opt.isratio);
          g2    = mds_gradients(opt.q,yy,yrep,a*Ds,[],opt.nanid); % Gradient for yy
          s     = (g2-g1)/sigma;        % Approximation of Hessian*P directly, instead of computing
          delta = p(:)' * s(:);         % the Hessian, since only DELTA = P'*Hessian*P is in fact needed
        end

        % Regularize the Hessian indirectly to make it positive definite.
        % DELTA is now computed as P'* (Hessian + regularization * Identity) * P
        delta = delta + (lambda1 - lambda) * pnorm2;

        % Indicate if the Hessian is negative definite; the regularization above was too small.
        if (delta < 0)
          lambda1 = 2 * (lambda - delta/pnorm2);  % Now the Hessian will be positive definite
          delta   = -delta + lambda * pnorm2;     % This is obtained after plugging lambda1
          lambda  = lambda1;                      % into the formulation a few lines above.
        end

        mi = - p(:)' * g1(:);
        yy = y + (mi/delta) .*p;                  % mi/delta is a step size
        [ee,a] = mds_samstress(opt.q,yy,yrep,Ds,[],opt.nanid,opt.isratio);

        % This minimization procedure is based on the second order approximation of the
        % stress function by using the gradient and the Hessian approximation. The Hessian
        % is regularized, but maybe not sufficiently. The ratio Dc (<=1) below indicates
        % a proper approximation, if Dc is close to 1.

        Dc = 2 * delta/mi^2 * (e - ee);
        e  = ee;

        % If Dc > 0, then the stress can be successfully decreased.
        success = (Dc >= 0);
        if (success)
          y       = yy;
          [ee,a]  = mds_samstress(opt.q,yy,yrep,Ds,[],opt.nanid,opt.isratio);
          g1      = mds_gradients(opt.q,yy,yrep,a*Ds,[],opt.nanid);
          gnorm2  = g1(:)' * g1(:);
          lambda1 = 0;

          beta = max(0,(g1(:)'*(g1(:)-g0(:)))/mi);
          p   = -g1 + beta .* p;                 % P is a new conjugate direction

          if (g1(:)'*p(:) >= 0 | mod(it-1,n*m) == 0),
            p = -g1;                            % No much improvement, restart
          end

          if (Dc >= 0.75)
            lambda = 0.25 * lambda;             % Make the regularization smaller
          end

          it  = it + 1;
          err = [err; e];
          prwaitbar(opt.maxiter,it,[tt num2str(it) ', error: ' num2str(e)]);
          %fprintf (opt.st,'iteration: %4i   stress: %3.8d\n',it,e);

        else        % Dc < 0
          % Note that for Dc < 0, the iteration number IT is not increased,
          % so the Hessian is further regularized until SUCCESS equals 1.
          lambda1 = lambda;
        end

      % The approximation of the Hessian was poor or the stress was not
      % decreased (Dc < 0), hence the regularization lambda is enlarged.
      if (Dc < 0.25)
        lambda = lambda + delta * (1 - Dc)/pnorm2;
      end
    end
  end
  prwaitbar(0);

return

% **********************************************************************************

%MDS_STRESS - Calculate Sammon stress during optimization
%
%   E = MDS_SAMSTRESS(Q,Y,YREP,Ds,D,NANINDEX)
%
% INPUT
%   Q         Indicator of the Sammon stress; Q = -2,-1,0,1,2
%   Y         Current lower-dimensional configuration
%   YREP      Configuration of the representation objects; it should be
%             empty when no representation set is considered
%   Ds        Original distance matrix
%   D         Approximate distance matrix (optional; otherwise computed from Y)
%   NANINDEX  Index of the missing values; marked in Ds by NaN (optional; to
%             be found in Ds)
%
% OUTPUT
%   E         Sammon stress
%
% DESCRIPTION
% Computes the Sammon stress between the original distance matrix Ds and the
% approximated distance matrix D between the mapped configuration Y and the
% configuration of the representation set YREP, expressed as follows:
%
% E = 1/(sum_{i<j} Ds_{ij}^(q+2)) sum_{i<j} (Ds_{ij} - D_{ij})^2 * Ds_{ij}^q
%
% It is directly used in the MDS_SAMMAP routine.

%
% Copyright: Elzbieta Pekalska, Robert P.W. Duin, ela@ph.tn.tudelft.nl, 2000-2003
% Faculty of Applied Sciences, Delft University of Technology
%

function [e,alpha] = mds_samstress (q,y,yrep,Ds,D,nanindex,isratio)

  % If D is not given, calculate it from Y, the current mapped points.

  if (nargin < 5) | (isempty(D))
    if (~isempty(yrep))
      D = sqrt(distm(y,yrep));
    else
      D = sqrt(distm(y));
    end
  end

  if (nargin < 6)
    nanindex = [];    % Not given, so calculate below.
  end

  if (nargin < 7)
    isratio = 0;      % Assume this is meant.
  end

  todefine = isempty(yrep);

  [m,n]  = size(y); [mm,k] = size(Ds);
  if (m ~= mm)
    error('The sizes of Y and Ds do not match.');
  end
  if (any(size(D) ~= size(Ds)))
    error ('The sizes of D and Ds do not match.');
  end
  m2 = m*k;

  % Convert to double.
  D  = +D; Ds = +Ds;

  % I is the index of non-NaN, non-zero (> eps) values to be included
  % for the computation of the stress.

  I = 1:m2;
  if (~isempty(nanindex))
    I(nanindex) = [];
  end

  O = [];
  if (todefine), O = 1:m+1:m2; end
  I = setdiff(I,O);

  % If OPTIONS.isratio is set, calculate optimal ALPHA to scale with.

  if (isratio)
    alpha = sum((Ds(I).^q).*D(I).^2)/sum((Ds(I).^(q+1)).*D(I));
    Ds    = alpha*Ds;
  else
    alpha = 1;
  end

  % C is the normalization factor.
  c = sum(Ds(I).^(q+2));

  % If Q == 0, prevent unnecessary calculation (X^0 == 1).
  if (q ~= 0)
    e = sum(Ds(I).^q .*((Ds(I)-D(I)).^2))/c;
  else
    e = sum(((Ds(I)-D(I)).^2))/c;
  end

return

% **********************************************************************************

%MDS_GRADIENTS - Gradients for variants of the Sammon stress
%
%   [G1,G2,CC] = MDS_GRADIENTS(Q,Y,YREP,Ds,D,NANINDEX)
%
% INPUT
%   Q          Indicator of the Sammon stress; Q = -2,-1,0,1,2
%   Y         Current lower-dimensional configuration
%   YREP      Configuration of the representation objects; it should be
%             empty when no representation set is considered
%   Ds        Original distance matrix
%   D         Approximate distance matrix (optional; otherwise computed from Y)
%   nanindex  Index of missing values; marked in Ds by NaN (optional;
%             otherwise found from Ds)
%
% OUTPUT
%   G1        Gradient direction
%   G2        Approximation of the Hessian by its diagonal
%
% DESCRIPTION
% This is a routine used directly in the MDS_SAMMAP routine.
%
% SEE ALSO (PRTools Guide)
% MDS, MDS_INIT, MDS_SAMMAP, MDS_SAMSTRESS

%
% Copyright: Elzbieta Pekalska, Robert P.W. Duin, ela@ph.tn.tudelft.nl, 2000-2003
% Faculty of Applied Sciences, Delft University of Technology
%

function [g1,g2,c] = mds_gradients(q,y,yrep,Ds,D,nanindex)

  % If D is not given, calculate it from Y, the current mapped points.

	y = +y;
	yrep = +yrep;
  if (nargin < 5) | (isempty(D))
    if (~isempty(yrep))
      D = sqrt(distm(y,yrep));
    else
      D = sqrt(distm(y));
    end
  end

  % If NANINDEX is not given, find it from Ds.

  if (nargin < 6)
    nanindex = find(isnan(Ds(:))==1);
  end

  % YREP is empty if no representation set is defined yet.
  % This happens when the mapping should be defined.

  todefine = (isempty(yrep));
  if (todefine)
    yrep  = y;
  end

  [m,n]  = size(y); [mm,k] = size(Ds);
  if (m ~= mm)
    error('The sizes of Y and Ds do not match.');
  end
  if (any(size(D) ~= size(Ds)))
    error ('The sizes of D and Ds do not match.');
  end
  m2 = m*k;

  % Convert to doubles.

  D  = +D; Ds = +Ds;

  % I is the index of non-NaN, non-zero (> eps) values to be included
  % for the computation of the gradient and the Hessians diagonal.

  I = (1:m2)';
  if (~isempty(nanindex))
    I(nanindex) = [];
  end
  K    = find(Ds(I) <= eps | D(I) <= eps);
  I(K) = [];

  % C is a normalization factor.

  c = -2/sum(Ds(I).^(q+2));

  % Compute G1, the gradient.

  h1 = zeros(m2,1);
  if (q == 0)                    % Prevent unnecessary computation when Q = 0.
    h1(I) = (Ds(I)-D(I)) ./ D(I);
  else
    h1(I) = (Ds(I)-D(I)) ./ (D(I).*(Ds(I).^(-q)));
  end
  h1 = reshape (h1',m,k);
  g2 = h1 * ones(k,n);          % Here G2 is assigned only temporarily,
  g1 = c * (g2.*y - h1*yrep);    % for the computation of G1.

  % Compute G2, the diagonal of the Hessian, if requested.

  if (nargout > 1)
    h2 = zeros(m2,1);
    switch (q)
      case -2,
        h2(I) = -1./(Ds(I).*D(I).^3);
      case -1,
        h2(I) = -1./(D(I).^3);
      case 0,
        h2(I) = - Ds(I)./(D(I).^3);
      case 1,
        h2(I) = - Ds(I).^2./(D(I).^3);
      case 2,
        h2(I) = -(Ds(I)./D(I)).^3;
      end
    h2 = reshape (h2',m,k);
    g2 = c * (g2 + (h2*ones(k,n)).*y.^2 + h2*yrep.^2 - 2*(h2*yrep).*y);
  end

return


% function [ARSignal StatWT] = WaveletAnalysis(StatWT,L,wavename,iqr,SignalLength)
%
%
% Perform a wavelet motion correction of the dod data and computes the
% distribution of the wavelet coefficients. It sets the coefficient
% exceeding iqr times the interquartile range to zero, because these are probably due
% to motion artifacts. It applies the inverse discrete wavelet transform and
% reconstruct the signal.
%
% The algorithm follows in part the procedure described by
% Molavi et al.,Physiol Meas, 33, 259-270 (2012).
%
% INPUTS:
% StatWT:       matrix of wavelet coefficients (# of time points x # of
%               levels+1). The first column contains the approximation
%               coefficients, while the other all the details coefficients at
%               different levels
% L:            Lowest wavelet scale used in the analysis
% wavename:     name of the wavelet used in the reconstruction, should be the
%               same used in the previous decomposition
% iqr:          parameter used to compute the statistics (iqr = 1.5 means 1.5 times the
%               interquartile range and is usually used to detect outliers).
%               Increasing it, it will delete less coefficients.
% SignalLength: Length of the original signal before zero padding
%
%
% OUTPUTS:
% ARSIgnal:     signal reconstructed after the discrete inverse wavelet transform
%               and corrected for motion artifacts.
% StatWT:       matrix of wavelet coefficients corrected for motion
%               artifacts. Same size as StatWT input
%
% LOG:
% Script by Behnam Molavi bmolavi@ece.ubc.ca adapted for Homer2 by RJC
% modified 10/17/2012 by S. Brigadoi

function [ARSignal,StatWT]  = WaveletAnalysis(StatWT,L,wavename,iqr,SignalLength)

n=size(StatWT,1);       % Length of data vector with zero padding
N=log2(size(StatWT,1)); % Finest scale (original signal)
SignalLength_tmp = SignalLength;

for j=1:N-L-1
    SignalLength_tmp = fix(SignalLength_tmp/2);
    n_blocks = 2^j; % number of blocks in the level
    l_blocks = n/n_blocks; % length of the blocks in the level
    for b=0:(2^j-1)
        sr = StatWT(b*l_blocks+1:b*l_blocks+l_blocks,j+1);

        sr_temp = sr(1:SignalLength_tmp); % compute statistics only on original data
        quants = quantile(sr_temp,[.25 .50 .75]);  % compute quantiles
        IQR = quants(3)-quants(1);  % compute interquartile range
        prob1 = quants(3)+IQR*iqr;
        prob2 = quants(1)-IQR*iqr;
        outliers_1 = find(sr>prob1);
        outliers_2 = find(sr<prob2);
        outliers = [outliers_1' outliers_2'];
        sr(outliers) = 0;  % set outliers to 0
        StatWT(b*l_blocks+1:b*l_blocks+l_blocks,j+1) = sr;
    end
end
ARSignal=IWT_inv(StatWT,wavename);  % reconstruct the signal with the discrete inverse wavelet transform


function trans = homothecy(point, ratio)
%HOMOTHECY create a homothecy as an affine transform
%
%   TRANS = homothecy(POINT, K);
%   POINT is the center of the homothecy, K is its factor.
%
%   See also:
%   transforms2d, transformPoint, createTranslation
%
%   ---------
%   author : David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 20/01/2005.
%

%   HISTORY
%   22/04/2009: copy to createHomothecy and deprecate

% deprecation warning
warning('geom2d:deprecated', ...
    '''homothecy'' is deprecated, use ''createHomothecy'' instead');

% call current implementation
trans = createHomothecy(point, ratio);


function [V] = GNMFtest(U, X)
% Graph regularized Non-negative Matrix Factorization (GNMF) handling the test data
%
% Notation:
% X ... (mFea x nSmp) data matrix
%       mFea  ... number of words (vocabulary size)
%       nSmp  ... number of documents
% U ... (mFea x K) basis matrix learned by GNMF.
%
% X = U*V'
%
% References:
% [1] Deng Cai, Xiaofei He, Xiaoyun Wu, and Jiawei Han. "Non-negative
% Matrix Factorization on Manifold", Proc. 2008 Int. Conf. on Data Mining
% (ICDM'08), Pisa, Italy, Dec. 2008.
%
% [2] Deng Cai, Xiaofei He, Jiawei Han, Thomas Huang. "Graph Regularized
% Non-negative Matrix Factorization for Data Representation", IEEE
% Transactions on Pattern Analysis and Machine Intelligence, , Vol. 33, No.
% 8, pp. 1548-1560, 2011.
%
%
%   version 1.0 --Jan./2012
%
%   Written by Deng Cai (dengcai AT gmail.com)
%

if min(min(X)) < 0
    error('Input should be nonnegative!');
end

UTU = U'*U;
UTU = max(UTU,UTU');
UTX = U'*X;
V = max(0,UTU\UTX);
V = V';


function [M1,MW,MW1] = perform_steerable_matching(M1,M,options)

% perform_steerable_matching - match multiscale histograms
%
% M1 = perform_steerable_matching(M1,M,options);
%
%   M1 is the image to synthesize.
%   M is the exemplar image.
%
%   This function match the histogram of the image and the histogram
%   of each sub-band of a steerable pyramid.
%
%   To do texture synthesis, one should apply several time this function.
%   You can do it by setting the value of options.niter_synthesis.
%   This leads to the synthesis as described in
%
%       Pyramid-Based Texture Analysis/Synthesis
%       D. Heeger, J. Bergen,
%       Siggraph 1995
%
%   Copyright (c) 2007 Gabriel Peyre

options.null = 0;
niter_synthesis = getoptions(options, 'niter_synthesis', 1);
copy_lowpass = getoptions(options, 'copy_lowpass', 1);

if isfield(options, 'color_mode') && strcmp(options.color_mode, 'pca') && ~isfield(options, 'ColorP') && size(M,3)==3
    [tmp,options.ColorP] = change_color_mode(M,+1,options);
end
rgb_postmatching = getoptions(options, 'rgb_postmatching', 0);

if size(M,3)==3
    options.niter_synthesis = 1;
    if not(isfield(options, 'color_mode'))
        options.color_mode = 'hsv';
    end
    for iter=1:niter_synthesis
        % color images
        M  = change_color_mode(M, +1,options);
        M1 = change_color_mode(M1,+1,options);
        for i=1:size(M,3)
            M1(:,:,i) = perform_steerable_matching(M1(:,:,i),M(:,:,i), options);
        end
        M  = change_color_mode(M, -1,options);
        M1 = change_color_mode(M1,-1,options);
        if rgb_postmatching
        for i=1:size(M,3)
            M1(:,:,i) = perform_histogram_equalization(M1(:,:,i),M(:,:,i));
        end
        end
    end
    return;
end

if size(M,3)>1
    for i=1:size(M,3)
        [M1(:,:,i),MW,MW1] = perform_steerable_matching(M1(:,:,i),M(:,:,i),options);
    end
    return;
end

if not(isfield(options, 'nb_orientations'))
    options.nb_orientations = 4;
end

nb_orientations = getoptions(options, 'nb_orientations', 1, 1);
Jmin = getoptions(options, 'JminSynthesis', 4);

for iter=1:niter_synthesis
    % spatial equalization
    M1 = perform_histogram_equalization(M1,M);
    % forward transforms
    MW1 = perform_steerable_transform(M1, Jmin, options);
    if iscell(M)
        MW = M;
    else
        MW = perform_steerable_transform(M, Jmin, options);
    end
    % wavelet domain equalization
    MW1 = perform_histogram_equalization(MW1,MW);
    if copy_lowpass
        % copy verbatim the low pass coefficients
        MW1{end} = MW{end};
    end
    % backward transform
    M1 = perform_steerable_transform(MW1, Jmin, options);
    % spatial equalization
    M1 = perform_histogram_equalization(M1,M);
end


function varargout = createCube()
%CREATECUBE Create a 3D mesh representing the unit cube.
%
%   [V, E, F] = createCube
%   Create a unit cube, as a polyhedra representation.
%   c has the form [V E F], where V is a 8-by-3 array with vertices
%   coordinates, E is a 12-by-2 array containing indices of neighbour
%   vertices, and F is a 6-by-4 array containing vertices array of each
%   face.
%
%   [V, F] = createCube;
%   Returns only the vertices and the face vertex indices.
%
%   MESH = createCube;
%   Returns the data as a mesh structure, with fields 'vertices', 'edges'
%   and 'faces'.
%
%   Example
%   [n, e, f] = createCube;
%   drawMesh(n, f);
%
%   See also
%   meshes3d, drawMesh
%   createOctahedron, createTetrahedron, createDodecahedron
%   createIcosahedron, createCubeOctahedron
%

% ------
% Author: David Legland
% E-mail: david.legland@inra.fr
% Created: 2005-02-10
% Copyright 2005-2022 INRA - TPV URPOI - BIA IMASTE

x0 = 0; dx= 1;
y0 = 0; dy= 1;
z0 = 0; dz= 1;

nodes = [...
    x0 y0 z0; ...
    x0+dx y0 z0; ...
    x0 y0+dy z0; ...
    x0+dx y0+dy z0; ...
    x0 y0 z0+dz; ...
    x0+dx y0 z0+dz; ...
    x0 y0+dy z0+dz; ...
    x0+dx y0+dy z0+dz];

edges = [1 2;1 3;1 5;2 4;2 6;3 4;3 7;4 8;5 6;5 7;6 8;7 8];

% faces are oriented such that normals point outwards
faces = [1 3 4 2;5 6 8 7;2 4 8 6;1 5 7 3;1 2 6 5;3 7 8 4];

% format output
varargout = formatMeshOutput(nargout, nodes, edges, faces);


function asa299_test01 ( )

%*****************************************************************************80
%
%% TEST01 tests SIMPLEX_LATTICE_POINT_NEXT.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    10 January 2007
%
%  Author:
%
%    John Burkardt
%
  n = 4;
  t = 4;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST01\n' );
  fprintf ( 1, '  SIMPLEX_LATTICE_POINT_NEXT generates lattice points\n' );
  fprintf ( 1, '  in the simplex\n' );
  fprintf ( 1, '    0 <= X\n' );
  fprintf ( 1, '    sum ( X(1:N) ) <= T\n' );
  fprintf ( 1, '  Here N = %d\n', n );
  fprintf ( 1, '  and T =  %d\n', t );
  fprintf ( 1, '\n' );
  fprintf ( 1, '     Index        X(1)      X(2)      X(3)      X(4)\n' );
  fprintf ( 1, '\n' );

  more = 0;
  x = [];

  i = 0;

  while ( 1 )

    [ more, x ] = simplex_lattice_point_next ( n, t, more, x );

    i = i + 1;

    fprintf ( 1, '  %8d  ', i );
    for j = 1 : n
      fprintf ( 1, '  %8d', x(j) );
    end
    fprintf ( 1, '\n' );

    if ( ~more )
      break
    end

  end

  return
end


function fem_basis_test02 ( )

%*****************************************************************************80
%
%% FEM_BASIS_TEST02 tests FEM_BASIS_2D
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    05 October 2010
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'FEM_BASIS_TEST02\n' );
  fprintf ( 1, '  FEM_BASIS_2D evaluates an arbitrary triangular\n' );
  fprintf ( 1, '  basis function.\n' );

  i1 = 1;
  j1 = 0;
  k1 = 2;
  d = i1 + j1 + k1;
  x1 = i1 / d;
  y1 = j1 / d;
  fprintf ( 1, '\n' );
  fprintf ( 1, '   I   J   K        X           Y      L(I,J,K)(X,Y)\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  %2d  %2d  %2d  %10.4f  %10.4f  %14.6g\n', ...
    i1, j1, k1, x1, y1, 1.0 );
  fprintf ( 1, '\n' );
  for j2 = 0 : d
    for i2 = 0 : d - j2
      k2 = d - i2 - j2;
      x2 = i2 / d;
      y2 = j2 / d;
      lijk = fem_basis_2d ( i1, j1, k1, x2, y2 );
      fprintf ( 1, '  %2d  %2d  %2d  %10.4f  %10.4f  %14.6g\n', ...
        i2, j2, k2, x2, y2, lijk );
    end
  end

  return
end


% Demo script for granulometry applied on grayscale image of coins.
%
%   output = granulo_coins(input)
%
%   Example
%   granulo_coins
%
%   See also
%

% ------
% Author: David Legland
% e-mail: david.legland@inrae.fr
% INRAE - BIA Research Unit - BIBS Platform (Nantes)
% Created: 2023-01-17,    using Matlab 9.13.0.2049777 (R2022b)
% Copyright 2023 INRAE.

%% Sample image

% read image
img = imread('coins.png');
imwrite(img, 'coins.png');

% compute several steps (before, between and after the two peaks)
radiusList = [15 27 35];
for iPlot = 1:3
    se = strel('disk', radiusList(iPlot), 0);
    imgOp = imopen(img, se);

    imwrite(imgOp, sprintf('coins_OpDisk%02d.tif', radiusList(iPlot)));
end

%% compute granulo.

% granulometry analysis setup
xi = 1:60;
vol0 = sum(img(:));
[gr, diams, vol] = imGranulo(img, 'opening', 'disk', xi);

% display granulo
figure; plot(diams, gr, 'color', 'b', 'linewidth', 2);
xlim([0 100]);
xlabel('Diameter of structuring element (pixels)');
ylabel('Variation of gray levels (%)');
title('Gray level granulometry by opening', 'Interpreter', 'none');
print(gcf, 'coins_grOpDk30.png', '-dpng');

% display volume curve
figure; plot([0 diams], vol, 'color', 'b', 'linewidth', 2);
xlim([0 100]);
xlabel('Diameter of structuring element (pixels)');
ylabel('Sum of gray levels');
title('Gray level granulometry by opening', 'Interpreter', 'none');
print(gcf, 'coins_grOpDk40_sumOfGrays.png', '-dpng');


% Given a set of nonnegative vectors x{i}, i=1,2,...,r
%
% Compute the function g(mu) = sum_i beta_i [ e^T x_i(mu) ]
% where
% beta_i = 1/[ ||w{i}|| - min_j w{i}(j) ], and
% If x{i} - beta_i mu w{i} contains at least one postive entry:
%      x_i(mu) = (x{i} - beta_i mu w{i})_+;
%      x_i(mu) = x_i(mu)/||x_i(mu)||_2;
% Otherwise
%     x_i(mu) is 1-sparse with nonzero entry equal to one at position
%     corresponding to the largest entry of x{i} - beta_i mu w{i}

function [vgmu,xp,gradg] = wgmu(x,w,mu);

vgmu = 0;
gradg = 0;
for i = 1 : length(x)
    ni = length(x{i});
    betai = 1/(norm(w{i})-min(w{i}));
    xp{i} = x{i} - mu*betai*w{i};
    indtp = find(xp{i} > 0);
    % Gradient g(mu)
    if ~isempty(indtp)
        xp{i} = max(0,xp{i});
        f2 = norm(xp{i});
        if nargout >= 3
            nip = w{i}(indtp)'*w{i}(indtp);

            gradg = gradg + betai^2 * ( - nip * f2^(-1) ...
                + (w{i}(indtp)'*xp{i}(indtp))^2 * f2^(-3)  );
        end
        xp{i} = xp{i}/norm(xp{i},2);
        vgmu = vgmu + betai*sum(xp{i}.*w{i});
    else
        [~,im] = max(xp{i});
        xp{i} = zeros( ni , 1 );
        xp{i}(im) = 1;
        vgmu = vgmu + betai*w{i}(im);
    end
end


function w = get_w(sv)

% w = get_w()
% returns value of w from svm
% AE: i have changed this procedure to include non linear feature
% selection with RFE. When non-linear, it gives  a score vector for each
% feature (used in RFE) which is not the margin but is sorted as the margin
if strcmp(sv.ker{1},'linear'),

  w=sv.alpha'*get_x(sv.Xsv);

else
    Xtmp = get_x(sv.Xsv);
    alphatmp = sv.alpha;

    if strcmp(sv.ker{1},'rbf'),

      % compute the kernel matrix for all components
      K = Xtmp*Xtmp';
      Kdn = sum(Xtmp.^2,2);
      Kn = sum(Xtmp.^2,2);
      K = ones(size(Xtmp,1),1)*Kdn' + Kn*ones(1,size(Xtmp,1)) - 2*K;
      K = exp(-K/(2*sv.ker{2}));
      % compute the margin when one component is removed
       for i = 1:size(Xtmp,2),
           Ki = Xtmp(:,i)*ones(1,size(Xtmp,1)) - ones(size(Xtmp,1),1)*Xtmp(:,i)';
           Ki = Ki.^2;
           Ki = Ki/(2*sv.ker{2});
           Ki = exp(Ki);
           w(i) = alphatmp'*(K.*Ki)*alphatmp;
       end;

    elseif strcmp(sv.ker{1},'poly'),

        % compute the margin when one component is removed
        Ktmp = Xtmp*Xtmp';
        for i = 1:size(Xtmp,2),
           Ki = Xtmp(:,i)*Xtmp(:,i)';
           K_i = (Ktmp - Ki+1).^(sv.ker{2});
           w(i) = alphatmp'*K_i*alphatmp;
	end;
    end;% if strcmp(...,'rbf')
    w=max(w)-w;  %% make largest the smallest --- wrong way round!

end;% if strcmp(...,'linear')


function A_inter = my_interp(A, filter_coef)
% Interpolation function
% This function performs the interpolation of the input image,
% using the specified filter
%
% Input:    A: input image
%           filter_coef: filter coefficients
%           example:    filter_coef = [1 1]/2 (Bilinear Filter)
%                       filter_coef = [1 -5 20 20 -5 1]/32 (6-tap filter)
% Output:   A_inter:  interpolated image
%
% Athanasopoulos Dionysios
% Postgraduate Student
% Computer Engineering and Informatics Dept.
% University of Patras, Greece

if (length(size(A)) == 3)
% if the input image is an RGB image or an YUV image
% or any 3D matrix just interpolate the three components separetely
    for i=1:3
        A_inter(:,:,i) = my_interp(A(:,:,i),filter_coef);
    end

else

    [m,n] = size(A);
    A_ = []; A_inter = [];
    % columns interpolation
    A_col= filter2(filter_coef,A);
    for i=1:n
        A_ = [A_ A(:,i) A_col(:,i)];
    end
    A_(:,end) = [];
    % rows interpolation
    A_rows = filter2(filter_coef,A_')';
    for i=1:m
        A_inter = [A_inter; A_(i,:); A_rows(i,:)];
    end
    A_inter(end,:) = [];

end


function visualizeCellVectorsRadial2D(phi_cell)
%VISUALIZECELLS plots the values of cell variable phi
%
% SYNOPSIS:
%  visualizeGradsRadial2D(phi)
%
% PARAMETERS:
%  phi_cell: A CellVector variable
%
% RETURNS:
%  None
%
% EXAMPLE:
%
% SEE ALSO:
%

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

% phi_cell=gradientCellTerm(phi);
L = phi_cell.domain.cellcenters.x(end);
x = phi_cell.domain.cellcenters.x;
y = phi_cell.domain.cellcenters.y;
[TH,R] = meshgrid(y, x);
[X,Y] = pol2cart(TH,R);
h = polar([0 2*pi], [0 L]);
delete(h);
quiver(X,Y,phi_cell.xvalue.*cos(TH)-phi_cell.yvalue.*sin(TH), phi_cell.xvalue.*sin(TH)+phi_cell.yvalue.*cos(TH))


%%*****************************************************************
%% primLB: compute a lower bound for the exact primal
%%         optimal value.
%%
%%*****************************************************************

  function LB = primLB(blk,At,C,b,eigX,y,mu);

  if (nargin < 7); mu = 1.1; end
  Aty = sdpnalAtyfun(blk,At,y);
  Znew = ops(C,'-',Aty);

  LB0 = b'*y;
  pert = 0;
  for p = 1:size(blk,1)
     pblk = blk(p,:);
     if strcmp(pblk{1},'s')
        eigtmp = eig(Znew{p});
        idx = find(eigtmp < 0);
        Xbar = mu*max(eigX{p});
     elseif strcmp(pblk{1},'l')
        eigtmp = Znew{p};
        idx = find(eigtmp < 0);
        Xbar = mu*max(eigX{p});
     end
     numneg = length(idx);
     if (numneg)
        mineig = min(eigtmp(idx));
        fprintf('\n numneg = %3.0d,  mineigZnew = %- 3.2e',numneg,mineig);
        pert = pert + Xbar*sum(eigtmp(idx));
     end
  end
  LB = LB0 + pert;
  fprintf('\n dobj = %-10.9e  \n LB   = %-10.9e\n',LB0,LB);
%%*****************************************************************


classdef Skewness < Algorithm

    methods (Access = public)

        function obj = Skewness()
            obj.name = 'Skewness';
            obj.inputPort = DataType.kSignal;
            obj.outputPort = DataType.kFeature;
        end

        function result = compute(~,signal)
            %meanAlgorithm = dsp.Mean('RunningMean',false,'Dimension','All');
            %signalMean = step(meanAlgorithm,signal);
            signalMean = mean(signal);

            n = single(length(signal));

            upper = single(0);
            lower = single(0);
            for i = 1 : n
                temp = single(signal(i) - signalMean);
                temp2 = single(temp * temp);
                upper = upper + temp2 * temp;
                lower = lower + temp2;
            end
            lower = lower / n;
            result = upper / (n * lower^1.5);
        end

        function metrics = computeMetrics(~,input)
            n = size(input,1);
            flops = 6 * n;
            memory = 1;
            outputSize = Constants.kFeatureBytes;
            metrics = Metric(flops,memory,outputSize);
        end
    end

end


function varargout = pcircle(center, radius, varargin)
%
% POINTS = PCIRCLE(center, radius, varargin)
% A simple function for drawing a circle pixel by pixel on a given
% region of interest (roi).
%
% INPUT:
% center:       center of the circle in [x0 y0] format
% radius:       radius of the circle (in pixels)
% varargin:     rectangular ROI defined with:
%               varagin{1} = (x1, y1) and varagin{2} = (x2, y2)
%
% OUTPUT:
% pixels:       list of circle coordinates in the format (x, y)

if nargin == 2
    roi1 = [Inf Inf];
    roi2 = [-Inf -Inf];
elseif nargin == 4
    roi1 = varargin{1};
    roi2 = varargin{2};
else
    error('Invalid number of inputs: type ''help'' PCIRCLE');
end

roil = min(roi1(1),roi2(1));
roir = max(roi1(1),roi2(1));
roib = min(roi1(2),roi2(2));
roiu = max(roi1(2),roi2(2));
x0 = center(1);
y0 = center(2);
nseg = ceil(2*pi*radius);
theta = 0:(2*pi/nseg):(2*pi);
x(:,1) = radius*cos(theta) + x0;
y(:,1) = radius*sin(theta) + y0;
pixels = round([x y]);

% delete repeated pixels
dpixels = abs(diff(pixels(:,1))) + abs(diff(pixels(:,2)));
ind = find(dpixels == 0);
pixels(ind,:) = [];
if (pixels(1,1) == pixels(end,1) & pixels(1,2) == pixels(end,2))
    pixels(end,:) = [];
end
% delete pixels out of the ROI (<=0)
rows = find(pixels(:,1) < roil | pixels(:,1) > roir);
pixels(rows,:) = [];
cols = find(pixels(:,2) < roib | pixels(:,2) > roiu);
pixels(cols,:) = [];

if nargout == 0   % draw circles
%    plot(x0, y0, 'xr', 'LineWidth',2); % also plots the center
    plot(pixels(:,1), pixels(:,2), 'r', 'LineWidth',2);
else
    varargout{1} = pixels;
end


function [Mreordered,Mindices,cost] = reorder_matrix(M1,cost,flag)
%REORDER_MATRIX         matrix reordering for visualization
%
%   [Mreordered,Mindices,cost] = reorder_matrix(M1,cost,flag)
%
%   This function rearranges the nodes in matrix M1 such that the matrix
%   elements are squeezed along the main diagonal.  The function uses a
%   version of simulated annealing.
%
%   Inputs:     M1             = connection matrix (weighted or binary,
%                                directed or undirected)
%               cost           = 'line' or 'circ', for shape of lattice
%                                cost (linear or ring lattice)
%
%               Mreordered     = reordered connection matrix
%               Mindices       = reordered indices
%               cost           = distance between M1 and Mreordered
%
%   Note that in general, the outcome will depend on the initial condition
%   (the setting of the random number seed).  Also, there is no good way to
%   determine optimal annealing parameters in advance - these paramters
%   will need to be adjusted "by hand" (particularly H, Texp, and T0).
%   For large and/or dense matrices, it is highly recommended to perform
%   exploratory runs varying the settings of 'H' and 'Texp' and then select
%   the best values.
%
%   Based on extensive testing, it appears that T0 and Hbrk can remain
%   unchanged in most cases.  Texp may be varied from 1-1/H to 1-10/H, for
%   example.  H is the most important parameter - set to larger values as
%   the problem size increases.  It is advisable to run this function
%   multiple times and select the solution(s) with the lowest 'cost'.
%
%   Setting 'Texp' to zero cancels annealing and uses a greedy algorithm
%   instead.
%
%   Yusuke Adachi, University of Tokyo 2010
%   Olaf Sporns, Indiana University 2010

N = size(M1,1);

% generate cost function
if (strcmp(cost,'line'))
    profil = fliplr(normpdf(1:N,0,N/2));
end;
if (strcmp(cost,'circ'))
    profil = fliplr(normpdf(1:N,N/2,N/4));
end;
COST = (toeplitz(profil,profil).*~eye(N));
COST = COST./sum(sum(COST));

% establish maxcost, lowcost, mincost
maxcost = sum(sort(COST(:)).*(sort(M1(:))));
lowcost = sum(sum(M1.*COST))/maxcost;
mincost = lowcost;

% initialize
anew = 1:N;
amin = 1:N;
h = 0; hcnt = 0;

% set annealing parameters
% H determines the maximal number of steps
% Texp determines the steepness of the temperature gradient
% T0 sets the initial temperature (and scales the energy term)
% Hbrk sets a break point for the simulation (if no further improvement)
H = 1e04; Texp = 1-10/H; T0 = 1e-03; Hbrk = H/10;
%Texp = 0;

while h<H
    h = h+1; hcnt = hcnt+1;
    % terminate if no new mincost has been found for some time
    if (hcnt>Hbrk)
        break;
    end;
    % current temperature
    T = T0*Texp^h;
    % choose two positions at random and flip them
    atmp = anew;
    %r = randperm(N);  % slower
    r = ceil(rand(1,2).*N);
    atmp(r(1)) = anew(r(2));
    atmp(r(2)) = anew(r(1));
    costnew = sum(sum(M1(atmp,atmp).*COST))/maxcost;
    % annealing
    if (costnew < lowcost) || (rand < exp(-(costnew-lowcost)/T))
        anew = atmp;
        lowcost = costnew;
        % is this a new absolute best?
        if (lowcost<mincost)
            amin = anew;
            mincost = lowcost;
            if (flag==1)
                disp(['step ',num2str(h),' ... current lowest cost = ',num2str(mincost)]);
            end;
            hcnt = 0;
        end;
    end;
end;
disp(['step ',num2str(h),' ... final lowest cost = ',num2str(mincost)]);

% prepare output
Mreordered = M1(amin,amin);
Mindices = amin;
cost = mincost;


% Copyright (C) 2012 Rik Wehbring
% Copyright (C) 1995-2012 Kurt Hornik
%
% This file is part of Octave.
%
% Octave 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.
%
% Octave 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 Octave; see the file COPYING.  If not, see
% <http://www.gnu.org/licenses/>.

% -*- texinfo -*-
% @deftypefn {Function File} {} finv (@var{x}, @var{m}, @var{n})
% For each element of @var{x}, compute the quantile (the inverse of
% the CDF) at @var{x} of the F distribution with @var{m} and @var{n}
% degrees of freedom.
% @end deftypefn

% Author: KH <Kurt.Hornik@wu-wien.ac.at>
% Description: Quantile function of the F distribution

function inv = finv (x, m, n)

if (nargin ~= 3)
  print_usage ();
end

if (~isscalar (m) || ~isscalar (n))
  [retval, x, m, n] = common_size (x, m, n);
  if (retval > 0)
    error ('finv: X, M, and N must be of common size or scalars');
  end
end

if ~(isreal (x) || isreal (m) || isreal (n))
  error ('finv: X, M, and N must not be complex');
end

if (isa (x, 'single') || isa (m, 'single') || isa (n, 'single'))
  inv = NaN (size (x), 'single');
else
  inv = NaN (size (x));
end

k = (x == 1) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf);
inv(k) = Inf;

k = (x >= 0) & (x < 1) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf);
if (isscalar (m) && isscalar (n))
  inv(k) = ((1 ./ betainv (1 - x(k), n/2, m/2) - 1) * n / m);
else
  inv(k) = ((1 ./ betainv (1 - x(k), n(k)/2, m(k)/2) - 1)...
    .* n(k) ./ m(k));
end

end


function r8ge_print ( m, n, a, title )

%*****************************************************************************80
%
%% R8GE_PRINT prints a R8GE matrix.
%
%  Discussion:
%
%    The R8GE storage format is used for a general M by N matrix.  A storage
%    space is made for each logical entry.  The two dimensional logical
%    array is mapped to a vector, in which storage is by columns.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    07 April 2006
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer M, the number of rows of the matrix.
%    M must be positive.
%
%    Input, integer N, the number of columns of the matrix.
%    N must be positive.
%
%    Input, real A(M,N), the R8GE matrix.
%
%    Input, string TITLE, a title to be printed.
%
  r8ge_print_some ( m, n, a, 1, 1, m, n, title );

  return
end


function y = daub10_transform ( n, x )

%*****************************************************************************80
%
%% DAUB10_TRANSFORM computes the DAUB10 transform of a vector.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 July 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the dimension of the vector.
%    N must be a power of 2 and at least 4.
%
%    Input, real X(N), the vector to be transformed.
%
%    Output, real Y(N), the transformed vector.
%
  c = [ ...
    0.1601023979741929; ...
    0.6038292697971895; ...
    0.7243085284377726; ...
    0.1384281459013203; ...
   -0.2422948870663823; ...
   -0.0322448695846381; ...
    0.0775714938400459; ...
   -0.0062414902127983; ...
   -0.0125807519990820; ...
    0.0033357252854738 ];
  p = 9;
  y(1:n,1) = x(1:n);
  m = n;
  q = floor ( ( p - 1 ) / 2 );

  while ( 4 <= m )

    i = 1;
    z(1:m,1) = 0.0;

    for j = 1 : 2 : m - 1

      mh = floor ( m / 2 );
      for k = 0 : 2 : p - 1
        j0 = i4_wrap ( j + k,     1, m );
        j1 = i4_wrap ( j + k + 1, 1, m );
        z(i,1)    = z(i,1)    + c(  k+1) * y(j0) + c(  k+2) * y(j1);
        z(i+mh,1) = z(i+mh,1) + c(p-k+1) * y(j0) - c(p-k  ) * y(j1);
      end

      i = i + 1;

    end

    y(1:m,1) = z(1:m);

    m = floor ( m / 2 );

  end

  return
end


%--------------------------------------------------------------------------
%
% Example script for sinf_1D.m and sinf_3D.m
%
% Author        : dr.ir. Emanuel A.P. Habets
% Date          : 16-09-2010
%
% Related paper : E.A.P. Habets and S. Gannot, 'Generating sensor signals
%                 in isotropic noise fields', Submitted to the Journal
%                 of the Acoustical Society of America, May, 2007.
%
% Comment       :
%
%--------------------------------------------------------------------------

clear;
close all;

%% Initialization
fs = 8000;                       % Sample frequency
NFFT = 256;                      % Number of frequency bins (for analysis)
w = 2*pi*fs*(0:NFFT/2)/NFFT;
c = 340;                         % Speed of sound
L = 2^18;                        % Data length

[x1,y1,z1]=sph2cart(0,0,0.1);    % Sensor position 1
[x2,y2,z2]=sph2cart(0,0,0.2);    % Sensor position 2
P = [0 x1 x2; 0 y1 y2; 0 z1 z2]; % Construct position matrix
M = 3;                           % Number of sensors

% Calculate sensor distances w.r.t. sensor 1
d = zeros(1,M);
for m = 2:M
    d(m) = norm(P(:,m)-P(:,1),2);
end

%% Generate sensor signals
params.c = c;
params.fs = fs;

% 1D example
params.N_phi = 64;
z = sinf_1D(d,L,params);

% 3D example
% params.N = 256;
% z = sinf_3D(P,L,params);

%% Calculate spatial coherences
sc_sim = zeros(M-2,NFFT/2+1);
sc_theory = zeros(M-2,NFFT/2+1);
for m = 1:M-1
    [sc,F]=mycohere(z(1,:)',z(m+1,:)',NFFT,fs,hanning(NFFT),0.75*NFFT);
    sc_sim(m,:) = real(sc');

    sc_theory(m,:) = sinc(w*d(m+1)/c/pi);
end

%% Plot results
% Sensor pair 1-2
figure(1);
m=1;
plot(F/1000,sc_sim(m,:),'k')
hold on;
plot(F/1000,sc_theory(m,:),'--k')
hold off;
xlabel('Frequency [kHz]');
ylabel('Spatial Coherence');
title(sprintf('Distance %1.2f m',d(m+1)));
set(gca,'DataAspectRatio',[1 0.75 1]);
legend('Simulation','Theory');
grid on;

% Sensor pair 1-3
figure(2);
m=2;
plot(F/1000,sc_sim(m,:),'k')
hold on;
plot(F/1000,sc_theory(m,:),'--k')
hold off;
xlabel('Frequency [kHz]');
ylabel('Spatial Coherence');
title(sprintf('Distance %1.2f m',d(m+1)));
set(gca,'DataAspectRatio',[1 0.75 1]);
legend('Simulation','Theory');
grid on;


function[varargout]=twodsort(varargin)
%TWODSORT  Distances from data points to nearby grid points.
%
%   [DS,XS,YS]=TWODSORT(X,Y,XO,YO,CUTOFF) returns sorted distances D
%   between data points at locations X,Y and grid points at XO,YO.
%
%   X and Y are arrays of the same size into data point locations. XO and
%   YO are arrays of length M and N, say, specifying the bin center
%   locations of an M x N matrix of grid points, i.e.
%
%      XO= [XO_1 XO_2 ... XO_N]      XO =  [YO_1;
%                                           YO_2;
%                                            ...
%                                           YO_M]
%
%   CUTOFF is the maximum distance to be included in the output arrays.
%
%   The output arrays are M numerical arrays arranged as a length M cell
%   array.  That is, there is one cell per element of Y0. Each numerical
%   array has N columns, i.e., the number of elements of X0, with the
%   number of rows varying between arrays.
%
%   DS gives the distances SQRT((X-XO)^2+(Y-YO)^2) of all data points less
%   than the CUTOFF distance from the (m,n)th grid point, sorted in order
%   of increasing distance.  Entries farther than CUTOFF in all output
%   fields are filled with NaNs.
%
%   XS and YS are corresponding deviations X-XO and Y-YO from the grid
%   point location to each data point.
%
%   The choice to put rows into cell arrays is made because for consistency
%   with SPHERESORT and for convenience in parallelizing POLYSMOOTH.
%   _________________________________________________________________
%
%   Limiting output dimension
%
%   [DS,XS,YS]=TWODSORT(X,Y,XO,YO,[CUTOFF JMAX]), where the fifth input
%   argument is a 2-vector, additionally specifies that number of rows of
%   in each cell of the output will be no larger than JMAX.  This option is
%   useful for the 'fixed population' algorithm in POLYSMOOTH.
%   _________________________________________________________________
%
%   Additional input parameters
%
%   Let's say some additional variables Z1, Z2,...,ZK are given at the data
%   locations X,Y.  Then
%
%   [DS,XS,YS,Z1S,Z2S,...,ZKS]=
%
%                TWODSORT(X,Y,Z1,Z2,...,ZK,XO,YO,CUTOFF);
%
%   also returns the values of these variables.
%
%   Z1S, Z2S,...,ZKS are the same size as the other output arguments, and
%   give the values of Z1, Z2,...,ZK sorted according to distance.
%
%   When there are multiple fields to be mapped, one may instead wish to
%   use the approach described under "One grid, many fields" in POLYSMOOTH.
%   _________________________________________________________________
%
%   See also SPHERESORT, POLYSMOOTH.
%
%   'twodsort --t' runs a test.
%
%   Usage: [ds,xs,ys,indexs]=twodsort(x,y,xo,yo,cutoff);
%          [ds,xs,ys,zs,indexs]=twodsort(x,y,zs,xo,yo,cutoff);
%          [ds,xs,ys,z1s,z2s,...,zNs]=twodsort(x,y,z1,z2,...,zN,xo,yo,cutoff);
%   __________________________________________________________________
%   This is part of JLAB --- type 'help jlab' for more information
%   (C) 2008--2020 J.M. Lilly --- type 'help jlab_license' for details

if strcmpi(varargin{1}, '--t')
    twodsort_test,return
end

xdata=varargin{1};
ydata=varargin{2};
xo=varargin{end-2};
yo=varargin{end-1};
cutoff=varargin{end};
varargin=varargin(3:end-3);

%In case max # points is not input
Ncutoff=inf;
if length(cutoff)==2
    Ncutoff=cutoff(2);
    cutoff=cutoff(1);
end

xo=xo(:);
yo=yo(:);

K=nargout;
if length(varargin)<K-3
    error('Not enough input arguments.')
end

%K,length(varargin)

if ~aresame(size(xdata),size(ydata))
    error('XDATA and YDATA must be the same size.')
end

for k=1:K
    varargout{k}=cell(length(yo),1);
end
indexo=find(isfinite(xdata)&isfinite(ydata));

if ~isempty(indexo)
    vcolon(xdata,ydata);
    vindex(xdata,ydata,indexo,1);
else
    disp(['No finite data values.']), return
end

%indexall=1:length(xdata);

N=length(xo);
for i=1:length(yo)
    xp=vrep(xdata,N,2)-vrep(xo',length(xdata),1);
    yp=vrep(ydata-yo(i),N,2);
    d=sqrt(xp.^2+yp.^2);
    d(d>cutoff)=nan;
    xp(isnan(d))=nan;
    yp(isnan(d))=nan;

    %size(d)
    if ~allall(~isfinite(d))
        [dsort,sorter]=sort(d,'ascend');
        jj=vrep(1:N,length(xdata),1);
        index=sub2ind(size(d),sorter,jj);

        xp=xp(index);
        yp=yp(index);

        L=min(find(sum(isfinite(dsort),2),1,'last'),Ncutoff);
        varargout{1}{i}=dsort(1:L,:);
        varargout{2}{i}=xp(1:L,:);
        varargout{3}{i}=yp(1:L,:);
        %vsize(d,xp,yp,dsort,sorter)
        for k=4:K
            temp=vrep(varargin{k-3}(indexo),N,2);
            temp=temp(index);
            temp(isnan(dsort))=nan;
            varargout{k}{i}=temp(1:L,:);
        end
    end
end

function[]=twodsort_test

[x,y,z]=peaks;
index=randperm(length(z(:)));
index=index(1:200);

[xdata,ydata,zdata]=vindex(x(:),y(:),z(:),index,1);

%Insert some NANs
xdata(1:7:end)=nan;

xo=(-3:.125:3);
yo=(-3:.125:3);
[xg,yg]=meshgrid(xo,yo);

%[ds,xs,ys,xs2,ys2]=twodsort(xdata,ydata,xdata,ydata,xo,yo,[1 20]);
%vsize(ds,xs,ys,xs2,ys2)

[ds,xs,ys,xs2,ys2]=twodsort(xdata,ydata,xdata,ydata,xo,yo,1);
for i=1:length(xs)
    bool(i)=aresame(xs{i}+vrep(xo,size(xs{i},1),1),xs2{i})&aresame(ys{i}+yo(i),ys2{i});
end
reporttest('TWODSORT consistency',allall(bool));


function [p,t] = circlemesh(x,y,r,h)
%% CIRCLEMESH generates a mesh for a circle
%
% [node,elem] = circlemesh(x,y,r,h) generates a quasi-uniform mesh with
% size h of the circle centered at (x,y) with readius r.
%
% Example
%
%   [node,elem] = circlemesh(0,0,1,0.1);
%   showmesh(node,elem);
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

[p,t] = odtmesh2d(@fd,@huniform,h,[-1,-1;1,1],[],0,x,y,r);

    function s = fd(p,x,y,r)
    s = sqrt(sum((p(:,1)-x).^2+(p(:,2)-y).^2,2))-r;
    end

    function h = huniform(p,varargin)
    h = ones(size(p,1),1);
    end
end


function [E,H] = Maxwell1D(E,H,eps,mu,FinalTime);

% function [E,H] = Maxwell1D(E,H,eps,mu,FinalTime)
% Purpose  : Integrate 1D Maxwell's until FinalTime starting with conditions (E(t=0),H(t=0))
%            and materials (eps,mu).

Globals1D;
time = 0;

% Runge-Kutta residual storage
resE = zeros(Np,K); resH = zeros(Np,K);

% compute time step size
xmin = min(abs(x(1,:)-x(2,:)));
CFL=1.0;  dt = CFL*xmin;
Nsteps = ceil(FinalTime/dt); dt = FinalTime/Nsteps

% outer time step loop
for tstep=1:Nsteps
   for INTRK = 1:5
      [rhsE, rhsH] = MaxwellRHS1D(E,H,eps,mu);

      resE = rk4a(INTRK)*resE + dt*rhsE;
      resH = rk4a(INTRK)*resH + dt*rhsH;

      E = E+rk4b(INTRK)*resE;
      H = H+rk4b(INTRK)*resH;
   end
   % Increment time
   time = time+dt;
end
return


function [f]=ref_idwilt_1(coef,g,a,M)
%REF_IDWILT_1  Reference IDWILT by IDGT
%

%   Author : Peter L. Søndergaard

L=size(g,1);
N=L/a;
W=size(coef,2);

coef=reshape(coef,M*2,N/2,W);

coef2=zeros(2*M,N,W);

if 1

  % ----- Loop version ---

  for n=0:N/2-1

    % m=0
    coef2(1,2*n+1,:) = coef(1,n+1,:);

    for m=0:M-1

      % m odd
      for m=1:2:M-1
	coef2(m+1,2*n+1,:)     = -i/sqrt(2)*coef(m+1,n+1,:);
	coef2(m+1,2*n+2,:)     =  1/sqrt(2)*coef(M+m+1,n+1,:);

	coef2(2*M-m+1,2*n+1,:) =  i/sqrt(2)*coef(m+1,n+1,:);
	coef2(2*M-m+1,2*n+2,:) =  1/sqrt(2)*coef(M+m+1,n+1,:);
      end;

      % m even
      for m=2:2:M-1
	coef2(m+1,2*n+1,:)     =  1/sqrt(2)*coef(m+1,n+1,:);
	coef2(m+1,2*n+2,:)     = -i/sqrt(2)*coef(M+m+1,n+1,:);

	coef2(2*M-m+1,2*n+1,:) =  1/sqrt(2)*coef(m+1,n+1,:);
	coef2(2*M-m+1,2*n+2,:) =  i/sqrt(2)*coef(M+m+1,n+1,:);
      end;

    end;

    % m=nyquest
    if mod(M,2)==0
      coef2(M+1,2*n+1,:) = coef(M+1,n+1,:);
    else
      coef2(M+1,2*n+2,:) = coef(M+1,n+1,:);
    end;

  end;

else
  % ----- Vector version ---

  % First and middle modulation are transferred unchanged.
  coef2(1,1:2:N,:) = coef(1,:,:);
  if mod(M,2)==0
    coef2(M+1,1:2:N,:) = coef(M+1,:,:);
  else
    coef2(M+1,2:2:N,:) = coef(M+1,:,:);
  end;

  if M>2
    coef2(3:2:M,1:2:N,:)        = 1/sqrt(2)*coef(3:2:M,:,:);
    coef2(3:2:M,2:2:N,:)        = -1/sqrt(2)*i*coef(M+3:2:2*M,:,:);

    coef2(2*M-1:-2:M+2,1:2:N,:) = 1/sqrt(2)*coef(3:2:M,:,:);
    coef2(2*M-1:-2:M+2,2:2:N,:) =  1/sqrt(2)*i*coef(M+3:2:2*M,:,:);
  end;

  % sine, first column.
  coef2(2:2:M,1:2:N,:)        = -1/sqrt(2)*i*coef(2:2:M,:,:);
  coef2(2:2:M,2:2:N,:)        = 1/sqrt(2)*coef(M+2:2:2*M,:,:);

  coef2(2*M:-2:M+2,1:2:N,:)   =  1/sqrt(2)*i*coef(2:2:M,:,:);
  coef2(2*M:-2:M+2,2:2:N,:)   = 1/sqrt(2)*coef(M+2:2:2*M,:,:);

end;

f=idgt(reshape(coef2,2*M,N,W),g,a);


% Test file for trigtech/roots.m

function pass = test_roots(pref)

if ( nargin < 1 )
    pref = trigtech.techPref();
end

testclass = trigtech();

%% Simple test:
f = testclass.make(@(x) cos(5*pi*x), [], pref);
r = roots(f);
exact = (-0.9:0.2:0.9).';
pass(1) = norm(r-exact,Inf) < 1e1*length(f)*eps;

%% More complicated:
k = 20;
f = testclass.make(@(x) sin(sin(pi*k*x)), [], pref);
r = roots(f);
pass(2) = norm(r-(-k:k)'/k, inf) < length(f)*eps;

%% No real roots.
f = testclass.make( @(x) 3./(5 - 4*cos(3*pi*x)), ...
    [], pref);
r = roots(f);
pass(3) = isempty(r);

%% Test that complex roots are now allowed.
f = testclass.make(@(x) 2 + cos(pi*x), [], pref);
r = roots(f, 'complex', 1);
pass(4) = norm( feval(f,r) ) < vscale(f)*eps;

f = testclass.make(@(x) sin(100*pi*x));
r1 = roots(f, 'complex', 1);
r2 = roots(f);
pass(5) = numel(r1) == 200 & numel(r2) >= 201;

%% Test an array-valued function:
f = testclass.make(@(x) [sin(pi*x), cos(pi*x)], [], pref);
r = roots(f);
r2 = [-1 0 1 -.5 .5 NaN].';
pass(6) = all( r(:) - r2 < 10*length(f)*eps | isnan(r2) );

f = testclass.make(@(x) [cos(2*pi*x), sin(pi*x)], [], pref);
r = roots(f, 'complex', 1);
r = r(:);
[temp, id] = sort(real(r));
r = r(id);
r2 = [-0.75 -0.25 0 0.25 0.75 1 NaN NaN].';
pass(7) = all( abs(r(:) - sort(r2)) < 1e1*length(f)*eps | isnan(r2) );

end


function [c,bb] = hcs(riskscore,y,z,t,varargin)
%HCS Compute Harrell's C for survival model at given time
%
%  Description
%    [C, BB] = HCS(RISKSCORE,Y,Z,T,OPTIONS) Given a risk score vector
%    RISKSCORE, an observed time vector Y, a censoring indicator column
%    vector Z (0=event, 1=censored) and time T, returns
%    Harrell's C at time T and its estimated density using
%    Bayesian Bootstrap method. Large value of RISKSCORE should predict
%    early event.
%
%    The implemented estimator is called ExtAUC(t)_Count in the reference.
%
%    OPTIONS is optional parameter-value pair
%      rsubstream - number of a random stream to be used for
%                   simulating dirrand variables. This way same
%                   simulation can be obtained for different models.
%                   See doc RandStream for more information.
%
%  Reference
%    L. E. Chambless, C. P. Cummiskey, and G. Cui (2011). Several
%    methods to assess improvement in risk prediction models:
%    Extension to survival analysis. Statistics in Medicine
%    30(1):22-38.

% Copyright (C) 2012 Tomi Peltola, Ernesto Ulloa, Aki Vehtari

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

ip=inputParser;
ip.addRequired('riskscore',@(x) ~isempty(x) && isreal(x) && all(isfinite(x(:))))
ip.addRequired('y', @(x) isreal(x) && all(isfinite(x(:))))
ip.addRequired('z', @(x) isreal(x) && all(isfinite(x(:))))
ip.addRequired('t', @(x) isreal(x) && isscalar(x) && ~isnan(x))
ip.addParamValue('rsubstream',0,@(x) isreal(x) && isscalar(x) && isfinite(x) && x>0)
ip.parse(riskscore,y,z,t,varargin{:})
rsubstream=ip.Results.rsubstream;

n=size(riskscore,1);

if nargout < 2
    % no bootstrapping
    numer = 0;
    denom = 0;
    for i = 1:n
        % i should have had event before or at t
        if z(i) == 1 || y(i) > t
            continue;
        end
        for j = 1:n
            % require y(i) < y(j) and check if the pair is concordant
            if y(i) >= y(j), continue, end;
            numer = numer + (riskscore(i) > riskscore(j));
            denom = denom + 1;
        end
    end
    c = numer / denom;
else
    % with bootstrapping
    n_replicates = 1000;

    % get substream
    if rsubstream > 0
        prevstream=setrandstream(0,'mrg32k3a');
        stream.Substream = rsubstream;
    end

    % bootstrap weights (first column is unit weights)
    w = [ones(n, 1) dirrand(n, n_replicates)];

    % set RandStream back to previous
    if rsubstream > 0
        setrandstream(prevstream);
    end

    % same algorithm as above, now with weights
    numer = zeros(1, size(w, 2));
    denom = zeros(1, size(w, 2));
    for i = 1:n
        if z(i) == 1 || y(i) > t
            continue;
        end
        for j = 1:n
            if y(i) >= y(j), continue, end;
            w_ = w(i, :) .* w(j, :);
            numer = numer + w_ * (riskscore(i) > riskscore(j));
            denom = denom + w_;
        end
    end
    bb = numer ./ denom;
    c = bb(1);  % first replicate is with unit weights
    bb(1) = []; % others are the bootstrap replicates
end

end


%              rof_mex_demo.m  by Tom Goldstein
% This code tests the method defined by "splitBregmanROF.c".  This code
% must be compiled using the "mex" command before this demo will work.

% Step 1:  Get the test image
exact = double(imread('cameraman.tif'));
dims = size(exact);

noisy = exact+15*randn(dims);

% Step 2: Denoise the Image

clean = splitBregmanROF(noisy,.05,0.001);

% Step 3:  Display Results

close all;
figure;
subplot(2,2,1);
imagesc(exact);
colormap(gray);
title('Original');

subplot(2,2,2);
imagesc(noisy);
colormap(gray);
title('noisy');

subplot(2,2,3);
imagesc(clean);
colormap(gray);
title('denoised');

subplot(2,2,4);
imagesc(noisy-clean);
colormap(gray);
title('difference');


function z = cinf_1D(d,len,params)

% Generating sensor signals for a 1D sensor array in a cylindrically
% isotropic noise field [1]
%
%    z = cinf_1D(d,len,params)
%
% Input parameters:
%    d            : sensor distances
%    len          : desired data length
%    params.fs    : sample frequency
%    params.c     : sound velocity in m/s
%    params.N_phi : number of cylindrical angles
%
% Output parameters:
%    z            : output signal
%
% References:
%    [1] E.A.P. Habets and S. Gannot, 'Generating sensor signals
%        in isotropic noise fields', The Journal of the Acoustical
%        Society of America, Vol. 122, Issue 6, pp. 3464-3470, Dec. 2007.
%
% Authors:  E.A.P. Habets and S. Gannot
%
% History:  2007-11-02 - Initial version
%           2010-09-16 - Minor corrections
%           2017-06-29 - Use native waitbar
%
% Copyright (C) 2007-2017 E.A.P. Habets
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

M = length(d);                        % Number of sensors
NFFT = 2^ceil(log2(len));             % Number of frequency bins
X = zeros(M,NFFT/2+1);

if ~isfield(params,'fs')
    fs = 8000;                        % Default
else
    fs = params.fs;
end
if ~isfield(params,'c')
    c = 340;                          % Default
else
    c = params.c;
end
if ~isfield(params,'N_phi')
    N_phi = 64;                       % Default
else
    N_phi = params.N_phi;
end

w = 2*pi*fs*(0:NFFT/2)/NFFT;
phi = 2*pi*(0:1/N_phi:1-1/N_phi);

% Calculate relative sensor distances
d_rel = d - d(1);

% Initialize waitbar
h = waitbar(0,'Generating sensor signals...');

% Calculate sensor signals in the frequency domain
for phi_idx = 1:N_phi
    waitbar(phi_idx/N_phi);
    X_prime = randn(1,NFFT/2+1) + 1i*randn(1,NFFT/2+1);
    X(1,:) = X(1,:) + X_prime;
    for m = 2:M
        Delta = d_rel(m)*cos(phi(phi_idx));
        X(m,:) = X(m,:) + X_prime.*exp(-1i*Delta*w/c);
    end
end
X = X/sqrt(N_phi);

% Transform to time domain
X = [sqrt(NFFT)*real(X(:,1)), sqrt(NFFT/2)*X(:,2:NFFT/2),...
    sqrt(NFFT)*real(X(:,NFFT/2+1)), sqrt(NFFT/2)*conj(X(:,NFFT/2:-1:2))];
z = real(ifft(X,NFFT,2));

% Truncate output signals
z = z(:,1:len);

% Close waitbar
close(h);


function [saliencyFeatures,saliencyMask,saliencyMap] = PQFT_2(img,img_3,varargin)
%%PQFT is written to demonstrate the ability of generating PQFT saliency
%%map
% Article: A Novel Multiresoulution Spatiotemporal Saliency Detection Model
% and Its Applications in Image and Video Compression
% input:
% img: current image
% img_3: frame at t = -3
% Copyright LE NGO ANH CAT, The University of Nottingham, Malaysia Campus 2012

%% Read info of img

% Tune the application for lane mark detection.
% Default value is 'general'
% Lanemark application has 'lanemark' tag
tmp_img = img;
inImg = im2double(img);
img_3 = im2double(img_3);
[row col] = size(rgb2gray(img));
visualScale = varargin{2};
inImg = imresize(inImg, [visualScale, visualScale], 'bilinear');
img_3 = imresize(img_3, [visualScale, visualScale], 'bilinear');
%% Create a quaternion image

r = inImg(:,:,1);
g = inImg(:,:,2);
b = inImg(:,:,3);

R = r - (b + g) /2;
G = g - (r + b) /2;
B = b - (r + g) /2;
Y = (r + g)/2 - abs(r - g)/2 - b;

% 2 Color channels
RG = R - G;
BY = B - Y;

% 1 Intensity channel
I = ( r + g + b ) / 3;
I_3 = sum(img_3,3) / 3;

% 1 Motion channel
M = abs(I - I_3);

% tst = zeros(varargin{2},varargin{2});
% q = quaternion(M,tst,tst,tst);
% q = quaternion(tst,RG,tst,tst);
% q = quaternion(tst,tst,BY,tst);
% q = quaternion(tst,tst,tst,I);
q = quaternion(M,RG,BY,I);

%% Test for edge features
% gray_img = rgb2gray(inImg);
% HE = double(edge(gray_img,'sobel','horizontal'));
% VE = double(edge(gray_img,'sobel','vertical'));
% q = quaternion(M,HE,VE,I);

%% Create Spatio-temporal Saliency Map by using QFT (Quaternion Fourier
%% Transform

myFFT = fft2(q);
a = ones(visualScale,visualScale)*q1 + ones(visualScale,visualScale)*q2 + ones(visualScale,visualScale)*q3;
myPhase = angle(myFFT,unit(a));

%% Display the spectrum of images with Gaussian Smoother
% tmp_myPhase = reshape(myPhase,[1 4096]);
% [n,xout] = hist(tmp_myPhase,100);
% figure;
% plot(xout,n);
% % % Gaussian Filter begin
% % gf=gausswin(8,3);
% % gf=gf/sum(gf);
% % n_smoothed=conv(gf,n);
% % figure;
% % plot(n_smoothed);
% ylabel('No of pixels');
% xlabel('Phase');
% % % Datacursors format
% % alldatacursors = findall(gcf,'type','hggroup');
% % set(alldatacursors,'FontSize',12);
saliencyMap = abs(ifft2(exp(1i*myPhase))).^2;
saliencyMap(1,1) = (saliencyMap(1,2) + saliencyMap(2,2) + saliencyMap(2,1))/3;
%% After Effect
if (isequal(varargin{1},'disk'))
    saliencyMap = imfilter(saliencyMap, fspecial('disk', 3));
elseif (isequal(varargin{1},'gaussian'))
    saliencyMap = imfilter(saliencyMap, fspecial('gaussian', 8, 3));
end
saliencyMap = mat2gray(saliencyMap);
% imshow(saliencyMap);
saliencyMask = im2bw(saliencyMap,graythresh(saliencyMap));

saliencyMap = imresize(saliencyMap, [row,col], 'bilinear');
saliencyMask = imresize(saliencyMask, [row,col], 'bilinear');

% %% LME as post-processing step
% if isequal(varargin{3},'lanemark_pospro')
%     img = LME(img);
%     saliencyMask = saliencyMask | (rgb2gray(img) > 0);
% end
%
% %% Result Presentation
% img = tmp_img;
% grayImg = double(rgb2gray(img));
%
% % % The below code line is for drawing around the lanemark
% % saliencyMask = 1 - edge(double(saliencyMask),'canny');
% saliencyFeatures = grayImg .* saliencyMask;

%% Filter the unnecessary road parts
tmp(:,:,1) = tmp_img(:,:,1) .* uint8(saliencyMask);
tmp(:,:,2) = tmp_img(:,:,2) .* uint8(saliencyMask);
tmp(:,:,3) = tmp_img(:,:,3) .* uint8(saliencyMask);
tmp = []; % Delete temporary variable

%% Result Presentation in Grayscale or Color
img = tmp_img;

if (nargin - 2 < 3) || isequal(varargin{3},'grayscale')
    grayImg = double(rgb2gray(img));
    % saliencyMask = 1 - edge(double(saliencyMask),'canny');
    saliencyFeatures = grayImg .* saliencyMask;
elseif isequal(varargin{3},'color')
    saliencyFeatures(:,:,1) = img(:,:,1) .* uint8(saliencyMask);
    saliencyFeatures(:,:,2) = img(:,:,2) .* uint8(saliencyMask);
    saliencyFeatures(:,:,3) = img(:,:,3) .* uint8(saliencyMask);
end
end


function [I,EI] = information(P)
%
%[I,EI] = information(P)
% Obtains the information (pointwise) and its expectation from a distribution of 1
% or two variables, hence:
% - for Pxy a bivariate distribution:
%  [I_Pxy,H_Pxy] = information(Pxy)
% obtains I_Pxy = log Pxy and H_Pxy is joint entropy
%
% - for Px a (row,column) univariate distribution
%  [I_Px,H_Px] = information(Px)
% obtains the self-information and the entropy.

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

I = -log2(P);
if nargout == 2
    lp = logical(P);
    if any(size(P) == 1)%row distribution or column distribution, resp
        EI = sum(P(lp) .* I(lp));
    else%bivariate, be very careful
        EI = sum(sum(P(lp) .* I(lp)));
    end
end
return%I,EI


function [kWh] = cal2kWh(cal)
% Convert energy or work from calories to kilowatt-hours.
% Note: these calories are different from the capitalized Calories found on
% American cereal boxes.  I suppose we'd be afraid to eat a candy bar with
% 250,000 calories in it.  Because then we'd feel like fatties.
% Chad A. Greene 2012
kWh = cal*0.000001163;


function G = GCVstopfun(alpha, u, s, beta, m, n)
%
%  G = GCVstopfun(alpha, u, s, beta, n, insolv)
%  This function evaluates the GCV function G(i, alpha), that will be used
%     to determine a stopping iteration.
%
% Input:
%   alpha - regularization parameter at the kth iteration of HyBR
%       u - P_k^T e_1 where P_k contains the left singular vectors of B_k
%       s - singular values of bidiagonal matrix B_k
%    beta - norm of rhs b
%     m,n - size of the ORIGINAL problem (matrix A)

% Silvia Gazzola, University of Bath
% Per Christian Hansen, Technical University of Denmark
% James G. Nagy, Emory University
% April, 2018.

% This file is part of the IR Tools package and is distributed under the
% 3-Clause BSD License. A separate license file should be provided as part
% of the package.

k = length(s);
beta2 = beta^2;

s2 = abs(s) .^ 2;
alpha2 = alpha^2;

t1 = 1 ./ (s2 + alpha2);
t2 = abs(alpha2*u(1:k) .* t1) .^2;
t3 = s2 .* t1;

num = beta2*(sum(t2) + abs(u(k+1))^2)/n;
den = ( (m - sum(t3))/n )^2;
G = num / den;


classdef DOC1 < PROBLEM
% <multi> <real> <constrained>
% Benchmark MOP with constraints in both decision and objective spaces

%------------------------------- Reference --------------------------------
% Z. Liu and Y. Wang, Handling constrained multiobjective optimization
% problems with constraints in both the decision and objective spaces. IEEE
% Transactions on Evolutionary Computation, 2019, 23(5): 870-884.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    methods
        %% Default settings of the problem
        function Setting(obj)
            obj.M = 2;
            obj.D = 6;
            obj.lower    = [0 78 33 27 27 27];
            obj.upper    = [1 102 45 45 45 45];
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values and constraint violations
        function Population = Evaluation(obj,varargin)
            X = varargin{1};
            X = max(min(X,repmat(obj.upper,size(X,1),1)),repmat(obj.lower,size(X,1),1));
            g = 5.3578547 * X(:, 4).^2 + 0.8356891 * X(:, 2).* X(:, 6) + 37.293239 * X(:, 2) - 40792.141+30665.5386717834 +1;
            PopObj(:,1) = X(:,1);
            PopObj(:,2) = g.*(1-sqrt(PopObj(:,1))./g);
            % Constraints in objective space
            PopCon(:,1) = max( -(PopObj(:,1).^2 + PopObj(:,2).^2-1), 0);
            % Constraints in decision space
            PopCon(:,2) = + 85.334407 + 0.0056858 * X(:, 3).* X(:, 6) + 0.0006262 * X(:, 2).* X(:, 5) - 0.0022053 * X(:, 4).* X(:, 6) - 92;
            PopCon(:,3) = -85.334407 - 0.0056858 * X(:, 3).* X(:, 6) - 0.0006262 * X(:, 2).* X(:, 5) + 0.0022053 * X(:, 4).* X(:, 6);
            PopCon(:,4) = + 80.51249 + 0.0071317 * X(:, 3).* X(:, 6) + 0.0029955 * X(:, 2).* X(:, 3) + 0.0021813 * X(:, 4).^2 - 110;
            PopCon(:,5) = -80.51249 - 0.0071317 * X(:, 3).* X(:, 6) - 0.0029955 * X(:, 2).* X(:, 3) - 0.0021813 * X(:, 4).^2 + 90;
            PopCon(:,6) = + 9.300961 + 0.0047026 * X(:, 4).* X(:, 6) + 0.0012547 * X(:, 2).* X(:, 4) + 0.0019085 * X(:, 4) .* X(:, 5) - 25;
            PopCon(:,7) = -9.300961 - 0.0047026 * X(:, 4).* X(:, 6) - 0.0012547 * X(:, 2).* X(:, 4) - 0.0019085 * X(:, 4) .* X(:, 5) + 20;
            Population  = SOLUTION(X,PopObj,PopCon,varargin{2:end});
            obj.FE      = obj.FE + length(Population);
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            R = UniformPoint(N,2);
            R = R./repmat(sqrt(sum(R.^2,2)),1,2);
        end
        %% Generate the image of Pareto front
        function R = GetPF(obj)
            R = obj.GetOptimum(100);
        end
    end
end


% Fig. 6.21   Feedback Control of Dynamic Systems, 6e
%             Franklin, Powell, Emami
%

clear all;
%close all;
clf

num=1;
den=[1 2 1];
rlocus(num,den);
axis([-3 1 -2 2])
grid;
title('Fig. 6.21: Root locus of G(s)=1/(s+2)^2 vs K');


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% triple.m %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% function [xtrip,ftrip,g,G,x1,x2,nf] = triple(fcn,data,x,f,x1,x2,u,v,G)
% finding a local quadratic model by triple search
% Input:
% fcn = 'fun'	name of function fun(data,x), x an n-vector
% x(1:n)	start vector
% f		its function value
% x1(1:n), x2(1:n)  'neighbors' of x with x(i), x1(i), x2(i) pairwise
%		distinct for i = 1,...,n
% [u,v]		original box
% G		Hessian of the quadratic model around xtrip
% Output:
% xtrip(1:n)	best point found
% ftrip		its function value
% g, G		gradient and Hessian of the quadratic model around xtrip
% the quadratic model is given by
% q(x) = ftrip + g^T(x-xtrip) + 0.5(x-xtrip)G(x-xtrip)
% Uses the following m-files:
% hessian.m
% polint1.m

function [xtrip,ftrip,g,G,x1,x2,nf] = triple(fcn,data,x,f,x1,x2,u,v,hess,G)
nf = 0;
n = length(x);
g = zeros(n,1);
if nargin < 9
  hess = ones(n,n);
end
ind = find(u < x & x < v);
ind1 = find(x <= u | x >= v);
for j=1:length(ind1)
  g(ind1(j)) = 0;
  for k=1:n
    G(ind1(j),k) = 0;
    G(k,ind1(j)) = 0;
  end
end
if length(ind) <= 1
  xtrip = x;
  ftrip = f;
  if ~isempty(ind)
    g(ind) = 1;
    G(ind,ind) = 1;
  end
  return
end
if nargin < 10
  G = zeros(n,n);
end
xtrip = x;
ftrip = f;
xtripnew = x;
ftripnew = f;
for j=1:length(ind)
  i = ind(j);
  x = xtrip;
  f = ftrip;
  x(i) = x1(i);
  f1 = feval(fcn,data,x);
  x(i) = x2(i);
  f2 = feval(fcn,data,x);
  nf = nf + 2;
  [g(i),G(i,i)] = polint1([xtrip(i) x1(i) x2(i)],[f f1 f2]);
  if f1 <= f2
    if f1 < ftrip
      ftripnew = f1;
      xtripnew(i) = x1(i);
    end
  else
    if f2 < ftrip
      ftripnew = f2;
      xtripnew(i) = x2(i);
    end
  end
  if nargin < 10
    k1 = 0;
    if f1 <= f2
      x(i) = x1(i);
    else
      x(i) = x2(i);
    end
    for k=1:i-1
      if hess(i,k)
        if xtrip(k) > u(k) & xtrip(k) < v(k) & ~isempty(find(ind==k))
          q1 = ftrip + g(k)*(x1(k)-xtrip(k))+0.5*G(k,k)*(x1(k)-xtrip(k))^2;
          q2 = ftrip + g(k)*(x2(k)-xtrip(k))+0.5*G(k,k)*(x2(k)-xtrip(k))^2;
          if q1 <= q2
            x(k) = x1(k);
          else
            x(k) = x2(k);
          end
          f12 = feval(fcn,data,x);
          nf = nf + 1;
          G(i,k) = hessian(i,k,x,xtrip,f12,ftrip,g,G);
          G(k,i) = G(i,k);
          if f12 < ftripnew
            ftripnew = f12;
            xtripnew = x;
            k1 = k;
          end
          x(k) = xtrip(k);
        end
      else
        G(i,k) = 0;
        G(k,i) = 0;
      end
    end
  end
  if ftripnew < ftrip
    if x1(i) == xtripnew(i)
      x1(i) = xtrip(i);
    else
      x2(i) = xtrip(i);
    end
    if nargin < 10 & k1 > 0
      if xtripnew(k1) == x1(k1)
        x1(k1) = xtrip(k1);
      else
        x2(k1) = xtrip(k1);
      end
    end
    for k=1:i
      if ~isempty(find(ind==k))
        g(k) = g(k) + G(i,k)*(xtripnew(i) - xtrip(i));
        if nargin < 10 & k1 > 0
          g(k) = g(k) + G(k1,k)*(xtripnew(k1) - xtrip(k1));
        end
      end
    end
    xtrip = xtripnew;
    ftrip = ftripnew;
  end
end


function [ res ] = crossprod( a, b )
%CROSSPROD Summary of this function goes here
%   Detailed explanation goes here

    Ax = [  0,   -a(3),   a(2);
           a(3),     0,  -a(1);
          -a(2),  a(1),      0;];

   res = Ax * b(:);

end


%%%%%%%%%%%%%%%%%%%%%%%
%    R E S U L T S
%%%%%%%%%%%%%%%%%%%%%%%

%% Using T3 elements,

% Max y-displacement
% Node           UX           UY
%   8   1.916937e-06    -1.065042e-05
T3_disp = -1.065042e-05;

% Stress in element 5 [MPA]
T3_Sigma_xx_e5 = -650.431082;
T3_Sigma_yy_e5 = -650.431082;
T3_Sigma_xy_e5 = -650.431082;
T3_Vonmises_e5 =  1300.862163;

% Stress in element 6 [MPA]
T3_Sigma_xx_e6 =  650.431082;
T3_Sigma_yy_e6 =  645.504435;
T3_Sigma_xy_e6 = -1349.568918;
T3_Vonmises_e6 =  2425.672941;

% Average stress in Node 8 [MPA]

T3_Sigma_xx = (T3_Sigma_xx_e6+T3_Sigma_xx_e5)/2
T3_Sigma_yy = (T3_Sigma_yy_e6+T3_Sigma_yy_e5)/2
T3_Sigma_xy = (T3_Sigma_xy_e6+T3_Sigma_xy_e5)/2
T3_Vonmises = (T3_Vonmises_e6+T3_Vonmises_e5)/2

% T3_Sigma_xx = 0
% T3_Sigma_yy = -2.4633
% T3_Sigma_xy = -1000
% T3_Vonmises = 1.8633e+03

%% Using Q4 elements,

% Max y-displacement
% Node           UX           UY
%    8   6.1172e-06    -2.6430e-05
Q4_disp = -2.6430e-05;

% Stress in element 3

% Stress in node 3 [MPA]
Q4_Sigma_xx = 1947.025060;
Q4_Sigma_yy = -837.861465;
Q4_Sigma_xy = -543.285579;
Q4_Vonmises = 2647.590101;

%% Using Q8 elements,

% Max y-displacement
% Node           UX           UY
%   18   9.1557e-06    -3.8250e-05
Q8_disp = -3.8250e-05;

% Stress in element 3

% Stress in node 3 [MPA]
Q8_Sigma_xx = 547.919444;
Q8_Sigma_yy = -5070.115307;
Q8_Sigma_xy = -1926.948499;
Q8_Vonmises = 6318.519705;

%% Using Q12 elements,

% Max y-displacement
% Node           UX           UY
%   28   9.3240e-06    -3.8900e-05
Q12_disp = -3.8900e-05;

% Stress in element 3

% Stress in node 3 [MPA]
Q12_Sigma_xx = -209.968713;
Q12_Sigma_yy = -7862.634791;
Q12_Sigma_xy = -2337.689116;
Q12_Vonmises = 8752.632553;

%%%%%%%%%%%%%%%%%%%%%%%
%    C O M P A R E
%%%%%%%%%%%%%%%%%%%%%%%
x = 1:4;
str = ['T3','Q4','Q8','Q12'];
disp_y   = [T3_disp,Q4_disp,Q8_disp,Q12_disp];
Sigma_xx = [T3_Sigma_xx,Q4_Sigma_xx,Q8_Sigma_xx,Q12_Sigma_xx];
Sigma_yy = [T3_Sigma_yy,Q4_Sigma_yy,Q8_Sigma_yy,Q12_Sigma_yy];
Sigma_xy = [T3_Sigma_xy,Q4_Sigma_xy,Q8_Sigma_xy,Q12_Sigma_xy];
VonMises = [T3_Vonmises,Q4_Vonmises,Q8_Vonmises,Q12_Vonmises];
figure(1)
subplot(2,3,1); scatter(x,disp_y,'ob'); title('Max y-displacement'); ylabel('[mm]'); xlabel('T3 - Q4 - Q8 - Q12');
subplot(2,3,2); scatter(x,Sigma_xx,'ok'); title('\sigma_{xx}'); ylabel('[MPa]'); xlabel('T3 - Q4 - Q8 - Q12');
subplot(2,3,3); scatter(x,Sigma_yy,'dr'); title('\sigma_{yy}'); ylabel('[MPa]'); xlabel('T3 - Q4 - Q8 - Q12');
subplot(2,3,4); scatter(x,Sigma_xy,'sb'); title('\sigma_{xy}'); ylabel('[MPa]'); xlabel('T3 - Q4 - Q8 - Q12');
subplot(2,3,5);scatter(x,VonMises,'xk'); title('VonMises'); ylabel('[MPa]'); xlabel('T3 - Q4 - Q8 - Q12');


function a = adaboost(C,hyper)

%  ADABOOST
%
%
% A=ADABOOST(H) implements basic boosting algorithm using max_margin linear hyperplanes.
%
%
% Hyperparameters, and their defaults
% kmax = 5                -- maximum number of weak learners
%
% Methods:
%  train, test
%
% Model:
%  child                  -- hyperplanes
% Example:
%
% % Use adaboost with 1-knn as weak learner and validate with 2 fold cross validation.
% c1=[2,0];
% c2=[-2,0];
% X1=randn(50,2)+repmat(c1,50,1);
% X2=randn(50,2)+repmat(c2,50,1);
%
% [r,a]=train(cv(adaboost(knn),'folds=2'),d);
%
% ========================================================================
% Reference : The boosting approach to machine learning: An overview
% Author    : Robert E. Schapire
% Link      : http://www.cs.princeton.edu/~schapire/uncompress-papers.cgi/msri.ps
% ========================================================================

  % model
  if (nargin <1)
      C=dualperceptron('margin=1');
  end
  a.alpha=[];
  a.child={};
  a.kmax=5;

  p=algorithm('adaboost');
  a= class(a,'adaboost',p);

  if nargin==2,
    eval_hyper;
  end;

  a.alpha=ones(a.kmax,1);

  for i=1:a.kmax
  	a.child{i}=C;
  end

  disp([num2str(a.kmax),' (', C.name, ') classifiers '])


function [D] = floydwarshall(A, sym, w)
% % Copyright 2012 Nino Shervashidze
% Input: A - nxn adjacency matrix,
%           sym - boolean, 1 if A and w symmetric
%	    w - nxn weight matrix
% Output: D - nxn distance matrix

n = size(A,1); % number of nodes
D=zeros(n,n);

if nargin<2 % if the graph is not weighted and we have no information about sym, then
  sym=1;
  w=A;
end

if nargin<3 % if the graph is not weighted, then
  w=A;
end

D=w.*A; % if A(i,j)=1,  D(i,j)=w(i,j);
D(A+diag(repmat(Inf,n,1))==0)=Inf; % If A(i,j)~=0 and i~=j D(i,j)=Inf;
D=full(D.*(ones(n)-eye(n))); % set the diagonal to zero

%t=cputime;
if sym % then it is a bit faster
  for k=1:n
    Daux=repmat(full(D(:,k)),1,n);
    Sumdist=Daux+Daux';
    D(Sumdist<D)=Sumdist(Sumdist<D);
  end
else
  for k=1:n
    Daux1=repmat(full(D(:,k)),1,n);
    Daux2=repmat(full(D(k,:)),n,1);
    Sumdist=Daux1+Daux2;
    D(Sumdist<D)=Sumdist(Sumdist<D);
  end
end
%cputime-t
end