Index: distools/Contents.m
===================================================================
--- distools/Contents.m	(revision 10)
+++ distools/Contents.m	(revision 10)
@@ -0,0 +1,70 @@
+%    DisTools Table of Contents
+%   23-Nov-2009_17:27
+% 
+%   This Matlab toolbox for the analysis of dissimilarity data works only 
+%   if also the pattern recognition toolbox PRTools is available.
+%   See http://prtools.org
+% 
+%     E. Pekalska,  ela.pekalska@googlemail.com, University of Manchester
+%     R.P.W. Duin,  r.duin@ieee.org, Delft University of Technology
+% 
+%  Characterization of dissimilarity matrices
+%  ------------------------------------------
+%  CHECKEUCL    Check whether a square dissimilarity matrix has a Euclidean behavior
+%  CHECKTR      Check whether a square dissimilarity matrix obeys triangle inequality
+%  CHARDMAT     Fiand several characteristic of (dis)similarity data
+%  CORRTR       Correct a square dissimilarity matrix to obey the triangle inequality
+%  DISCHECK     Dissimilarity matrix check
+%  DISNORM      Normalization of a dissimilarity matrix
+%  DISSTAT      Basic statistics of the dissimilarity matrix
+%  ISSQUARE     Check whether a matrix is square
+%  ISSYM        Check whether a matrix is symmetric
+%  ASYMMETRY    Compute asymmetry of dissimilarity matrix
+%  NNE          Leave-one-out Nearest Neighbor error on a dissimilarity matrix
+%  NNERR        Exact expected NN error from a dissimilarity matrix
+%  
+%  Dissimilarity Measures
+%  -----------------------------------------------
+%  COSDISTM     Distance matrix based on inner products
+%  EUDISTM      Euclidean distance matrix
+%  HAMDISTM     Hamming distance matrix between binary vectors
+%  HAUSDM       Hausdorff and modified Hausdorff distance between datasets of image blobs
+%  
+%  Transformations
+%  DISSIMT      Fixed DISsimilarity-SIMilarity transformation
+%  MAKESYM      Make a matrix symmetric
+%  PE_EM        Pseudo-Euclidean embedding (includes Classical Scaling as a special case)	
+%  
+%  Classification in Pseudo-Euclidean Space and indefinite kernels
+%  -----------------------------------------------
+%  SETSIG       Set PE signature for mappings or datasets
+%  GETSIG       Set PE signature for mappings or datasets
+%  ISPE_DATASET Test dataset for PE signature setting 
+%  ISPE_EM      Test mapping for PE signature setting
+%  PE_DISTM     Square pseudo-Euclidean distance between two datasets
+%  PE_KERNELM   Compute kernel in PE space
+%  PE_MTIMES    Matrix multiplication (inner product) in PE space
+%  PE_PARZENC   Parzen classifier in PE space
+%  PE_KNNC      KNN classifier in PE space
+%  PE_NMC       Nearest mean classifier in PE space
+%  PE_EM        Pseudo-Euclidean linear embedding
+%  PLOTSPECTRUM Plot spectrum of eigenvalues
+%  
+%  Routines supporting in learning from dissimilarity matrices
+%  -----------------------------------------------------------------------
+%  CROSSVALD    Cross-validation error for dissimilarity representations
+%  DISSPACES    Compute various spaces out of a dissimilarity matrix
+%  GENDDAT      Generate random training and test sets for dissimilarity data
+%  GENREP       Generate a representation set
+%  GENREPI      Generate indices for representation, learning and testing sets
+%  SELCDAT      Select Class Subset from a Square Dissimilarity Dataset
+%  PROTSELFD    Forward prototype selection   
+%  DLPC         LP-classifier on dissimilarity (proximity) data
+%  KNNDC        K-Nearest Neighbor classifier for dissimilarity matrices
+%  PARZENDDC    Parzen classifier for dissimilarity matrices
+%  TESTKD       Test k-NN classifier for dissimilarity data
+%  TESTPD       Test Parzen classifier for dissimilarity data
+% 
+%  EXAMPLES
+%  --------
+%  CROSSVALD_EX Crossvalidation of several classifiers
Index: distools/asymmetry.m
===================================================================
--- distools/asymmetry.m	(revision 10)
+++ distools/asymmetry.m	(revision 10)
@@ -0,0 +1,14 @@
+%ASYMMETRY Estimate asymmetry of dissimilarity matrix
+%
+%   ASYM = ASYMMETRY(D)
+%
+% The asymmetry is defined as the average over 2*|D-D'|./(|D|+|D'|).
+
+function asym = asymmetry(d)
+
+  d = +d;
+  e = abs(d-d')./(abs(d)+abs(d')+1e-100); %avoid division by 0
+  L = find(~isnan(e));
+  asym = mean(mean(e(L)));
+
+return
Index: distools/aucdlpc.m
===================================================================
--- distools/aucdlpc.m	(revision 10)
+++ distools/aucdlpc.m	(revision 10)
@@ -0,0 +1,119 @@
+%AUCDLPC AUC-LP classifier on dissimilarity data
+%
+%   [W,R] = AUCLPC(D,C)
+%
+% INPUT
+%   D   Dissimilarity data
+%   C   Trade-off parameter in the LP-optimization, similar to C in the SVM
+%       (optional; default: 10)
+%
+% OUTPUT
+%   W   Mapping: AUC-LP Classifier
+%   R   Object identifiers of support objects
+%
+% DEFAULTS
+%   C  = 10
+%
+% DESCRIPTION
+% Determines a linear programming classifier for the dissimilarity representation D.
+% This LP-function is determined for a two-class problem based on the maximization
+% of the AUC measure (area under the curve) of the corresponding ROC curve.
+% It calls AUCLPM(D,C,'SUBK',1).
+%
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, AUCLPC, AUCLPM
+%
+% REFERENCE
+% D.M.J. Tax and C. Veenman, Tuning the hyperparameter of an AUC-optimized classifier,
+% in: Seventeenth Belgium-Netherlands conference on artificial intelligence, 2005, 224-231.
+
+% David Tax, Robert P.W. Duin, Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty of Electrical Engineering, Mathematics and Computer Science,
+% Delft University of Technology, The Netherlands.
+
+
+function [w,r] = aucdlpc(d,C,usematlab,prec)
+
+if nargin < 4, prec = 1e-7; end;
+if nargin < 3, usematlab = 0; end
+if nargin < 2 | isempty(C),
+  C = 10;
+end
+
+if nargin < 1 | isempty(d)
+    w = mapping(mfilename,C);
+    w = setname(w,'AUCDLPC');
+    return
+end
+
+
+[m,k,c] = getsize(d);
+
+if c > 2,
+  % multi-class problem
+
+  lab = getlab(d);
+  fe  = getfeatlab(d);
+  [nlab,nfe,lablist] = renumlab(lab,fe);
+
+  w = [];
+  N = [];
+  for i=1:c
+    mlab = 2 - (nlab == i);
+    mfe  = 2 - (nfe == i);
+    dd   = setlabels(d,mlab);
+    dd   = setfeatlab(dd,mfe);
+    if ~isempty(d.prior)
+      dd = setprior(dd,[d.prior(i),1-d.prior(i)]');
+    end
+    [v,J]= aucdlpc(dd,C,usematlab,prec);
+    w = [w,setlabels(v(:,1),lablist(i,:))];
+    N = [N; J];
+  end
+  r = unique(N);
+  w  = setname(w,'AUCDLPC');
+  return
+
+else
+  % two-class problem
+
+  v    = auclpm(d,C,'subk',1,1,usematlab);
+  nlab = getnlab(d);
+  p    = getprior(d);
+  q    = +(d*v);
+  [qq,J] = sort(q);
+  n1 = sum(nlab == 1);
+  n2 = sum(nlab == 2);
+%  e = n1-n2;
+%  J1 = cumsum(nlab(J) == 1);
+%  J2 = n2-cumsum(nlab(J) == 2);
+  e1 = p(1)*cumsum(nlab(J) == 1)/n1 + p(2)*(1 - cumsum(nlab(J) == 2)/n2);
+  e2 = p(2)*cumsum(nlab(J) == 2)/n2 + p(1)*(1 - cumsum(nlab(J) == 1)/n1);
+
+  [min1,k1] = min(e1);
+  [min2,k2] = min(e2);
+% if min1 < min2          % NO!! We should assume that AUCLPM gives a proper
+%    if k1 == length(q)   % and well defined class order: 1 -> -, 2 > +
+%      w0 = q(J(k1)) + realmin;
+%    else
+%      w0 = (q(J(k1))+q(J(k1+1)))/2;
+%    end
+%    w = v.data.u - v.data.v;
+%  else
+    if k2 == length(q)
+      w0 = q(J(k2)) + realmin;
+    else
+      w0 = (q(J(k2))+q(J(k2+1)))/2;
+    end
+    w = v.data.v - v.data.u;
+%  end
+
+  ss = sum(abs(w));
+  J  = find(abs(w) >= ss*prec);
+  w  = featsel(k,J)*affine(w(J),w0,d(:,J),getlablist(d),k,c);
+  w  = setout_conv(w,1);
+  w  = setname(w,'AUCDLPC');
+  r  = J;
+end
+return
Index: distools/augpsem.m
===================================================================
--- distools/augpsem.m	(revision 10)
+++ distools/augpsem.m	(revision 10)
@@ -0,0 +1,200 @@
+%AUGPSEM Augmented Pseudo-Euclidean Linear Embedding
+%
+% --- THIS IS A TEST VERSION! DO NOT RELY ON IT. ----
+%
+%   [W,SIG,L] = AUGPSEM(D,ALF,P)
+%
+% INPUT
+%   D   NxN symmetric dissimilarity matrix (dataset)
+%   ALF Parameter determining the dimensionality and the mapping (optional, defaulf: Inf)
+%       (0,1)   - fraction of the total (absolute value) preserved variance
+%        Inf    - no dimensionality reduction, keeping all dimensions (it's noisy)
+%       'p'     - projection into a Euclidean space based on positive eigenvalues only
+%       'PARp'  - projection into a Euclidean space based on the PAR fraction of
+%                 positive eigenvalues; e.g. ALF = '0.9p'
+%       'n'     - projection into a Euclidean space based on negative eigenvalues only
+%       'PARn'  - projection into a Euclidean space based on the PAR fraction of
+%                 positive eigenvalues; e.g. ALF = '0.7n'
+%       1 .. N  - number of dimensions <= N
+%   P   Integer between 0 and N specifying which object is mapped at the origin;
+%       0 stands for the mean; (optional, default: 0)
+%
+% OUTPUT
+%   W   Augmented pseudo-Euclidean embedding
+%   SIG Signature of the space
+%   L   List of eigenvalues
+%
+% DEFAULT
+%   ALF = INF
+%   P   = 0
+%
+% DESCRIPTION
+% Linear mapping W onto an M-dimensional pseudo-Euclidean subspace from a symmetric,
+% square dissimilarity matrix D such that the dissimilarities are preserved.
+% M is determined by ALF. E.g., the subspace is found such that at least a fraction
+% ALF of the total variance is preserved for ALF in (0,1). The resulting X is found
+% by D*W.
+% This is an augmented embedding of the standard pseudo-Euclidean embedding (PSEM)
+% such that the dissimilairites are perfectly preserved. The augmentation is by one
+% (Euclidean case) or two (pseudo-Euclidean case) dimensions. This has no effect
+% on the original data D(R,R); the additional dimension(s) are zeros. The effect
+% is apparent when test data D(Te,R) are projected. Due to the projection error,
+% the new dissimilarities are not preserved by PSEM, while they are preserved by
+% the augmented embedding.
+%
+% The parameter SIG describes the signature of the subspace. L is a sorted list
+% of eigenvalues describing the variances in the (pseudo-)Euclidean space.
+%
+% SEE ALSO
+% PSEM, MAPPINGS, DATASETS
+%
+% LITERATURE
+% 1. A. Harol, E.Pekalska, S.Verzakov, R.P.W. Duin, "Augmented embedding of
+% dissimilarity data into (pseudo-)Euclidean spaces", Joint Workshops on S+SSPR
+% Lecture Notes in Computer Science, vol. 4109, 613-621, 2006.
+% 2. L. Goldfarb, A unified approach to pattern recognition, Pattern Recognition,
+% vol.17, 575-582, 1984.
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function [W,sig,L] = augpsem(d,alf,pzero)
+
+if nargin < 3 | isempty(pzero), pzero = 0; end
+if nargin < 2 | isempty(alf), alf = inf; end
+if nargin < 1 | isempty(d)
+   W = mapping(mfilename,alf,pzero);
+   W = setname(W,'Augmented PE embedding');
+   return
+end
+
+
+
+if (isdataset(d) | isa(d,'double'))
+  if ismapping(alf)
+
+    % APPLY THE MAPPING
+    pars = getdata(alf);
+    [m,n] = size(d);
+    ds    = sum(diag(+d));
+
+    Wp    = pars{1};   % projection onto positive Euclidean subspace
+    Wn    = pars{2};   % projection onto negative Euclidean subspace
+    dme   = pars{3};   % average square distance of the training disssimilarities
+    pzero = pars{4};   % pzero=0 -> the mean of the embedded configuration lies at 0, otherwise the mean lies at pzero
+    tsig  = pars{5};   % true signature of PE embedding
+    sig   = pars{6};   % signature of the augmented PE embedding
+    tol   = pars{7};
+
+    Xp = d*Wp;
+    if tsig(2) > 0,
+      Xn = d*Wn;
+      J  = diag([ones(tsig(1),1); -ones(tsig(2),1)]);
+    else
+      Xn = [];
+      J = diag(ones(tsig(1),1));
+    end
+    XX = [+Xp +Xn];
+
+    % Compute the true PE norm depending on pzero
+    if pzero > 0,
+      Xtnorm   = +d(:,pzero).^2;
+    else
+      Xtnorm   = mean(+d.^2,2) - 0.5*dme;
+    end
+
+    % Compute the PE norm of the projected data
+    Xpnorm = diag(XX*J*XX');
+
+    % Compute the square projection error
+    % In a perfect Euclidean embedding, the true norm should >= the projected norm.
+    perr   = (Xtnorm - Xpnorm);  % negative signs of perr indicate PE space
+
+    % To remove noise, set very small values to zero
+    P = find(abs(perr) < tol);
+    perr(P) = 0;
+
+    % Additional 'positive' dimension is extablish by positive projection error
+    Ip =  find(perr >= 0);
+    Zp = zeros(m,1);
+    Zp(Ip,1) = sqrt(perr(Ip));
+
+    W = Xp;
+    if sig(2) > 0,
+      % Additional 'negative' dimension is extablish by negative projection error
+      In =  find(perr < 0);
+      Zn = zeros(m,1);
+      Zn(In,1) = -sqrt(abs(perr(In)));
+      W = setdat(W, [Xp Zp Xn Zn]);
+      if max(abs([Zp; Zn])) < tol & ds > tol & ~issym(d),
+         prwarning(1,'Augmented dimensions are close to zero. Perform PSEM, instead.');
+      end
+    else
+      W = setdat(W, [Xp Zp]);
+      if max(abs(Zp)) < tol & ds > tol & ~issym(d),
+         prwarning(1,'Augmented dimension is close to zero. Perform PSEM, instead.');
+      end
+    end
+    W.user = sig;
+    return
+  end
+end
+
+
+% TRAIN THE MAPPING
+% Tolerance value used in comparisons
+if mean(+d(:)) < 1,
+  tol = 1e-12;
+else
+  tol = 1e-10;
+end
+
+[n,m] = size(d);
+if ~issym(d,tol),
+  prwarning(1,'Matrix should be symmetric. It is made symmetric by averaging.')
+  d = 0.5*(d+d');
+end
+
+if pzero > n,
+  error('Wrong third parameter.');
+end
+
+[W,tsig,L,Q] = psem(d,alf,pzero);
+Wp  = psem(W,'p');
+Wn  = [];
+sig = tsig;   % this is the signature describing augmented mapping
+I   = tsig > 0;
+sig (I) = sig(I) + 1;
+if tsig(2) > 0,
+  Wn  = psem(W,'n');
+end
+dme = mean(+d(:).^2);
+
+
+%%%%% ------------ THIS IS NOT USED now ------------ %%%%%
+%% Compute the true PE norm depending on pzero
+%if pzero > 0,
+%  Xtnorm = +d(:,pzero).^2;
+%else
+%  Xtnorm = mean(+d.^2,2) - 0.5*dme;
+%end
+%
+%% Compute the PE norm of the projected data
+%% Note that X = Q * diag(sqrt(abs(L))), so
+%% Xpnorm = diag (X*J*X') = diag(Q * diag(L) * Q')
+%Xpnorm = diag(Q * diag(L) * Q');
+%
+%% Compute the square projection error
+%% It is different from zero if ALF is not 0.99999999 or Inf
+%perr   = Xtnorm - Xpnorm;  % negative values indicate PE space
+%if sum(perr) < tol,
+%  perr = zeros(size(d,1),1);
+%end
+%%%%% ---------------------------------------------- %%%%%
+
+W = mapping(mfilename,'trained',{Wp,Wn,dme,pzero,tsig,sig,tol},[],m,sum(sig));
+W = setname(W,'Augmented PE embedding');
+return
Index: distools/bindistm.m
===================================================================
--- distools/bindistm.m	(revision 10)
+++ distools/bindistm.m	(revision 10)
@@ -0,0 +1,173 @@
+%BINDISTM Dissimilarity Matrix between Binary Vectors
+%
+%   D = BINDISTM(A,B,TYPE)
+%
+% INPUT
+%   A     NxK Binary matrix or dataset
+%   B     MxK Binary matrix or dataset (optional; default: B=A)
+%   TYPE	Type of the similarity S (optional; default: 'J'):
+%           'SM', 'Simple-match':   (a+d)/(a+b+c+d)
+%           'RR', 'Russel-Rao':     a/(a+b+c+d)
+%           'J',  'Jaccard':        a/(a+b+c)
+%           'D',  'Dice':           a/(a+0.5*(b+c))
+%           'SS', 'Sokal-Sneath':   (a+d)/(a+0.5*(b+c)+d)
+%           'RT', 'Rogers-Tanimoto':(a+d)/(a+2*(b+c)+d)
+%           'K',  'Kulczynski':     0.5*(a/(a+b) + a/(a+c))
+%           'A1', 'Anderberg1':     a/(a+2*(b+c))
+%           'A2', 'Anderberg2':     0.5*(a/(a+b) + a/(a+c) + d/(c+d) + d/(b+d))
+%           'H',  'Hamman':         ((a+d)-(b+c))/(a+b+c+d)
+%           'Y',  'Yule':           (a*d -b*c)/(a*d+b*c)
+%           'P1', 'Pearson1':       (a*d)/sqrt((a+b)*(a+c)*(b+d)*(c+d))
+%           'P2', 'Pearson2':       (a*d-b*c)/sqrt((a+b)*(a+c)*(b+d)*(c+d))
+%           'O',  'Ochiai':         a/sqrt((a+b)*(a+c))
+%         The distance D is computed as D=sqrt(1-S).
+%
+%         Type of distance:
+%           'HG', 'Hamming':        (b+c)
+%           'EU', 'Euclidean':      sqrt(b+c)
+%           'VAR','Variance':       0.25*(b+c)/(a+b+c+d)
+%           'BC', 'Bray-Curtis':    (b+c)/(2*a+b+c)
+%           'SD', 'Size-diff':      (b-c)^2/(a+b+c+d)^2
+%           'PD', 'Pattern-diff':   b*c/(a+b+c+d)^2
+%           'SHD','Shape-diff':     ((a+b+c+d)*(b_c)-(b-c)^2)/(a+b+c+d)^2;
+%
+% OUTPUT
+%   D 		NxM Dissimilarity matrix or dataset
+%
+% DESCRIPTION
+% Distance between sets of binary vectors, A and B.
+% The distances which are non-metric: 'K','A2','Y','BC','SD','PD' and 'SHD'.
+% The distances which do not have a Euclidean behaviour: 'SS','K','A2','Y','HG',
+% 'VAR','BC','SD','PD' and 'SHD'. If for the similarity S defined above, D is
+% computed as D=1-S, then the following distances are non-metric: 'D','SS','K',
+% 'A2','Y','P1','P2',and 'O', and all of the distances are non-Euclidean.
+%
+% NOTE
+% In some cases the operations may be undefined such as 0/0. This results
+% in NANs which are replaced here by zeros.
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% DEFAULT
+%   B    = A
+%   TYPE = 'J'
+%
+% REFERENCE
+% J.Gower, Metric and Euclidean Properties od Dissimilarity Coefficients.
+% Journal of Classification, no.5, 5-48, 1986.
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function D = bindistm(A,B,type)
+
+if nargin < 3,
+  type = 'J';
+end
+
+bisa = (nargin < 2 | isempty(B));
+if bisa,
+  B = A;
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a = +A;
+b = +B;
+
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+if ca ~= cb,
+  error ('Matrices should have equal numbers of columns.');
+end
+
+if any(a~=0 & a~=1) | any(b~=0 & b~=1),
+  error('Data should be binary.');
+end
+
+Aij = a*b';
+Bij = a*(1-b)';
+Cij = (1-a)*b';
+Dij = (1-a)*(1-b)';
+
+D = [];
+switch lower(type)
+  case {'hg','hamming'}
+    D = (Bij+Cij);
+  case {'eu','euclidean'}
+    D = sqrt(Bij+Cij);
+  case {'var','variance'}
+    D = 0.25*(Bij+Cij)/ca;
+  case {'bc','bray-curtis'}
+    D = (Bij+Cij)./(2*Aij+Bij+Cij);
+  case {'sd','size-diff'}
+    D = (Bij-Cij).^2./ca^2;
+  case {'pd','pattern-diff'}
+    D = Bij.*Cij./ca^2;
+  case {'shd','shape-diff'}
+    D = (ca*(Bij_Cij)-(Bij-Cij).^2)./ca^2;
+%
+  case {'sm','simple-match'}
+    S = (Aij+Dij) ./ ca;
+  case {'rr','russel-rao'}
+    S = Aij ./ ca;
+  case {'j','jaccard'}
+    S = Aij ./ (Aij+Bij+Cij);
+  case {'d','dice'}
+    S = Aij ./ (Aij+0.5*(Bij+Cij));
+  case {'ss','sokal-sneath'}
+    S = (Aij +Dij)./ (Aij + 0.5*(Bij+Cij) + Dij);
+  case {'a1','anderberg1'}
+    S = Aij./ (Aij + 2*(Bij+Cij));
+  case {'rt','rogers-tanimoto'}
+    S = (Aij +Dij)./ (Aij + 2*(Bij+Cij)+Dij);
+  case {'k','kulczynski'}
+    S = 0.5*(Aij./ (Aij + Bij) + Aij./ (Aij + Cij));
+  case {'a2','anderberg2'}
+    S = 0.5*(Aij./ (Aij + Bij) + Aij./ (Aij + Cij) + Dij./ (Cij + Dij) + Dij./ (Bij + Dij) );
+  case {'h','hamman'}
+    S = ((Aij + Dij) - (Bij + Cij))/ca;
+  case {'y','yule'}
+    S = (Aij .* Dij  - Bij .* Cij) ./ (Aij .* Dij  + Bij .* Cij);
+  case {'p1','pearson1'}
+    S = (Aij .* Dij) ./ sqrt((Aij + Bij) .* (Aij + Cij).*(Bij + Dij).*(Cij + Dij));
+  case {'p2','pearson2'}
+    S = (Aij .* Dij - Bij .* Cij) ./ sqrt((Aij + Bij) .* (Aij + Cij).*(Bij + Dij).*(Cij + Dij));
+  case {'o','ochiai'}
+    S = Aij / sqrt((Aij + Bij) .* (Aij + Cij));
+  othwerwise
+    error('Wrong type.');
+end
+
+if isempty(D),
+  D = sqrt(1 - S);
+end
+
+% Replace potential NaNs by zeros
+D(find(isnan(D))) = 0;
+
+% Check numerical inaccuracy
+D(find(D<eps)) = 0;
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/blobbox.m
===================================================================
--- distools/blobbox.m	(revision 10)
+++ distools/blobbox.m	(revision 10)
@@ -0,0 +1,75 @@
+%BLOBBOX Find box around a binary blob and resample
+%
+%   B = BLOBBOX(A,ny,nx)
+%
+% INPUT
+%   A     MY x MX x N matrix of N binary images of the size MY x MX
+%   NX,NY Resampling sizes (optional, default: 16)
+%
+% OUTPUT
+%   B     NY x NX x N matrix of N binary images of the size NY x NX
+%
+% DEFAULT
+% NX = NY = 16.
+%
+% DESCRIPTION
+% For an MY x MX x N set of N binary images A the bounding boxes around
+% the blobs are computed and resampled with NX x NY pixels.
+%
+
+% Copyright: R.P.W. Duin, r.duin@ieee.org
+% and Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function b = blobbox(a,ny,nx);
+if nargin < 2,
+  ny = 16;
+end
+if nargin < 3,
+  nx = ny;
+end
+
+[mx,my,n] = size(a);
+b = zeros(nx,ny,n);
+
+for i=1:n
+  c = a(:,:,i);
+  J = find(any(c));
+  J = [min(J):max(J)];
+  K = find(any(c'));
+  K = [min(K):max(K)];
+  c = double(c(K,J));
+  if length(c(:)) > 0,
+    c = bord(c,0);
+    b(:,:,i) = imresize(c,[ny,nx]);
+  end
+end
+
+
+
+function C = bord(A,n,m);
+% C = bord(A,n,m)
+% Puts a border of the width m (default m=1) around the image A
+% and gives it value n. If n = NaN: mirror image values.
+
+if nargin == 2;
+  m=1;
+end
+[x,y] = size(A);
+if m > min(x,y)
+  mm = min(x,y);
+  C = bord(A,n,mm);
+  C = bord(C,n,m-mm);
+  return
+end
+
+if isnan(n)
+  C = [A(:,m:-1:1),A,A(:,y:-1:y-m+1)];
+  C = [C(m:-1:1,:);C;C(x:-1:x-m+1,:)];
+else
+  bx = ones(x,m)*n;
+  by = ones(m,y+2*m)*n;
+  C = [by;[bx,A,bx];by];
+end
Index: distools/blurdistm.m
===================================================================
--- distools/blurdistm.m	(revision 10)
+++ distools/blurdistm.m	(revision 10)
@@ -0,0 +1,87 @@
+%BLURDM Blurred Euclidean distance between blobs
+%
+%   D = BLURDISTM(A,B,RA,RB)
+%
+% INPUT
+%   A     MYA x MXA x NA matrix of NA binary images of the size MYA x MXA
+%   B     MYB x MXB x NB matrix of NA binary images of the size MYB x MXB
+%   RA,RB Blurring paramters (optional, default: 1, no blurring)
+%
+% OUTPUT
+%   D     NA x NB Blurred Euclidean distance matrix
+%
+% DESCRIPTION
+% Computes the blurred Euclidean distance matrix D between sets of blobs.
+% Images are first uniformly blurred with the sizes of RA x RA or RB x RB.
+% Next they are rescaled to square images with the sizes equal to
+% max([MYA,MXA,MYB,MXB]) vy using bilinear interpolation. Finally, the
+% Euclidean distance is computed.
+%
+% Preferably use NA <= NB, as it is faster.
+
+% Copyright: R.P.W. Duin, r.duin@ieee.org
+% Ela Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function d = blurdistm(A,B,ra,rb,fid)
+if nargin < 3,
+  ra = 1;
+end
+if nargin < 4,
+  rb = ra;
+end
+if nargin < 5,
+  fid = 0;
+end
+
+[ma1,ma2,na] = size(A);
+[mb1,mb2,nb] = size(B);
+m = max([ma1,ma2,mb1,mb2]);
+d = zeros(na,nb);
+filta = exp(-[-ra:ra].^2/(0.5*ra*ra));
+filta = filta./sum(filta);
+filtb = exp(-[-rb:rb].^2/(0.5*rb*rb));
+filtb = filtb./sum(filtb);
+
+if fid > 0,
+  figure(1); clf;
+  figure(2); clf;
+end
+
+for i=1:na
+  a = A(:,:,i);
+  J = find(any(a));
+  J = [min(J):max(J)];
+  K = find(any(a'));
+  K = [min(K):max(K)];
+  a = double(a(K,J));
+
+% figure(1); imagesc(a); drawnow
+
+  a = bord(a,0,ra);
+  a = conv2(filta,filta,a,'same');
+  a = a(ra:end-ra,ra:end-ra);
+  a = imresize(a,[32 32],'bilnear');
+  if fid > 0,
+    figure(1); imagesc(a); drawnow
+  end
+  for j = 1:nb
+    b = B(:,:,j);
+    J = find(any(b));
+    J = [min(J):max(J)];
+    K = find(any(b'));
+    K = [min(K):max(K)];
+    b = double(b(K,J));
+    b = bord(b,0,rb);
+    b = conv2(filtb,filtb,b,'same');
+    b = b(rb:end-rb,rb:end-rb);
+    b = imresize(b,[32 32],'bilnear');
+    d(i,j) = sqrt(sum((a(:)-b(:)).^2));
+    if fid > 0
+      fprintf(fid,'%5d %5d %10.3f \n',i,j,d(i,j));
+      figure(2); imagesc(b); drawnow;
+    end
+  end
+end
Index: distools/chardmat.m
===================================================================
--- distools/chardmat.m	(revision 10)
+++ distools/chardmat.m	(revision 10)
@@ -0,0 +1,274 @@
+%CHARDMAT Characterization of a square, labeled dissimilarity matrix
+%
+%  [C,D_OUT] = CHARDMAT(D,Ntr,Nsubeucl)
+%
+% Characterizes a square (dis)similarity dataset D.
+% D_OUT is the symmetric, normalized dissimilarity dataset D. If D is 
+% a similarity dataset it is converted to dissimilarities first.
+% The following fields are returned in the structure C.
+% name       - dataset name as stored by PRTools or read command
+% desc       - dataset description as stored by read command
+% link       - web links as stored by read command
+% ref        - references as stored by read command
+% asym       - asymmetry, 2*|D-D'|./(|D|+|D'|)
+% size       - number of objects
+% classes    - number of classes
+% clsizes    - vector with class sizes
+% type       - 'dis' for dissimilarities, 'sim' for similarities
+%
+%         all following items are computed for a transformation
+%         of D by MAKESYM and DISNORM (make average distance 1),
+%         similarities are first transformed into dissimilarities
+%         by d(i,j) = sqrt(d(i,j) + d(j,j) - d(i,j) - d(j,i))
+%
+% within_mean- average within class dissimilarity
+% between_mean- average between class dissimilarity
+% pe_mapping - Pseudo-Euclidean mapping as computed by PE_EM
+% signature  - 2 component vector with # of positive and negative
+%              eigenvalues obtained during the PE embedding
+% eigenvalues- the eigenvalues obtained during the PE embedding, 
+%              see PE_EM for their ranking
+% nef         - Negative Eigen Fraction (sum of absolute negative
+%               eigenvalues divided by sum of all absolute eigenvalues)
+% ner         - Negative Eigen Ratio (- largest negative eigenvalue 
+%               divided by largest positive eigenvalue)
+% trineq      - fraction of triangle inequality violations
+%
+%         the following characteristics refer to a set of five spaces:
+%         - Pseudo-Euclidean space based on a full embedding. Distances
+%           in this space are identical to D.
+%         - Associated space, the same vector spaces, but now treated as
+%           an Euclidean space
+%         - Positive space based on the positive eigenvalues only
+%         - Negative space based on the negative eigenvalues only
+%         - Corrected space based on an embedding of sqrt(D.^2+2*Lmin)
+%           in which Lmin is the absolute values of the largest negative
+%           eigenvalue. The result is a proper Euclidean space.
+%
+% loo_a       - leave-one-out nearest neighbor errors for all five 
+%               embedded spaces
+% loo_d       - leave-one-out nearest neighbor errors for the dissimilarity
+%               spaces related to the above five embedded spaces
+% lcurve_a    - nearest neighbor learning curves for the five embedded
+%               spaces
+% lcurve_a    - nearest neighbor learning curves for the five dissimilarity
+%               spaces
+% anames      - names of the five embedded spaces, useful for annotation
+% dnames      - names of the five dissimilarity spaces
+%
+% Ntr (default 200) and Nsubeucl (default 50) control numbers of trials to
+% estimate the fraction of triangle violations and the accuracy of the
+% subeuclidean curves.
+
+
+function [c,d] = chardmat(d,Ntr,Nsubeucl,makefigs)
+
+	if nargin < 4, makefigs = 0; end
+	if nargin < 3 | isempty(Nsubeucl), Nsubeucl = 50; end
+	if nargin < 2 | isempty(Ntr), Ntr = 200; end
+
+  isdataset(d);
+
+  datname = getname(d);
+  discheck(d,[],1);
+  m = size(d,1);
+  nclass = getsize(d,3);
+
+  c.name = datname;
+  c.desc = getuser(d,'desc');
+  c.link = getuser(d,'link');
+  c.ref = getuser(d,'ref');
+  c.asym = asymmetry(d); 
+  c.size = m;
+  c.classes  = nclass;
+  c.clsizes  = classsizes(d);
+  
+  if discheck(d);
+    c.type = 'dis';
+  else
+    c.type = 'sim';
+		d = dissimt(d,'sim2dis');
+	end
+	
+  % we now have a dissimilarity matrix with positive distances
+  
+  d = makesym(d);  % make it symmetric now
+	d = d*disnorm(d);
+  
+  uc = zeros(1,nclass);
+  for j=1:c.classes
+		nj = c.clsizes(j);
+    dj = +selcdat(d,j);
+    uc(j) = sum(dj(:))/(nj*(nj-1));
+  end
+  c.within_mean = uc*(c.clsizes'.^2-c.clsizes')/(sum(c.clsizes.^2) - m);
+
+  ud = (m*(m-1) - uc*(c.clsizes'.^2-c.clsizes')) / (m*(m-1) - sum(c.clsizes.^2) + m);
+  c.between_mean = ud;
+
+  [nef,ner,w] = checkeucl(d);
+  c.pe_mapping  = w;
+  c.signature   = getsig(w);
+  c.eigenvalues = getdata(w,'eval');
+  c.nef      = nef;
+  c.ner      = ner;
+  c.trineq   = checktr(d,200);
+  
+  [A D] = disspaces(d,w);
+  nspaces = length(A);
+  c.loo_a = zeros(1,nspaces); % LOO NN errors embedding spaces
+  c.loo_d = zeros(1,nspaces); % LOO NN errors dis spaces
+  c.lcurve_a = cell(1,nspaces);  % NN Learning curves embedding spaces
+  c.lcurve_d = cell(1,nspaces);  % NN Learning curves dis spaces
+	c.anames = cell(1,nspaces);    % names embedded spaces
+	c.dnames = cell(1,nspaces);    % names dis spaces
+	t = sprintf('Compute %i learning curves: ',nspaces*2);
+	prwaitbar(nspaces*2,t); 
+  for j=1:nspaces   
+    c.loo_a(j) = nne(D{j});
+		ddj = distm(D{j});
+    c.loo_d(j) = nne(ddj);
+		prwaitbar(nspaces*2,j*2-1,[t int2str(j*2-1)]);
+    c.lcurve_a{j} = nnerr(D{j});
+    c.lcurve_a{j}.names = getname(A{j});
+    c.anames{j} = getname(A{j});
+		prwaitbar(nspaces*2,j*2,[t int2str(j*2)]);
+    c.lcurve_d{j} = nnerr(ddj);
+    c.lcurve_d{j}.names = getname(D{j});
+    c.dnames{j} = getname(D{j});
+	end
+	prwaitbar(0);
+
+	if makefigs
+		make_figs(d,c);
+	else
+		show_figs(c,d,Nsubeucl)
+	end
+	
+return
+
+function show_figs(c,d,Nsubeucl)
+
+	if nargin < 3 | isempty(Nsubeucl)
+		Nsubeucl = 50;
+	end
+
+  fonts = 12;
+  m = size(d,1);
+  nclass = getsize(d,3);
+  d
+  delfigs
+  
+  figure; imagesc(+d);
+  colormap gray
+  axis off;
+  axis square
+  title('Dissimilarity Matrix');
+  fontsize(fonts);
+  
+  figure; scatterd(d*c.pe_mapping(:,1:2));
+  title('Scatterplot on first two positive eigenvectors')
+  xlabel('Eigenvector 1');
+  ylabel('Eigenvector 2');
+  fontsize(fonts);
+  
+  figure; plotspectrum(c.eigenvalues); 
+  fontsize(fonts);
+	
+  figure; plote([c.lcurve_a(1:4) c.lcurve_d(1)],[],char('k-','r-','b-','m-','k--'));
+	V = axis; V(2)= m+1; axis(V);
+	ticks = [1 10 100 1000];
+	ticks = ticks(ticks <= m);
+	set(gca,'xtick',ticks);
+	set(gca,'xticklabel',ticks);
+  fontsize(fonts);
+  
+  if isfield(c,'lcurve_d')
+    figure; plote([c.lcurve_d(1:4) c.lcurve_a(1)],[],char('k--','r--','b--','m--','k-'));
+    V = axis; V(2)= m+1; axis(V);
+    ticks = [1 10 100 1000];
+    ticks = ticks(ticks <= m);
+    set(gca,'xtick',ticks);
+    set(gca,'xticklabel',ticks);
+    fontsize(fonts);
+  end
+	
+  [nef,ner,N] = checkeucl(d,'all');
+  figure;
+	semilogx(N,nef); 
+	linewidth(2); fontsize(fonts);
+	V = axis; V(2)= m+1; axis(V);
+	ticks = [1 10 100 1000];
+	ticks = ticks(ticks <= m);
+	set(gca,'xtick',ticks);
+	set(gca,'xticklabel',ticks);
+	xlabel('Subset size')
+	ylabel('Fraction')
+	title('Negative Eigen Fraction')
+	
+	figure; semilogx(N,ner);
+	linewidth(2); fontsize(fonts);
+	V = axis; V(2)= m+1; axis(V);
+	ticks = [1 10 100 1000];
+	ticks = ticks(ticks <= m);
+	set(gca,'xtick',ticks);
+	set(gca,'xticklabel',ticks);
+	xlabel('Subset size')
+	ylabel('Fraction')
+	title('Negative Eigen Ratio')
+	
+  figure;
+  nep = checksubeucl(d,Nsubeucl);
+	n = min(find(nep==1));
+	if isempty(n), n = 0; end
+	plot(nep(1:n+1));
+	linewidth(2); fontsize(fonts);
+	xlabel('Subset size')
+	ylabel('Fraction')
+	title('Fraction of Non-Euclidean Subsets')
+	
+  figure;
+  hist(+d(:),[0:0.05:ceil(max(+d(:)*20))/20]);
+  dc = zeros(sum(c.clsizes.^2),1);
+  n = 0;
+  for j=1:nclass
+    nn = c.clsizes(j)^2;
+    dj = +selcdat(d,j);
+    dc(n+1:n+nn) = dj(:);
+    n = n+nn;
+  end
+  hold on
+  hist(+dc(:),[0:0.05:ceil(max(+d(:)*20))/20]);
+  h = get(gca,'Children');
+  set(h(1),'facecolor',[1 0 0]);
+  V = axis;
+  axis([-0.1 max(+d(:)) 0 V(4)]);
+  fontsize(fonts)
+  legend('between class','within class');
+  title('Histogram of normalized distances')
+  
+  showfigs
+  
+  
+%FSAVE Save current figure as eps and fig
+%
+%    FSAVE <dir,fig_nane>
+
+function fsave(datdir,file)
+
+  file = fullfile(datdir,file);
+  uns = get(gcf,'units');
+  pos = get(gcf,'position');
+  set(gcf,'units','pixels');
+  set(gcf,'position',[1 1 900 600]);
+
+  exportfig(gcf,file,'format','eps','preview','tiff','color','cmyk')
+  %exportfig(gcf,file,'format','png','color','cmyk')
+  %exportfig(gcf,file,'format','jpeg100','color','cmyk')
+  saveas(gcf,file,'fig')
+
+  set(gcf,'units',uns);
+  set(gcf,'position',pos);
+
+return
+
Index: distools/checkeucl.m
===================================================================
--- distools/checkeucl.m	(revision 10)
+++ distools/checkeucl.m	(revision 10)
@@ -0,0 +1,110 @@
+%CHECKEUCL Check whether a square dissimilarity matrix has a Euclidean behavior
+%
+%   [NEF,NER,W] = CHECKEUCL(D)
+%   [NEF,NER]   = CHECKEUCL(D,K)
+%   [NEF,NER,K] = CHECKEUCL(D,'all')
+%
+% INPUT
+%   D     NxN dissimilarity matrix or dataset
+%   K     Vector with desired subset sizes
+%
+% OUTPUT
+%   NEF   Index of non-Euclidean behavior; negative eigen-fraction NEF in [0,1)
+%   NER   Index of non-Euclidean behavior; negative eigen-ratio NER >= 0
+%   W     Pseudo-Euclidean embedding
+%
+% DESCRIPTION
+% Computes how well the square dissimilarity matrix D can be embedded
+% in a Euclidean space.
+% NER and NEF are computed by performing the Pseudo-Euclidean embedding.
+% NEF is a ratio expressing the sum of magnitudes of all negative
+% eigenvalues divided by the sum of magnitudes of all eigenvalues. NER is
+% a ratio of the magnitude of the lowest negative eigenvalue to the largest
+% positive eigenvalue.
+%
+% D is Euclidean if D.^2 is isometrically embeddable into a Euclidean space.
+% Ideally, both NEF and NER are zero. Note that due to numerical inaccuracies
+% of the emebdding procedure, both NEF and NER might be very small, e.g.
+% in the order of ~1e-10, for perfect Euclidean distance data.
+%
+% In case a set of subset sizes K is given as many random subsets of K(i) 
+% objects are selected that are needed to estimate the expected NEF for
+% matrices of K(i)*K(i) dissimilarities with a standard deviation of 5%.
+%
+% SEE ALSO
+% PE_EM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+%
+
+function [nef, ner, W] = checkeucl(D,N)
+
+	if nargin < 2, N = []; end
+	alf = 0.05;
+	[m,k] = size(D);
+	if m ~= k
+		error('Dissimilarity matrix D should be square.')
+	end
+
+	D = dataset(D,1);  % we are not interested in labels here.
+	D = setfeatlab(D,ones(m,1));
+	
+	if isempty(N)
+		W    = pe_em(D);
+    L    = getdata(W,'eval');
+		nef  = sum(abs(L(find(L < 0))))/sum(abs(L));
+		ner  = max(abs(L(find(L < 0)))) / max(L(find(L > 0)));
+    if isempty(ner), ner = 0; end
+  else
+    if ischar(N) & strcmp(N,'all')
+      N = [3,4,5,7,10,15,20,30,50,70,100,150,200,300,500,700,1000,1500,2000,3000];
+      N = [N(N<m) m];
+    end
+    npoints = length(N);
+		nef = zeros(1,npoints);
+		ner = zeros(1,npoints);
+    if npoints > 1
+      s = sprintf('checkeucl: NEF on %i points: ',npoints);
+      prwaitbar(npoints,s);
+    end
+		for j = 1:npoints
+      if npoints > 1, prwaitbar(npoints,j,[s int2str(j)]); end
+			n = N(j);
+      if n==m
+        [nef(j) ner(j)] = feval(mfilename,D);
+      else
+        nfe = 0;
+        nre = 0;
+        nfv  = 0;
+        for i=1:5
+          [nf nr] = feval(mfilename,genddat(D,n));
+          nfe = nfe+nf;    nfee = nfe/i;
+          nre = nre+nr;    
+          nfv = nfv+nf*nf; nfvv = nfv/i;
+				end
+				if nfee == 0
+					acc = 0;
+				else
+					acc = sqrt(nfvv-nfee^2)/(sqrt(i)*nfee);
+				end
+        while acc > alf & i < 1000
+          i = i+1;
+          [nf nr] = feval(mfilename,genddat(D,n));
+          nfe = nfe+nf;    nfee = nfe/i;
+          nre = nre+nr;    
+          nfv = nfv+nf*nf; nfvv = nfv/i;
+          acc = sqrt(nfvv-nfee^2)/(sqrt(i)*nfee);
+          if nfee < 0.001, nfee = 0; acc = 0; end
+          %disp([i,round(10000*acc)])
+        end
+        nef(j) = nfee;
+        ner(j) = nre/i;
+      end
+		end
+    if npoints > 1, prwaitbar(0); end
+    W = N;
+	end
+
+return;
Index: distools/checksubeucl.m
===================================================================
--- distools/checksubeucl.m	(revision 10)
+++ distools/checksubeucl.m	(revision 10)
@@ -0,0 +1,44 @@
+%CHECKSUBEUCL Find probabilities for non-Euclidean subsets
+%
+%	NEP = CHECKSUBEUCL(D,N)
+%
+% For every size of subsets of the dissimilarity matrix D at random
+% N of such subsets are taken and checked on their Euclideaness.
+% In NEP(n) the fraction of non-Euclidean subsets is returned for
+% subsets of size n. Default N = 500.
+
+%  SEE ALSO
+%  PSEM, CHECKEUCL, CHECKTR
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function nep = checksubeucl(d,reps)
+
+if nargin < 2 | isempty(reps), reps = 500; end
+discheck(d)
+m = size(d,1);
+d = dataset(+d,1);
+d = setfeatlab(d,ones(m,1));
+
+[nef ner] = checkeucl(d);
+nep = zeros(1,m);
+if ner > 1e-6
+  s = sprintf('Check sub-euclidean probs %i trials: ',reps);
+  prwaitbar(reps,s);
+  for n=1:reps
+		prwaitbar(reps,n,[s int2str(n)]);
+    J = randperm(m);
+    for j=3:m
+      [nef ner] = checkeucl(d(J(1:j),J(1:j)));
+      if ner>1e-6
+        nep(j:end) = nep(j:end) + 1;
+        break
+      end
+    end
+  end
+  nep = nep/reps;
+	prwaitbar(0)
+end
+  
Index: distools/checktr.m
===================================================================
--- distools/checktr.m	(revision 10)
+++ distools/checktr.m	(revision 10)
@@ -0,0 +1,84 @@
+%CHECKTR Check whether Square Distance Matrix Obeys the Triangle Inequality
+%
+%   [P,C] = CHECKTR(D,N)
+%
+% INPUT
+%   D   NxN symmetric distance matrix or dataset
+%
+% OUTPUT
+%   P   Total fraction of inequalities disobeying the triangle inequality
+%   C   Constant determined such that when added to all off-diagonal
+%       values of D, makes D metric
+%
+% DESCRIPTION
+% Checks whether a symmetric distance matrix D obeys the triangle inequality.
+% If D is asymmetric, it is made symmetric by averaging. M is the total number
+% of disobeyed inequalities. Hence, for M = 0, the triangle inequality holds
+% for the distance matrix D. Additionally, a constant C is sought, which when
+% added to the off-diagonal elements of D will make D obey the triangle inequality:
+%    C = max_{i,j,k} {abs(D_{ij} + D_{ik}  - D_{jk})}
+% If C is zero, then D fulfills the condition.
+%
+% If N is given, a random NxN subset is taken to speed up and P is an
+% estimate.
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [no,c] = checktr(d,nmax)
+d = +d;
+[n,m] = size(d);
+if nargin < 2
+	nmax = n; % check all
+end
+	
+prec = 1e-12;
+if ~issym(d,prec)
+  prwarning(1,'Distance matrix should be symmetric. It is made so by averaging.')
+end
+d = 0.5*(d+d');
+d(1:n+1:end) = 0;
+
+c = 0;
+ismetric = 1;
+
+no = 0;         % Number of disobeyed triangle inequalities
+if n > nmax     % take subset to speed up.
+	R = randperm(n);
+	R = R(1:nmax);
+	d = d(R,R);
+	n = nmax;
+end
+	
+prwaitbar(n,'check triangle inequalities');
+N = 0;
+for j=1:n-1
+  prwaitbar(n,j);
+  r1 = d(:,j);
+  r2 = d(j,j+1:n);
+  % M checks the triangle ineqaulities; all elements of M are
+  % positive or zero if this holds.
+  M  = repmat(r1,1,n-j) + d(:,j+1:n) - repmat(r2,n,1);
+
+  % The elemnets of M should ideally be compared to 0. However,
+  % due to numerical inaccuracies, a small negative number should
+  % be used. Experiments indicate that -1e-13 works well.
+  % Otherwise, one gets wrong results.
+  tol = 1e-13;
+  mm  = sum(M(:) < -tol);
+
+	N = N + (n-j)*n;
+  no = no + mm;
+  ismetric = ismetric & (mm == 0);
+  if ~ismetric,
+    cc = max(max(M));
+    if cc > c,
+      c = cc;
+    end
+  end
+end
+no = no/N;
+prwaitbar(0);
+return;
Index: distools/chickenpieces.m
===================================================================
--- distools/chickenpieces.m	(revision 10)
+++ distools/chickenpieces.m	(revision 10)
@@ -0,0 +1,39 @@
+%CHICKENPIECES
+%
+%   D = CHICKENPIECES(NORM,COST,DIR)
+%
+% Reads the original, asymmetric distances
+
+function a = chickenpieces(norm,cost,dirname)
+if nargin < 3
+    dirname = ['/data/pr/projects/dissim/data/chickenpieces/chickenpieces_norm' num2str(norm) '.0'];
+		if ispc
+			dirname = ['s:\root' dirname];
+		end
+end
+if nargin < 2
+    dir(dirname)
+    a = [];
+    return
+end
+name = ['chickenpieces_norm' num2str(norm) '.0_AngleCostFunction' num2str(cost) '.0.dm'];
+a = prtbunke(fullfile(dirname,name));
+if length(a)==1 & a==-1
+    return
+end
+a = setprior(a,getprior(a,0));
+%a = (a + a')/2; 
+a = setname(a,['Chickenpieces-' int2str(norm) '-' int2str(cost)]);
+desc = ['This is one of the chickenpieces dissimilarity matrices as made available by Bunke et.al. ' ...
+  'Every entry is a weighted edit distance between two strings representing the contours of 2D blobs. ' ...
+  'Contours are approximated by vectors of length ' num2str(norm) ...
+  '. Angles between vectors are used as replacement costs. ' ...
+  'The costs for insertion and deletion are ' num2str(cost)];
+ref = ['H. Bunke, H., U. Buhler, Applications of approximate string matching to 2D shape recognition, ' ...
+  'Pattern recognition 26 (1993) 1797-1812'];
+link = {'The original dissimilarity datasets', 'http://www.iam.unibe.ch/fki/databases/string-edit-distance-matrices'; ...
+  'The original images','http://algoval.essex.ac.uk/data/sequence/chicken/'; ...
+  'The PRTools versions','http://prlab.tudelft.nl/data/disdatasets.html'};
+a = setuser(a,desc,'desc');
+a = setuser(a,ref,'ref');
+a = setuser(a,link,'link');
Index: distools/corrdistm.m
===================================================================
--- distools/corrdistm.m	(revision 10)
+++ distools/corrdistm.m	(revision 10)
@@ -0,0 +1,85 @@
+%CORRDISTM  Distance Matrix based on Correlations
+%
+%   D = CORRDISTM(A,B)
+%       OR
+%   D = CORRDISTM(A)
+%
+% INPUT
+%   A   NxK Matrix or dataset
+%   B   MxK Matrix or dataset (optional; default: B=A)
+%
+% OUTPUT
+%   D   NxM dissimilarity matrix or dataset; D in [0,1]
+%
+% DESCRIPTION
+% Computes the distance matrix D between two sets of vectors, A and B.
+% Distances between vectors X and Y are computed based on their correlation as:
+%     CORR(X,Y) = COV(X,Y) / sqrt(Var(X) * VAR(Y))
+%     D(X,Y)    = (1 - CORR)/2
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% DEFAULT
+%   B = A
+%
+% SEE ALSO
+% SIMDISTM, JACSIMDISTM, COSDISTM, LPDISTM, EUDISTM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function D = corrdistm (A,B)
+bisa = nargin < 2;
+if bisa,
+  B = A;
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a = +A;
+b = +B;
+
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+
+if ca ~= cb,
+  error ('Matrices should have equal numbers of columns.');
+end
+
+ma  = mean(a');
+a   = a - ma' * ones(1,ca);
+mb  = mean(b');
+b   = b - mb' * ones(1,cb);
+
+aa = sum(a.*a,2);
+bb = sum(b.*b,2)';
+D  = (a*b') ./ sqrt(repmat(aa,1,rb) .* repmat(bb,ra,1));
+D  = 0.5 * (1 - D);
+
+% Check numerical inaccuracy
+D (find (D < eps)) = 0;   % Make sure that distances are nonnegative
+if bisa,
+  D = 0.5*(D+D');         % Make sure that distances are symmetric for D(A,A)
+end
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/corrtr.m
===================================================================
--- distools/corrtr.m	(revision 10)
+++ distools/corrtr.m	(revision 10)
@@ -0,0 +1,49 @@
+%CORRTR Correct square distance matrix for the violation of the triangle inequality
+%
+%   DC = CORRTR(D)
+%
+% INPUT
+%   D   NxN symmetric dissimilarity matrix or dataset
+%
+% OUTPUT
+%   DC  Dissimilarity matrix/dataset with all entries corrected where the triangle inequality is violated
+%
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org, Ela Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function d = corrtr(x)
+
+d = +x;
+[n,m] = size(d);
+if n ~= m
+	error('Dissimilarity matrix should be square')
+end
+
+d = min(d,d');
+d(1:n+1:end) = 0;
+
+for j=1:n-1 % correct the upper triangle, top down
+  r1 = d(:,j);
+  r2 = d(j,j+1:n);
+  % M checks the triangle ineqaulities; all elements of M are
+  % positive or zero if this holds.
+  % M  = repmat(r1,1,n-j) - d(:,j+1:n) + repmat(r2,n,1);
+  d(:,j+1:n)  = min(repmat(r1,1,n-j) + repmat(r2,n,1), d(:,j+1:n));
+end
+d = min(d,d'); % correct the bottom triangle as well
+
+for j=n:-1:2 % correct the bottom triangle, bottom up
+  r1 = d(:,j);
+  r2 = d(j,1:j-1);
+  % M checks the triangle ineqaulities; all elements of M are
+  % positive or zero if this holds.
+  % M  = repmat(r1,1,n-j) - d(:,j+1:n) + repmat(r2,n,1);
+  d(:,1:j-1)  = min(repmat(r1,1,j-1) + repmat(r2,n,1), d(:,1:j-1));
+end
+d = min(d,d'); % correct the upper triangle as well
+
+d = setdata(x,d);
+
+return
Index: distools/cosdistm.m
===================================================================
--- distools/cosdistm.m	(revision 10)
+++ distools/cosdistm.m	(revision 10)
@@ -0,0 +1,85 @@
+%COSDISTM  Distance Matrix based on Inner Products
+%
+%   D = COSDISTM(A,B)
+%       OR
+%   D = COSDISTM(A)
+%
+% INPUT
+%   A 	NxK Matrix or dataset
+%   B   MxK Matrix or dataset (optional; default: B=A)
+%
+% OUTPUT
+%   D   NxM Dissimilarity matrix or dataset; D in [0,1]
+%
+% DESCRIPTION
+% Computes a distance matrix D between two sets of vectors, A and B.
+% Distances between vectors X and Y are derived based on their inner products
+% (and their relations to the cosinus of the angle between them) as:
+%     D(X,Y) = (1 - X'*Y/(||X||*||Y||))
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% DEFAULT
+%   B = A
+%
+% SEE ALSO
+% SIMDISTM, JACSIMDISTM, CORRDISTM, LPDISTM, EUDISTM
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function D = cosdistm (A,B)
+bisa = nargin < 2;
+if bisa,
+  B = A;
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a = +A;
+b = +B;
+
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+
+if ca ~= cb,
+  error ('Matrices should have equal numbers of columns');
+end
+
+if ~bisa,
+  ab = a * b';
+  a2 = sum(a.*a,2);
+  b2 = sum(b.*b,2)';
+  D  = ab ./ sqrt(a2(:,ones(rb,1)) .* b2(ones(ra,1),:));
+else
+  aa = a * a';
+  a2 = diag(aa);
+  a3 = diag(aa)';
+  D  = aa ./ sqrt(a2(:,ones(ra,1)) .* a3(ones(ra,1),:));
+end
+D = (1 - D);
+D(find (D < eps)) = 0;
+
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/create_long.m
===================================================================
--- distools/create_long.m	(revision 10)
+++ distools/create_long.m	(revision 10)
@@ -0,0 +1,45 @@
+%CREATE_LONG
+%
+%  Create long Contents.m in distools directory
+
+function create_long
+
+disdir = which('distools_long.m');
+disdir = fileparts(disdir);
+s = readf(fullfile(disdir,'distools_long.m'));
+s = strrep(s,'%%','% ');
+writf(fullfile(disdir,'Contents.m'),s);
+
+return
+
+%WRITF Write file
+%
+% writf(file,r)
+% Write file from string r
+
+function writf(file,r)
+fid = fopen(file,'w');
+if fid < 0
+   error('Cannot open file')
+end
+fprintf(fid,'%c',r);
+fclose(fid);
+return
+
+%READF Readfile
+%
+% [r,n] = readf(file,newline)
+% Reads file into string r. The number of lines
+% is returned in n.
+
+function [r,n] = readf(file,newline)
+if nargin < 2, newline = 13; end
+fid = fopen(deblank(file),'r');
+if fid < 0
+   error(['Cann''t open ' file])
+end
+r = fscanf(fid,'%c');
+fclose(fid);
+n = length(find(r==newline));
+if r(length(r)) ~= newline, n = n + 1; end
+return
Index: distools/create_short.m
===================================================================
--- distools/create_short.m	(revision 10)
+++ distools/create_short.m	(revision 10)
@@ -0,0 +1,75 @@
+%CREATE_SHORT
+%
+%  Create short Contents.m in distools directory
+
+function create_short
+
+disdir = which('distools_long.m');
+disdir = fileparts(disdir);
+r = readf(fullfile(disdir,'distools_long.m'));
+k = grep(r,'%%');
+s = listn(r,k);
+s = strrep(s,'%%','% ');
+writf(fullfile(disdir,'Contents.m'),s);
+
+return
+
+%WRITF Write file
+%
+% writf(file,r)
+% Write file from string r
+
+function writf(file,r)
+fid = fopen(file,'w');
+if fid < 0
+   error('Cannot open file')
+end
+fprintf(fid,'%c',r);
+fclose(fid);
+return
+
+%READF Readfile
+%
+% [r,n] = readf(file,newline)
+% Reads file into string r. The number of lines
+% is returned in n.
+
+function [r,n] = readf(file,newline)
+if nargin < 2, newline = 13; end
+fid = fopen(deblank(file),'r');
+if fid < 0
+   error(['Cann''t open ' file])
+end
+r = fscanf(fid,'%c');
+fclose(fid);
+n = length(find(r==newline));
+if r(length(r)) ~= newline, n = n + 1; end
+return
+
+%LISTN List lines specified by their line number
+%
+% t = listn(r,n)
+% Get the lines in r given by the line numbers in n.
+function t = listn(r,n)
+k = [0,find(r==newline)];
+t = [];
+for j = n
+    t = [t,r(k(j)+1:k(j+1))];
+end
+return
+
+%GREP Get line specific lines
+%
+% [k,n] = grep(r,s)
+% Get the numbers of all lines in the set of lines r 
+% that contain s.
+% n is the total number of lines.
+
+function [k,z] = grep(r,s)
+n = [0,find(r==newline)];
+m = findstr(r,s);
+[i,j] = sort([n,m]);
+q = [0,j(1:length(j)-1)]-j;
+k = j(find(q>0))-1;
+z = length(n)-1; % # of lines
+return
Index: distools/crossvald.m
===================================================================
--- distools/crossvald.m	(revision 10)
+++ distools/crossvald.m	(revision 10)
@@ -0,0 +1,252 @@
+%CROSSVALD Cross-validation error for dissimilarity representations
+% 
+%   [ERR,STD_ERR] = CROSSVALD(D,CLASSF,N,K,ITER,FID)
+%   [ERR,CERR,NLAB_OUT] = CROSSVALD(D,CLASSF,N,K,1,FID)
+%
+% INPUT
+%   A          Input dataset
+%   CLASSF     Untrained classifier to be tested.
+%   N          Number of dataset divisions (default: N==number of
+%              samples, leave-one-out)
+%   K          Desired size of the representation set (default: use all)
+%   ITER       Number of iterations
+%   FID        File descriptor for progress report file (default: 0)
+%
+% OUTPUT
+%   ERR        Average test error weighted by class priors.
+%   CERR       Unweighted test errors per class
+%   STD_ERR    Standard deviation in the error
+%   NLAB_OUT   Assigned numeric labels
+%
+% DESCRIPTION
+% Cross-validation estimation of the error and the instability of the
+% untrained classifier CLASSF using the dissimilarity dataset D. The set is 
+% randomly permutated and divided in N (almost) equally sized parts. Note that
+% for a dissimilarity matrix, the division has to be applied both to rows and
+% to columns. The classifier is trained on N-1 parts and the remaining part is 
+% used for testing. This is rotated over all parts. 
+%
+% ERR is their weighted avarage over the class priors. CERR are the class error 
+% frequencies.  D and/or CLASSF may be cell arrays of datasets and classifiers. 
+% In that case ERR is an array with errors with on position ERR(i,j) the error of 
+% the j-th classifier for the i-th dataset. In this mode, CERR and NLAB_OUT are 
+% returned in cell arrays.
+%
+% If ITER > 1 the routine is run ITER times and results are averaged. The
+% standard deviation of the error is returned in STD_ERR.
+%
+% NOTE
+% D is a square dissimilarity matrix for which the representation set has to be 
+% reduced to a K-element subset from the training set. This is done by random 
+% selection. If K is not chosen the entire training set is used. 
+% 
+% Progress is reported in file FID, default FID=0: no report.  Use FID=1
+% for report in the command window.
+% 
+% EXAMPLE
+% A = GENDATB(100);
+% D = SQRT(DISTM(A));
+% [E,S] = CROSSVALD (D, ldc([],1e-2,1e-6)*LOGDENS, 10, [], 5);
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, TESTC
+
+% Copyright: R.P.W. Duin, r.duin@ieee.org
+% and Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [err,cerr,nlabout] = crossvald(data,classf,n,kred,iter,fid)
+
+	prtrace(mfilename);
+
+	if nargin < 6, fid = []; end
+	if nargin < 5 | isempty(iter), iter = 1; end
+	if nargin < 4 | isempty(kred), kred = []; end
+	if nargin < 3, n = []; end
+    
+	if iter ~= 1
+		eer = cell(1,iter);
+    s = sprintf('crossvald, %i iterations: ',iter);
+    prwaitbar(iter,s);
+		for j = 1:iter
+      prwaitbar(iter,j,[s num2str(j)]);
+			eer{j} = feval(mfilename,data,classf,n,kred,1,fid);
+		end
+    prwaitbar(0);
+		fe = zeros(size(eer{1},1),size(eer{1},2),iter);
+		for j=1:iter
+			fe(:,:,j) = eer{j};
+		end
+		err = mean(fe,3);
+		std_err = std(fe,[],3);
+		cerr = std_err;
+		return
+	end
+	
+			
+	% datasets or classifiers are cell arrays
+	if iscell(classf) | iscell(data)
+
+		seed = rand('state');
+		if ~iscell(classf), classf = {classf}; end
+		if ~iscell(data), data = {data}; end
+		if isdataset(classf{1}) & ismapping(data{1}) % correct for old order
+			dd = data; data = classf; classf = dd;
+		end
+		numc = length(classf);
+		numd = length(data);
+		cerr = cell(numd,numc);
+		nlab_out = cell(numd,numc);
+
+		prprogress(fid,['\n%i-fold crossvalidation: ' ...
+			     '%i classifiers, %i datasets\n'],n,numc,numd);
+
+		e = zeros(numd,numc);
+    if numc > 1
+      snumc = sprintf('crossvald: %i classifiers: ',numc);
+      prwaitbar(iter,snumc);
+    end
+        
+		for jc = 1:numc
+
+      if numc > 1, prwaitbar(numc,jc,[snumc num2str(jc)]); end
+			prprogress(fid,'  %s\n',getname(classf{jc}));
+      if numd > 1
+        snumd = sprintf('crossvald: %i datasets: ',numd);
+        prwaitbar(iter,snumd);
+      end
+            
+			for jd = 1:numd
+
+        if numd > 1, prwaitbar(numd,jd,[snumd num2str(jd)]); end
+				prprogress(fid,'    %s',getname(data{jd}));
+
+				rand('state',seed);
+				[ee,cc,nn] = feval(mfilename,data{jd},classf{jc},n,kred,1,fid);
+				e(jd,jc) = ee;
+				cerr(jd,jc) = {cc};
+				nlabout(jd,jc) = {nn};
+
+			end
+      if numd > 1, prwaitbar(0); end
+			%fprintf(fid,'\n');
+
+		end
+		if nargout == 0
+			fprintf('\n  %i-fold cross validation result for',n);
+			disperror(data,classf,e);
+		else
+			err = e;
+		end
+    if numc > 1, prwaitbar(0); end
+    
+	else
+
+		if isdataset(classf) & ismapping(data) % correct for old order
+			dd = data; data = classf; classf = dd;
+		end
+   % discheck(data,[],0);
+		isdataset(data);
+		ismapping(classf); 	
+		[m,k,c] = getsize(data);
+		lab = getlab(data);
+		if isempty(n), n = m; end
+
+		if n > m
+			warning('Number of batches too large: reset to leave-one-out')
+			n = m;
+		elseif n <= 1
+			error('Wrong size for number of batches')
+		end
+		if ~isuntrained(classf)
+			error('Classifier should be untrained')
+		end
+		J = randperm(m);
+		N = classsizes(data);
+
+		% attempt to find an more equal distribution over the classes
+		if all(N > n)
+
+			K = zeros(1,m);
+
+			for i = 1:length(N)
+
+				L = findnlab(data(J,:),i);
+
+				M = mod(0:N(i)-1,n)+1;
+
+				K(L) = M;
+
+			end
+
+		else
+            
+			K = mod(1:m,n)+1;
+
+		end
+        
+		nlabout = zeros(m,1);
+		rstate2 = rand('state');
+    prprogress(fid,'%5.0f      ',n);
+    sfolds = sprintf('crossvald: %i folds: ',n);
+    prwaitbar(n,sfolds);
+		for i = 1:n
+      prwaitbar(n,i,[sfolds num2str(i)]);
+			OUT = find(K==i);
+			JOUT=J(OUT);
+			JIN = J; JIN(OUT) = [];
+			if ~isempty(kred)
+				if length(JIN) < kred
+					error('Training set too small for desired size representation set.')
+				end
+				rstate1 = rand('state');
+				rand('state',rstate2);
+				RED     = randperm(length(JIN));
+				rstate2 = rand('state');
+				rand('state',rstate1);
+				RED  = RED(1:kred);  % Here we reduce the repr. set but dont take care of an equal distribution over classes
+				JINF = JIN(RED);
+				JINR = JINF;
+			else
+				JINF = JIN;
+			end
+			if (iscell(classf.data) & length(classf.data) > 0 & isparallel(classf.data{1}))
+				m = size(data,1);
+				k = size(data,2)/m;
+				if (k ~= floor(k))
+					error('Dataset should be a concatenation of square matrices.')
+				end
+				JINF = repmat(JINF(:),1,k) + repmat([0:k-1]*m,kred,1);
+				JINF = JINF(:);
+			end
+			dlearn = data(JIN,JINF); 
+			dtest  = data(JOUT,JINF);
+			w      = dlearn*classf;   % Training
+			                          % Testing
+			[mx,nlabout(JOUT)] = max(+(dtest*w),[],2);
+             % nlabout contains class assignments according to w
+						 % needs conversion to nlabs
+			L1 = matchlablist(getlablist(data),getlabels(w));
+			[LL,L2] = sort(L1);
+			nlabout(JOUT) = L2(nlabout(JOUT));																			
+			s = sprintf('\b\b\b\b\b%5.0f',i);
+			prprogress(fid,s);
+		end
+    prwaitbar(0)
+    prprogress(fid,'\b\b\b\b\b\b\b\b\b\b\b',n);
+    %L = matchlablist(getlablist(data),getlabels(w));
+		for j=1:c
+			J = findnlab(data,j);
+			f(j) = sum(nlabout(J)~=j)/length(J);
+		end
+		e = f*getprior(data)';
+		if nargout > 0
+			err  = e;
+			cerr = f;
+		else
+			disp([num2str(n) '-fold cross validation error on ' num2str(size(data,1)) ' objects: ' num2str(e)])
+		end
+	end
+	return
Index: distools/discc.m
===================================================================
--- distools/discc.m	(revision 10)
+++ distools/discc.m	(revision 10)
@@ -0,0 +1,110 @@
+%DISCC Dissimilarity based combining classifier
+%
+%	W = discc(D,par)
+%
+% If D is a square dissimilarity matrix then the distances to each
+% representation object are used for building a classifier such that
+% sigmoid(a*d+b), can be used to estimate the posterior probability of a
+% new object at distance d. The scalar parameters a and b are optimized
+% over the training set using a maximum likelihood estimator.
+% W is a set of parallel classifiers such that D*W*classc yields the posterior
+% probabilities. Note that D*W*maxc yields the same classification results as
+% the NN classifier.
+%
+% par = 'loo' - (default) compute leave-one-out optimization for a and b.
+%               it is assumed that the first objects in the training set
+%               constitute the representation set.
+%       'all' - include all dissimilarities for optimization of k
+%               (representation set should not be included in training set)
+%
+% See also mappings, datasets, classc, classd, testd, knnd
+%
+% $Id: discc.m,v 1.2 2001/07/10 16:35:58 pavel Exp $
+
+% Copyright: R.P.W. Duin, duin@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function W = discc(d,par)
+			% set default leave-one-out
+if nargin < 2
+	par = 'loo';
+end
+			% empty call, to handle d*knnd, or d*knnd([],par)
+if nargin < 1 | isempty(d)
+	if isstr(par)	% untrained classifier, par = 'loo' or 'all'
+		W = mapping('discc',par);
+	else			% fixed classifier, par = knn
+		W = mapping('discc','fixed',par);
+	end
+	return
+end
+
+[nlab,lablist,m,k,c,p,featlist] = dataset(d);
+[clab,classlist] = renumlab(featlist);
+c = size(classlist,1);
+[cl,nc] = renumlab(classlist,lablist);
+if size(nc,1) > c
+	error('Object labels do not match representation set')
+end
+
+if isstr(par)
+	
+	% training (find parameters a and b)
+			
+	if strcmp(par,'loo')
+		n = k*(k-1) + (m-k)*k;
+		s = zeros(n,1);
+		t = zeros(n,1);
+		r = zeros(n,1);
+		K = 0;
+		for j=1:k
+			if j == 1
+				J = 2:k;
+			elseif j < k
+				J = [1:(j-1) j+1:k];
+			else
+				J = [1:k-1];
+			end
+			s(K+1:K+k-1) = d(j,J)';
+			t(K+1:K+k-1) = repmat(nlab(j),k-1,1);
+			r(K+1:K+k-1) = nlab(J);
+			K = K+k-1;
+		end
+		for j=k+1:m
+			s(K+1:K+k) = d(j,:)';
+			t(K+1:K+k) = repmat(nlab(j),k,1);
+			r(K+1:K+k) = nlab(1:k);
+			K = K+k;
+		end
+		w = +(dataset(s,2-(t==r))*loglc);
+		W = mapping('discc',w,lablist,k,c,1);
+	elseif strcmp(par,'all')
+		n = m*k;
+		s = zeros(n,1);
+		t = zeros(n,1);
+		r = zeros(n,1);
+		K = 0;	
+		for j=1:m
+			s(K+1:K+k) = d(j,:)';
+			t(K+1:K+k) = repmat(nlab(j),k,1);
+			r(K+1:K+k) = nlab(1:k);
+			K = K+k;
+		end
+		w = +(dataset(s,2-(t==r))*loglc);
+		W = mapping('discc',w,lablist,k,c,1);
+	else
+		error(['Unknown option ''' par ''''])
+	end
+	
+else
+
+	% testing for given mapping
+		
+	if isa(par,'mapping')
+		w = +par;
+		W = d*w(1) + w(2);
+	else
+		error('Second parameter should be string or mapping')
+	end
+end
Index: distools/discheck.m
===================================================================
--- distools/discheck.m	(revision 10)
+++ distools/discheck.m	(revision 10)
@@ -0,0 +1,86 @@
+%DISCHECK Dissimilarity Matrix Check
+%
+%   N = DISCHECK(D)
+%         OR
+%   N = DISCHECK(D,LABLIST,FLAG)
+%
+% INPUT
+%   D       NxN dissimilarity matrix or dataset
+%   LABLIST List of labels
+%   FLAG    0 - check square dissimilarity matrix
+%           1 - check square similarity matrix
+%
+% OUTPUT
+%   N      1/0 if D is/isnot a proper dissimilarity matrix
+%
+% DESCRIPTION
+% Returns error if 
+% 	- D is not a square dissimilarity matrix with feature labels 
+% 		equal to object labels or feature labels of D are not in LABLIST.
+% 	- FLAG==0 & there are non-zero elements on the diagonal of D
+% 	- FLAG==0 & there are negative values in D
+%
+
+% Copyright: R.P.W. Duin, r.duin@ieee.org
+% and Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+function out = discheck(D,lablist,flag)
+
+if nargin < 3, flag = 0; end
+if nargin < 2 | isempty(lablist)
+  [m,k,c]  = getsize(D);
+  lablist  = getlablist(D);
+  featlist = getfeatlab(D);
+  if m ~= k
+    if nargout == 0
+      error('Square (dis)similarity matrix D is expected.')
+    else
+      out = 0;
+      return
+    end
+  end
+else
+  featlist = getfeat(D);
+  c = size(lablist,1);
+end
+[nn,nf,fl] = renumlab(lablist,featlist);
+if max(nf) > c
+  if nargout == 0
+    error('Feature labels do not match the class labels.')
+  else
+    out = 0;
+    return
+  end
+end
+
+if any(+D < 0) & ~flag,
+  if nargout == 0
+    error('Dissimilarities should be nonnegative.')
+  else
+    out = 0;
+    return
+  end
+end
+
+dd = diag(+D);
+if any(dd ~= 0) & ~flag,
+  if max(dd) < 1e-5 & min(dd) >= 0
+     D(1:m+1:end) = 0;
+     prwarning(3,'The diagonal has small non-zero values. They are set to zero.'); 
+  else
+    if nargout == 0
+      error('The diagonal of D should be a zero vector.')
+    else
+      out = 0;
+      return
+    end
+  end
+end
+
+if nargout > 0
+  out = 1;
+end
+
+return;
Index: distools/disex_protselfd.m
===================================================================
--- distools/disex_protselfd.m	(revision 10)
+++ distools/disex_protselfd.m	(revision 10)
@@ -0,0 +1,38 @@
+%DISEX_PROTSELFD Example of forward prototype selection
+%
+% This example shows the use of PROTSELFD for a greedy forward
+% selection of prototypes from a square dissimilarity matrix in
+% order to optimize the representation set.
+%
+% The final plot shown is a 'feature curve'. This is the error
+% as a function of the number of features used (here the number
+% of prototypes). The error measure is the mean classification 
+% error of the 1-NN rule using the given dissimilarities as 
+% distances (KNNDC([],1))
+
+d = readchicken(20,45);  % read dissimilarity dataset
+w = protselfd(a);        % forward feature selection
+n = size(w,2);           % max number of selected prototypes
+                         % random prototype (feature) ranking
+v = featsel(size(d,2),randperm(n));
+
+K = [1 2 3 5 7 10 15 20 30 50 70 100 150 200 300 500 700 1000];
+K = [K(K<n) n];          % dimensionalities to be checked
+
+% In the next step the feature curve is build. Note that features
+% here are prototypes (representation objects). 
+% knndc([],1) is used for classification, i.e. use the values in d 
+% (or d*w) as distances in the 1-NN rule. 
+% Testd is used for evaluation as it is resistant against missing 
+% classes (classes not available in the representation set).
+% In 10 repititions 50% of the data is used for training and 50%
+% for testing. Note that final performances are biased as all data
+% is used in this example for prototype selection.
+
+ew = clevalf(d*w,knndc([],1),K,0.5,10,[],testd);
+ew.names = 'Forward selection';
+ev = clevalf(d*v,knndc([],1),K,0.5,10,[],testd);
+ev.names = 'Random selection';
+ev.title = getname(d);
+ev.xlabel = 'Size of Representation Set';
+plote({ew,ev})
Index: distools/dismatsel.m
===================================================================
--- distools/dismatsel.m	(revision 10)
+++ distools/dismatsel.m	(revision 10)
@@ -0,0 +1,61 @@
+%DISMATSEL Forward selection and combination of dissimilarity datasets
+%
+%		[D,L,E] = DISMATSEL(C)
+%
+% C is a cell array of labeled datasets being square dissimilarity
+% matrices. In a forward selection the best of them according to the
+% leave-one-out nearest neighbor error (NNE) are selected and summed. 
+% L contains the ranked set of indices of selected matrices. E stores the
+% error and D is the sum of the best subset.
+%
+% SEE ALSO
+% DATASETS, NNE
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function [d_final,L,E] = dismatsel(c,nmax)
+
+if ~iscell(c) | ~isdataset(c{1})
+	error('Cell array of dissimilarity matrices expected')
+end
+
+n = length(c);
+if nargin < 2, nmax = n; end
+for j=1:n
+	c{j} = abs(c{j});
+	c{j} = setfeatlab(c{j},getlabels(c{j}));
+	c{j} = c{j}*disnorm(c{j});
+end
+L = zeros(1,nmax);
+J = [1:n];
+E = zeros(1,nmax);
+d = zeros(size(c{1}));
+emin_total = 1;
+for j=1:nmax
+	emin = 1;
+	for i=J
+		e = nne(c{i}+d);
+		if e < emin
+			L(j) = i;
+			emin = e;
+		end
+	end
+	d = c{L(j)}+d;
+	if nargin < 2 % do not allow multiple choices
+		J(J==L(j)) = [];
+	end
+	E(j) = emin;
+	if emin < emin_total
+		emin_total = emin;
+		d_final = d;
+	end
+end
+
+		
+
+
+
+
+
Index: distools/disnorm.m
===================================================================
--- distools/disnorm.m	(revision 10)
+++ distools/disnorm.m	(revision 10)
@@ -0,0 +1,62 @@
+%DISNORM Normalization of a dissimilarity matrix
+%
+% 	V = disnorm(D,OPT)
+%   F = E*V
+%
+% INPUT
+%   D 	 NxN dissimilarity matrix or dataset, which sets the norm
+%   E    Matrix to be normalized
+% 	OPT  'max' : maximum dissimilarity is set to 1 by global rescaling
+% 		   'mean': average dissimilarity is set to 1 by global rescaling (default)
+%
+% OUTPUT
+%   V 	Fixed mapping
+%   F  	Normalized dissimilarity data
+%
+% DEFAULT
+%   OPT = 'mean'
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function V = disnorm(D,opt)
+if nargin < 2,
+	opt = 'mean';
+end
+
+if nargin == 0 | isempty(D)
+  V = mapping(mfilename,{opt});
+  V = setname(V,'Disnorm');
+  return
+end
+
+%DEFINE mapping
+if isstr(opt)
+	discheck(D);
+	opt = lower(opt);
+	if strcmp(opt,'mean')
+		n = size(D,1);
+		m = sum(sum(+D))/(n*(n-1));
+	elseif strcmp(opt,'max')
+		m = max(D(:));
+	else
+		error('Wrong OPT.')
+	end
+	if nargout > 1
+		D = D./m;
+	end	
+    V = mapping(mfilename,'trained',{m},[],size(D,2),size(D,2));
+	return;
+end
+
+
+% APPLY mapping
+if ismapping(opt)
+	opt = getdata(opt,1);
+	V = D./opt;
+	return;
+end			
+	
Index: distools/dispc.m
===================================================================
--- distools/dispc.m	(revision 10)
+++ distools/dispc.m	(revision 10)
@@ -0,0 +1,60 @@
+%DISPC Dissimilarity based Parzen classifier
+%
+%	W = dispc(A)
+%
+% A should be a dissimilarity based dataset with class labels as
+% feature labels.
+%
+% $Id: dispc.m,v 1.2 2001/07/10 16:35:58 pavel Exp $
+
+% Copyright: R.P.W. Duin, duin@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function w = dispc(a,v)
+
+if nargin < 1 | isempty(a) % empty call (untrained classifier)
+        w = mapping('dispc');
+		
+elseif nargin == 1    % training
+	[nlab,lablist,m,k,c,p] = dataset(a);
+	[nn,nf,fl] = renumlab(lablist,getfeat(a));
+	if c < 2
+		error('Dataset should containf more than one class')
+	end
+	if max(nf) > c
+		error('Feature labels of dataset do not match with class labels')
+	end
+	w = [];
+	for j=1:c
+		F = find(nf==j);
+		L = find(nlab==j);
+		n = ceil(sqrt(length(L)));
+		[b,r] = sort(+a(L,F));
+		for f=1:length(F)
+			h(F(f)) = b(r(n,f),F(f));
+		end	
+
+		b = {+a(find(nlab==nf(j)),j) +a(find(nlab~=nf(j)),j)};
+		w = [w; mapping('distrc',b,fl(nf(j),:),1,1,1)];
+	end
+
+%	w = cnormc(w,a); forget normalisation and apriori probs for the moment
+
+elseif nargin == 2 	% evaluation
+	[m,k] = size(a);
+	b = +v; b1 = b{1}; b2 = b{2};
+	n1 = length(b1); n2 = length(b2);
+	w1 = zeros(m,1); w2 = zeros(m,1);
+	[d R1] = sort([b1;+a]);
+	[d R2] = sort([b2;+a]);
+	L1 = find(R1>n1);
+	L2 = find(R2>n2);
+	w1(R1(L1)-n1) = (n1+2-(L1-[1:m]'))/(n1+2);
+	w2(R2(L2)-n2) = (n2+2-(L2-[1:m]'))/(n2+2);
+%	disp([w1;w2])
+	w = invsig(dataset((w1+w2)/2,getlab(a),getfeat(v)));
+else
+	error('Illegal call')
+end
+
Index: distools/disrc.m
===================================================================
--- distools/disrc.m	(revision 10)
+++ distools/disrc.m	(revision 10)
@@ -0,0 +1,66 @@
+%DISRC Dissimilarity based classifier by distance ranking
+%
+%	W = disrc(A)
+%	W = A*disrc
+%
+% A should be a dissimilarity based dataset with class labels as
+% feature labels. The classifier W is based on distance ranking.
+% A new dataset B defined by dissimilarities to the same representation
+% set A is classified by D = B*W by comparing the dissimilarities in B
+% with the ranked dissimilarities in A for each object in the
+% representation set separately. The columns in D yield for each
+% object in the representation set a distance such that D*classc
+% generates for these objects the ranked based probabilities.
+%
+% Formally W is a set of parallel mappings, so B*W*classd combines
+% them by assigning objects to the class with the highest probability.
+% Other combiners may be used as well, e.g. B*W*classc*prodc,
+% combining all probabilities by the product rule.
+%
+% See mappings, classc, classd.
+%
+% $Id: disrc.m,v 1.2 2001/07/10 16:35:58 pavel Exp $
+
+% Copyright: R.P.W. Duin, duin@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function w = disrc(a,v)
+
+if nargin < 1 | isempty(a) % empty call (untrained classifier)
+        w = mapping('disrc');
+		
+elseif nargin == 1    % training
+	[nlab,lablist,m,k,c,p] = dataset(a);
+	[nn,nf,fl] = renumlab(lablist,getfeat(a));
+	if c < 2
+		error('Dataset should containf more than one class')
+	end
+	if max(nf) > c
+		error('Feature labels of dataset do not match with class labels')
+	end
+	w = [];
+	for j = 1:k
+		b = {+a(find(nlab==nf(j)),j) +a(find(nlab~=nf(j)),j)};
+		w = [w; mapping('disrc',b,fl(nf(j),:),1,1,1)];
+	end
+
+%	w = cnormc(w,a); forget normalisation and apriori probs for the moment
+
+elseif nargin == 2 	% evaluation
+	[m,k] = size(a);
+	b = +v; b1 = b{1}; b2 = b{2};
+	n1 = length(b1); n2 = length(b2);
+	w1 = zeros(m,1); w2 = zeros(m,1);
+	[d R1] = sort([b1;+a]);
+	[d R2] = sort([b2;+a]);
+	L1 = find(R1>n1);
+	L2 = find(R2>n2);
+	w1(R1(L1)-n1) = (n1+2-(L1-[1:m]'))/(n1+2);
+	w2(R2(L2)-n2) = (n2+2-(L2-[1:m]'))/(n2+2);
+%	disp([w1;w2])
+	w = invsig(dataset((w1+w2)/2,getlab(a),getfeat(v)));
+else
+	error('Illegal call')
+end
+
Index: distools/dissimt.m
===================================================================
--- distools/dissimt.m	(revision 10)
+++ distools/dissimt.m	(revision 10)
@@ -0,0 +1,123 @@
+%DISSIMT  Fixed DISsimilarity-SIMilarity transformation
+%
+%    W = DISSIMT([],TYPE,PAR)
+%           OR
+%    T = DISSIMT(P,TYPE,PAR)
+%
+% INPUT
+%   P     NxN or NxM proximity matrix or dataset
+%   TYPE  Type of the transformation that acts on proximity data
+%         (optional; default: 'POW'):
+%         'I',    'identity':   P
+%         'SCALE', 'scale': 		P ./ PAR
+%         'NEG',  'negative':   -P
+%         'NEG2', 'negative2':  -P.^2
+%         'REV',  'reverse':    1./(PAR + P)
+%         'REV2', 'reverse':    1./(PAR^2 + P.^2)
+%         'D2S',  'S2D':        1-P
+%         'D2SSQ','S2DSQ':      sqrt(1-P)
+%         'POW',  'power':      P.^PAR
+%         'EXP',  'exponent':   exp(-P./PAR)
+%         'EXP2', 'exponent2':  exp((-P.^2)./(PAR^2))
+%         'GAUSS':              exp((-P.^2)./(2*PAR^2))
+%         'LOG',  'logarithm':  log(P/PAR)
+%         'NLOG', 'neglog':     -log((P+1)./PAR)
+%         'NLOG2','neglog2':    -log((P.^2+1)./PAR^2)
+%         'SIGM', 'sigmoid':    2./(1+exp(-P./PAR))-1
+%         'SIGM2','sigmoid2':   2./(1+exp(-(P.^2)./PAR^2))-1
+%         'SIM2DIS'
+%         'DIS2SIM'
+%   PAR   Parameter, PAR > 0 (optional; default: 1)
+%
+% OUTPUT
+%   W     Fixed mapping
+%   T     NxN or NxM proximity matrix or dataset
+%
+% DESCRIPTION
+% A fixed mapping that transforms proximity data. Note that in some cases
+% similarity is transformed into dissimilarity, or vice versa.
+% If a proximity data P is supplied, the data are directly mapped, so there
+% is no mapping defined. Hence, DISSIMT([],TYPE,PAR) is a mapping, while
+% DISSIMT(P,TYPE,PAR) returns data.
+%
+% DEFAULT
+%   PAR = 1
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function W = dissimt(D,type,p)
+if nargin < 3,
+  p = 1;
+end
+if nargin < 2,
+  type = 'pow';
+end
+if nargin == 0 | isempty(D)
+  W = mapping(mfilename,'fixed',{type,p});
+  W = setname(W,'Fixed proximity transformation');
+  return
+end
+
+if p <= 0 or p == inf,
+  error('Wrong PAR.');
+end
+
+switch lower(type)
+case {'i','identity'}
+   W = D;
+case {'scale'}
+   W = D./p;
+case {'neg','negative'}
+   W = -D;
+case {'neg2','negative2'}
+   W = -D.^2;
+case {'rev','reverse'}
+   W = 1./(p+D);
+case {'rev2','reverse2'}
+   W = 1./(p^2+D.^2);
+case {'d2s','s2d'}
+   if any(D > 1 | D < 0),
+     error('Proximity data should be in [0,1].')
+   end
+   W = 1-D;
+case {'d2ssq','s2dsq'}
+   if any(D > 1 | D < 0),
+     error('Proximity data should be in [0,1].')
+   end
+   W = sqrt(1-D);
+case {'pow','power'}
+   W = D.^p;
+case {'exp','exponent'}
+   W = exp(-D/p);
+case {'exp2','exponent2'}
+   W = exp(-D.^2/p^2);
+case {'gauss'}
+   W = exp(-D.^2/(2*p^2));
+case {'log','logarithm'}
+   W = log(D/p);
+case {'nlog','neglog'}
+   W = -log((D+1)/p);
+case {'nlog2','neglog2'}
+   W = -log((D.^2+1)/p^2);
+case {'sigm','sigmoid'}
+   W = 2./(1+exp(-D/p))-1;
+case {'sigm2','sigmoid2'}
+   W = 2./(1+exp(-D.^2/p^2))-1;
+case {'dis2sim'}
+	m = size(D,1);
+	one = ones(m,1);
+	H = eye(m) - one*one'/m;
+	W = -H*D.^2*H/2;
+case {'sim2dis'}
+	m = size(D,1);
+	DD = diag(+D);
+	DD = +(sqrt(-D-D'+repmat(DD,1,m)+repmat(DD',m,1)));
+	W = setdata(D,real(DD));
+otherwise
+   error('Transformation is unknown.');
+end
+return
Index: distools/disspaces.m
===================================================================
--- distools/disspaces.m	(revision 10)
+++ distools/disspaces.m	(revision 10)
@@ -0,0 +1,101 @@
+%DISSPACES Compute various spaces out of a dissimilarity matrix
+%
+%   [X,E,W] = DISSPACES(D,W,FLAG)
+%
+% INPUT
+%   D    Dataset, square dissimilarity matrix, size NxN
+%   W    Pseudo-Euclidean mapping, W = PE_EM(D)
+%        signature [P,Q], see PE_EM
+%   FLAG 1 normalize distances by DISNORM (default)
+%        0 do not normalize
+% 
+% OUTPUT
+%   X   Cell array of five datasets related to embedded 'spaces'
+%       - Nx(N-1) PE space
+%       - Nx(N-1) Associated space
+%       - NxP     Positive space 
+%       - NxQ     Negative space
+%       - Nx(N-1) Corrected space
+%   E   Cell array of five datasets related to dissimilarity 'spaces'.
+%       These are the NxN (Pseudo-)Euclidean dissimilarity matrices
+%       computed from the above embedded spaces
+%   W   Cell array with the mappings from D to E
+%
+% SEE ALSO
+% PE_EM
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function [X,D,W] = disspaces(d,wpe,normalize)
+
+	if nargin < 3, normalize = 1; end
+  if nargin < 2 | isempty(wpe)
+		wpe = pe_em(d);
+	end
+	
+  % Pseudo-Euclidean space
+  xpe = d*wpe;
+  xpe = setname(xpe,'PE Space');
+  dis = setname(d,'Dis Space');
+  if normalize, dis = dis*disnorm(dis); end
+  sig = getsig(wpe);
+
+  % Associated space, neglect signature
+  was = wpe*setsig;
+  xas = d*was;
+  xas = setname(xas,'Ass Space');
+  das = sqrt(distm(xas));
+  if normalize, das = das*disnorm(das); end
+  das = setname(das,'Ass Dis Space');
+  
+  % Positive space, use sig(1) features only
+  wps = wpe(:,1:sig(1))*setsig;
+  xps = d*wps;
+  xps = setname(xps,'Pos Space');
+  dps = sqrt(distm(xps));
+  if normalize, dps = dps*disnorm(dps); end
+  dps = setname(dps,'Pos Dis Space');
+  
+  % Negative space, use sig(2) features only (start at sig(1)+1)
+	if sig(2) == 0
+		xns = setdat(d,zeros(size(d,1),1));
+		dns = setdat(d,zeros(size(d,1),size(d,1)));
+	else
+		wns = wpe(:,sig(1)+1:end)*setsig;
+		xns = d*wns;
+		dns = sqrt(distm(xns));
+		if normalize, dns = dns*disnorm(dns); end
+	end
+	xns = setname(xns,'Neg Space');
+	dns = setname(dns,'Neg Dis Space');
+  
+  % Corrected space (add off-diagonal constant)
+  L = getdata(wpe,'eval');
+  m = size(d,1);
+  dcs = sqrt(d.^2+2*(-min(L))*(ones(m)-eye(m)));
+  %dcs = dcs*disnorm(dcs);
+  if normalize, dcs = dcs./meanstd(dcs); end
+  dcs = setname(dcs,'Cor Dis Space');
+  xcs = dcs*pe_em(dcs); % compute space fom dis mat
+  xcs = setname(xcs,'Cor Space');
+  if nargout > 2 % save some time
+    wcs = affine(prinv(+d)*(+xcs),[],d); % OK for original data
+	end
+  
+  X = {xpe,xas,xps,xns,xcs};
+  D = {dis,das,dps,dns,dcs};
+  if nargout > 2 % save some time
+    W = {wpe,was,wps,wns,wcs};
+	end
+	
+	
+function [u,s] = meanstd(d)
+
+  m = size(d,1);
+  d = +d;
+  d = reshape(d(1:end-1),m+1,m-1); % remove all zeros on diagonal
+  d = d(2:m+1,:);
+  u = mean(d(:));
+  s = std(d(:));
Index: distools/disstat.m
===================================================================
--- distools/disstat.m	(revision 10)
+++ distools/disstat.m	(revision 10)
@@ -0,0 +1,61 @@
+%DISSTAT Basic information (statistics) on a dissimilarity represenatation 
+%
+%   [MIN,MAX,ME,STD,SKEW] = DISSTAT(D)
+%
+% INPUT
+%   D   NxN or NxM dissimilarity matrix or dataset
+%
+% OUTPUT
+%   MIN  Vector of minimal dissimilarities per class and for the whole data   
+%   MAX  Vector of maximal dissimilarities per class and for the whole data   
+%   ME   Vector of average dissimilarities per class and for the whole data   
+%   STD  Vector of standard deviations of dissimilarities per class and for the whole data  
+%   SKEW Vector of skeweness coefficients per class and for the whole data
+%
+% DESCRIPTION
+% Basic statistics on a dissimilarity represenatation: minimum, maximum,
+% average, standard deviation and skewness are computed per class and for
+% the whole data. They are returned in vectors of the length of C+1, where C
+% is the number of classes. The last elements reflect the statistics for
+% the whole data.
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com, Robert P.W. Duin, r.duin@ieee.org
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [MIN,MAX,ME,STD,SKEW] = disstat(D)
+
+if isnumeric(D)
+    DD   = D;
+    DD   = setdiff(DD(:),0);
+    MIN  = min(DD);
+    MAX  = max(DD);          
+    ME   = mean(DD);
+    STD  = std(DD);
+    SKEW = mean(((DD-ME)/STD).^3);
+else    
+    ll  = getlab(D);
+    fll = getfeatlab(D);
+    [lab,flab,lablist] = renumlab(ll,fll);
+
+    D = +D;
+    I = find(D == 0);
+
+    for i=1:max(lab)+1
+        I = find(lab == i);
+        J = find(flab == i);
+        if i < max(lab)+1
+            DD = D(I,J);
+        else
+            DD = D;
+        end
+        DD     = setdiff(DD(:),0);
+        MIN(i,1) = min(DD);
+        MAX(i,1) = max(DD);          
+        ME(i,1)  = mean(DD);
+        STD(i,1) = std(DD);
+        SKEW(i,1)= mean(((DD-ME(i))/STD(i)).^3);
+    end
+end
+return;
Index: distools/distgraph.m
===================================================================
--- distools/distgraph.m	(revision 10)
+++ distools/distgraph.m	(revision 10)
@@ -0,0 +1,54 @@
+%DISTGRAPH Compute distances in a graph
+%
+%	D = DISTGRAPH(L,E)
+%
+% INPUT
+%   L   Nx2 array with indices of connected nodes
+%   E   Vector with N corresponding distances
+%       Default: all distances equal to 1
+%
+% OUTPUT
+%   D   Full square distance matrix
+%
+% DESCRIPTION
+% The distances between all nodes in the graph are computed by
+% adding all distances of the connecting nodes. Unconnected
+% nodes have distance INF.
+%
+% SEE ALSO
+% KMST, GRAPHPATH, PLOTGRAPH
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+
+function g = distgraph(L,e);
+
+n = size(L,1);
+if nargin < 2
+	e = ones(n,1);
+end
+R = 1e10/max(e);
+e = round(e*R);   % reduce accuracy to avoid bit ripling
+k = max(L(:));    % size of distance matrix (highest node index)
+                  % construct initial distance matrix
+g = repmat(inf,k,k);
+g(1:k+1:k*k) = zeros(1,k);
+                  % substitute given distances
+for j=1:n
+	g(L(j,1),L(j,2)) = e(j);
+end
+h = min(g,g');
+                  % take care that edges are given two-way
+L = [L; fliplr(L)];
+x = [e(:);e(:)];
+                  % loop as long as changes
+while any(h(:) ~= g(:))
+	g = h;
+	for j=1:length(x)
+		h(L(j,1),:) = min(h(L(j,1),:),h(L(j,2),:)+x(j));
+	end
+	h = min(h,h');
+o
+g = h/R;           % reset scale
Index: distools/dlpc.m
===================================================================
--- distools/dlpc.m	(revision 10)
+++ distools/dlpc.m	(revision 10)
@@ -0,0 +1,403 @@
+%DLPC LP-classifier on dissimilarity (proximity) data
+%
+%   [W1,W2,W3] = DLPC(D,BIAS,TYPE,PARAM)
+%
+% INPUT
+%   D     Dissimilarity (proximity) dataset
+%   BIAS  YES or NO (optional; default: 1 (YES))
+%   TYPE  Type of a classifier
+%         'SIMPLE'   - the most simple formulation; no sparse solution; PARAM = [];
+%         'STANDARD' - minimization of the training misclassification errors;
+%                      no sparse solution; PARAM = [];
+%         'C-SPARSE' - sparse solution; a formulation similar to the LP_1 SVM;
+%                       PARAM is a tradeoff parameter, similar as in the traditional
+%                       SVM; (optional; DEFAULT: 1).
+%         'MU-SPARSE' - sparse solution; a formulation similar to the LP_1 SVM,
+%                       based on the paper of Graepel, Herbrich, Smola etc
+%                       'Classification on proximity data with LP-machines'.
+%                       PARAM is a tradeoff parameter, usually PARAM = 0.05 or 0.1.
+%                       It is an upper bound on the misclassfied training objects.
+%                       So, for well separable problems, PARAM = 0.01 or PARAM = 0.02.
+%                       (optional; DEFAULT: the LOO 1-NN error * 1.3).
+%  PARAM Parameter connected to the TYPE, as above
+%
+% OUTPUT
+%   W1  LP-Classifier in the complete dissimilarity space
+%   W2  LP-Classifier in a reduced dissimilarity space
+%   W3  Object selection mapping; the indices of support objects are in +W3.
+%
+% DEFAULTS
+%   BIAS  = 1
+%   TYPE  = 'STANDARD'
+%   PARAM = []
+%
+% DESCRIPTION
+% Classification problem on a N x M dissimilarity dataset D with LP-machines.
+% D should be described by both label and feature lists. If D is a square,
+% symmetric matrix, then the feature list should be the same as the label list.
+%
+% Assume a 2-class problem. Let DLPC select J support objects. Then:
+% W1 is an M x 2 classifier in the original dissimilarity space, W2 is an J x 2
+% classifier in the dissimilarity space defined by the J support objects
+% and W3 is an M x R feature selection such that W1 = W3 * W2.
+% Note that the indices of the support objects can be retrieved by +W3.
+%
+% A linear classifier is built on D:
+%
+%     f(D(x,*)) = diag(Y) * D(x,*) * W + W0,
+%
+% where Y are labels (+/- 1) and W are the weights. If BIAS is 1, then W0 is also
+% sought, otherwise it equals 0, hence the hyperplane is forced to go through the origin.
+%
+% For C-class problems, C classifiers are trained, one against all others.
+% In such a case, only W1 is returned and W3 in now NOT a feature selection,
+% but directly the indices of the support objects.
+
+
+%
+% Let [n,k] = size(D). Assume a two-class problem.
+% Any multi-class problem is converted one-against-all to two-class problems.
+% Y are the labels (converted +/-1)
+% D_Y = diag(Y_r) * D * diag(Y_c),
+% where Y_r are the labels for rows of D and
+% Y_c are the labels for columns.
+% alpha is the sought solution.
+%
+% Internal - the optimization schema (A,b,f) refer to the constraints in
+% the standard Matlab LINPROG procedure.
+%
+% 'simple':
+%   min    0^T * alpha(1:k) (= 0)
+%   s.t.   [D_Y  Y]  * [alpha(1:k) alpha_0)] >= 1
+%
+%   A = [D_Y  Y]  is  n x (k+1)
+%   b = 1(n,1)
+%   f = 0(k+1,1)
+%
+%
+% 'standard':
+%   min    p^T * beta(1:n),    p = 1/n_i for the class_i
+%   s.t.   [D_Y Y] * [alpha(1:k) alpha_0] + beta(1:n) >= 1,
+%          beta >= 0
+%
+%   A = [D_Y  Y  eye(n)]
+%   b = 1(n,1)
+%   f = [0(k+1,1) p]^T
+%
+%
+% 'c-sparse':
+%   min    sum(alpha(1:k)) + sum (alpha2(1:k)) + C*sum(ksi)
+%   s.t.   [D_Y Y] * [alpha(1:k)-alpha2(1:k)  alpha_0] + ksi(1:n) >= 1,
+%          ksi >= 0
+%          alpha, alpha2 >= 0
+%
+%   A = [D_Y  -D_Y Y  eye(n,n)]
+%   b = 1(n,1)
+%   f = [0(k+1,1)]^T
+%
+%
+% 'mu-sparse':
+%   min    sum(ksi)/n - mu*g
+%   s.t.   [D_Y -D_Y Y] * [alpha(1:k)-alpha2(1:k)  alpha_0] + ksi(1:n) >= g,
+%          sum(alpha) + sum(alpha2) = 1
+%          alpha, alpha2 >= 0
+%          ksi >= 0
+%
+%   A = [D_Y  -D_Y  Y  eye(n,n)]
+%   b = 1(n,1)
+%   f = [0(2k+1,1)]
+%
+
+
+% Elzbieta Pekalska, Robert P.W. Duin, e.pekalska@tudelft.nl
+% Faculty of Electrical Engineering, Mathematics and Computer Science,
+% Delft University of Technology, The Netherlands.
+
+
+
+function [W1,W2,W3] = dlpc (d,is_w0,type,par,usematlab,prec)
+if nargin < 6, prec = 1e-7; end
+if nargin < 5, usematlab = 0; end
+if nargin < 3 | isempty(type), type =  'standard'; end
+if nargin < 4
+    par = [];
+end
+if nargin < 2 | isempty(is_w0), is_w0 = 1; end
+if nargin < 1 | isempty(d)
+  W1 = mapping(mfilename,{is_w0,type,par,usematlab});
+  W1 = setname(W1,'DLPC');
+  W2 = [];
+  W3 = [];
+  return
+end
+
+
+if ~isdataset(d),
+  error('The first parameter should be a dataset.')
+end
+if ~isnumeric(is_w0) | (is_w0 ~= 0 & is_w0 ~= 1),
+  error('The second parameter should be 0 or 1.');
+end
+
+if isempty(par),
+  switch upper(type)
+    case 'MU-SPARSE',
+      par = max(0.01,1.3*testkd(d,1,'loo')); % upperbound error: 1.3 * loo 1-nn error
+    case 'C-SPARSE',
+      par = 1;
+    case {'SIMPLE','STANDARD'},
+      par = [];
+    otherwise
+      error('Wrong type.')
+  end
+end
+
+lab      = getnlab(d);
+lablist  = getlablist(d);
+featlab  = getfeatlab(d);
+[m,k,C]  = getsize(d);
+
+[nl, fe, fl] = renumlab(lablist,featlab);
+if max(fe) > size(lablist,1)
+  error('Feature labels of the dataset do not match with class labels.')
+end
+
+
+
+z = (is_w0 > 0);  % is bias used or not?
+
+% This is the status of the optimization procedure.
+% For GLPK, this is the exit code; see GLPKMEX for details.
+% For Matlab LINPROG, if negative then no solution is found.
+
+status = 1;
+
+
+% If more than 2 classes, do one against all others.
+if C > 2,
+% W1 = mclassc(d,mapping(mfilename,{is_w0,type,par,usematlab}));
+
+  W1 = [];
+  W2 = [];
+  W3 = [];
+  N = [];
+  for i=1:C
+    mlab = 2 - (lab == i);
+    mfe  = 2 - (fe == i);
+    dd   = setlabels(d,mlab);
+    dd   = setfeatlab(dd,mfe);
+    if ~isempty(d.prior)
+      dd = setprior(dd,[d.prior(i),1-d.prior(i)]');
+    end
+    [v1,v2,v3]= dlpc(dd,is_w0,type,par,usematlab);
+    j = +v3;
+    if isempty(v1),
+      W1 = [];
+      W2 = [];
+      W3 = [];
+      prwarning(1,'No solution found.');
+      return;
+    end
+    W1 = [W1,setlabels(v1(:,1),lablist(i,:))];
+    W2 = [W2;setlabels(v2(:,1),lablist(i,:))];
+    W3(j) = ones(length(j),1);
+    N = [N j];
+  end
+  [N1,N2,N3] = unique(N);
+  W3 = featsel(k,N1);
+  %disp(size(W3,2))
+  W2 = featsel(length(N1),N3)*W2;
+  return
+
+else
+
+  Y1 = 3 - 2 * lab;   % labels     +/-1
+  Y  = 3 - 2 * fe;    % featlabels +/-1
+
+  alpha(1:k+1,1) = 0;
+
+
+  switch type
+    case 'simple',
+      f = zeros(k+z,1);
+      b = -ones(m,1);
+      if is_w0,
+        A = -[(Y1*Y').* +d  Y1];
+      else
+        A = -[(Y1*Y').* +d];
+      end
+
+%     if (exist('glpkmex')>0) & (usematlab==0)
+%       smin     = 1;  % solve minimum
+%       ctype    = char(ones(m,1)*abs('U'));    % Sign of inequalities
+%       vartype  = char(ones(k+z,1)*abs('C'));  % Continous variables
+%       lpsolver = 2;                           % Interior Point Method
+%       lpsolver = 1;                           % Revised Simlex Method
+%       params.msglev = 0; % no outputs
+%       [al,fval,status] = glpkmex(smin,f,A,b,ctype,[],[],vartype,params,lpsolver);
+%     else
+%       [al,fval,status] = linprog(f,A,b);
+%     end
+
+      [al,fval,status] = linprog(f,A,b);
+      alpha(1:k+z) = al;
+
+
+
+    case 'standard',
+      L    = ones(k,1);
+      I    = find(Y==1);
+      if ~isempty(I)
+        L(I) = L(I)/length(I);
+      end
+      J    = find(Y==-1);
+      if ~isempty(J)
+        L(J) = L(J)/length(J);
+      end
+
+      f  = [zeros(k+z,1); L];
+      lb = [-Inf .*ones(k+z,1); zeros(k,1)];
+      ub = Inf .* ones(2*k+z,1);
+      b  = -ones(m,1);
+      if is_w0,
+        A  = -[(Y1*Y').* +d  Y1  eye(m,k)];
+      else
+        A  = -[(Y1*Y').* +d  eye(m,k)];
+      end
+
+%     if (exist('glpkmex')>0) & (usematlab==0)
+%       smin     = 1;  % solve minimum
+%       ctype    = char(ones(m,1)*abs('U'));     % Sign of inequalities
+%       vartype  = char(ones(2*k+z,1)*abs('C')); % Continous variables
+%%        lpsolver = 2;                          % Interior Point Method
+%       lpsolver = 1;                            % Revised Simlex Method
+%       params.msglev = 0; % no outputs
+%       [sss,hostname] = unix('hostname');
+%       hostname = hostname(1:end-1);
+%       if strcmp(hostname,'saturnus') | strcmp(hostname,'polaris') | strcmp(hostname,'neptunus')
+%         [al,fval,status] = glpkmex_redhat(smin,f,A,b,ctype,lb,ub,vartype,params,lpsolver);
+%       else
+%         [al,fval,status] = glpkmex(smin,f,A,b,ctype,lb,ub,vartype,params,lpsolver);
+%       end
+%     else
+%       [al,fval,ststus] = linprog(f,A,b,[],[],lb,ub);
+%     end
+
+    [al,fval,ststus] = linprog(f,A,b,[],[],lb,ub);
+      alpha(1:k+z) = al(1:k+z);
+
+
+
+    case 'c-sparse',
+      L  = ones(k,1);
+      ub = Inf .* ones(3*k+z,1);
+      lb = [zeros(2*k,1); -Inf.*ones(z,1); zeros(k,1)];
+      b  = -ones(m,1);
+
+      dd = (Y1*Y').* +d;
+      if is_w0,
+        f  = [ones(2*k,1); 0; par*L];
+        A  = -[dd  -dd  Y1 eye(m,k)];
+      else
+        f  = [ones(2*k,1); par*L];
+        A  = -[dd  -dd  eye(m,k)];
+      end
+      if (exist('glpkmex')>0) & (usematlab==0)
+        smin     = 1;  % solve minimum
+        ctype    = char([ones(m,1)*abs('U')]);       % Sign of inequalities
+        vartype  = char(ones(3*k+z,1)*abs('C'))  ;   % Continuous variables
+%         lpsolver = 1;                               % Revised Simlex Method
+        lpsolver = 2;                               % Interior Point Method
+        params.msglev = 0;    % no outputs
+        params.itlim  = 400;  % iteration limit
+        [sss,hostname] = unix('hostname');
+        hostname = hostname(1:end-1);
+        if strcmp(hostname,'saturnus') | strcmp(hostname,'polaris') | strcmp(hostname,'neptunus')
+          [al,fval,status] = glpkmex_redhat(smin,f,A,b,ctype,lb,ub,vartype,params,lpsolver);
+        else
+          [al,fval,status] = glpkmex(smin,f,A,b,ctype,lb,ub,vartype,params,lpsolver);
+        end
+      else
+        [al,fval,status] = linprog (f,A,b,[],[],lb,ub);
+      end
+      alpha(1:k) = al(1:k) - al(k+1:2*k);
+      if is_w0,
+        alpha(k+1) = al(2*k+1);
+      end
+
+
+
+    case 'mu-sparse',
+      L   = ones(k,1)/k;
+      f   = [zeros(2*k+z,1); L; -par];
+      ub  = Inf .* ones(3*k+1+z,1);
+      lb  = [zeros(2*k,1); -Inf.*ones(z,1); zeros(k+1,1)];
+      Aeq = [ones(2*k,1); zeros(k+1+z,1)]';
+      beq = 1;
+      b   = zeros(m,1);
+      dd  = (Y1*Y').* +d;
+
+      if is_w0,
+        A  = -[dd  -dd  Y1  eye(m,k) -ones(m,1)];
+      else
+        A  = -[dd -dd  eye(m,k) -ones(m,1)];
+      end
+
+      if (exist('glpkmex')>0) & (usematlab==0)
+        smin     = 1;  % solve minimum
+        ctype    = char([ones(m,1)*abs('U'); 'S']);  % Sign of inequalities
+        vartype  = char(ones(3*k+1+z,1)*abs('C'));   % Continous variables
+%        lpsolver = 1;                                % Revised Simlex Method
+        lpsolver = 2;                               % Interior Point Method
+        params.msglev = 0;    % no outputs, but doesn't seem to work
+        params.itlim  = 400;  % iteration limit
+        [sss,hostname] = unix('hostname');
+        hostname = hostname(1:end-1);
+        if strcmp(hostname,'saturnus') | strcmp(hostname,'polaris') | strcmp(hostname,'neptunus')
+          [al,fval,status] = glpkmex_redhat(smin,f,[A; Aeq],[b; beq],ctype,lb,ub,vartype,params,lpsolver);
+        else
+          [al,fval,status] = glpkmex(smin,f,[A; Aeq],[b; beq],ctype,lb,ub,vartype,params,lpsolver);
+        end
+      else
+        [al,fval,status] = linprog(f,A,b,Aeq,beq,lb,ub);
+      end
+
+      alpha(1:k) = al(1:k) - al(k+1:2*k);
+      if is_w0,
+        alpha(k+1) = al(2*k+1);
+      end
+
+    otherwise
+      error ('Wrong type.');
+    end
+  end
+
+  if (status <= 0) | (status > 181 | status == 150),
+    prwarning(1,'Fisher classifier is trained.');
+    W1 = fisherc(d);
+    W2 = W1;
+    W3 = featsel(k,[1:k]);
+    return;
+  end
+
+
+  % Choose support objects
+  ss = sum(abs(alpha(1:k)));
+  J  = find(abs(alpha(1:k)) > ss*prec);
+  if ~isempty(J),
+    W3 = featsel(k,J);
+    w = [Y; 1] .* alpha(1:k+1);
+    W2 = affine(w(J),w(k+1),d(:,J),lablist,k,2);
+    W2 = cnormc(W2,d(:,J));
+    W1 = W3*W2;
+    W1 = setname(W1,'DLPC');
+    W2 = setname(W2,'DLPC');
+  else
+    prwarning(1,'No support objects found. Fisher classifier is trained.');
+    W1 = fisherc(d);
+    W2 = W1;
+    W3 = featsel(k,[1:k]);
+    return;
+  end
+  % disp(size(W3,2))
+return;
Index: distools/dmstspm.m
===================================================================
--- distools/dmstspm.m	(revision 10)
+++ distools/dmstspm.m	(revision 10)
@@ -0,0 +1,146 @@
+%DMSTSPM Find the Shortest Paths along K Minimum Spanning Trees
+%
+%   W = DMSTSPM (D,K,P)
+%
+% INPUT
+%   D   NxN Symmetric dissimilarity matrix or dataset
+%   K   Number of minimum spanning trees; (optional; default: 1)
+%   P   Object number, P = 1..N;
+%       (optional; default: P with the largest distances to all other objects)
+%
+% OUTPUT
+%   W   Mapping that determines the shortest paths
+%
+% DESCRIPTION
+% Determines the shortest paths along a neighborhood graph defined by K minimum
+% spanning trees. MSTs are found by the Prim's algorithm, starting from the
+% point P. The result, however, does not depend on P. New vertices are projected
+% on an edge of the existing neighborhood graph such that the distances
+% between a new object and the vertices of this edge are the smallest. Then,
+% the distances along the shortest paths are computed.
+%
+% DEFAULT
+% K = 1
+% P = max(dist)
+%
+% SEE ALSO
+% KMST, DSPATH, DSPATHS
+
+% Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty of EWI, Delft University of Technology, The Netherlands and 
+% School of Computer Science, University of Manchester
+
+
+
+
+function W = dmstspm(D,K,p)
+
+if nargin < 3 | isempty(p),
+  [ss,p]= max(sum(+D));
+end
+if nargin < 2 | isempty(K),
+  K = 1;
+end
+if nargin < 1 | isempty(D)
+   W = mapping(mfilename,{K,p});
+   W = setname(W,'dmstspm');
+   return
+end
+
+
+if isdataset(D) | isa(D,'double'),
+
+  if ismapping(K),
+    n_orig = getsize_in(K);
+    pars   = getdata(K);
+
+    L   = pars{1};    % list of edges in the MSTs
+    dm  = pars{2};    % weights of the edges
+    K   = pars{3};    % number of MSTs
+
+    W   = D;
+    D   = +D;
+    [m,n] = size(D);
+    if n ~= n_orig,
+      error('The number of columns in the test data does not match.')
+    end
+
+    is_porig = (m > n &  sum(diag(+D(1:n,:)))<=1e-16);
+    is_orig  = (m == n & sum(diag(+D))<=1e-16);
+
+    LL  = [L; L(:,[2 1])];
+    ddm = [dm; dm];
+    DD  = inf * ones(n_orig);
+    DD((LL(:,2)-1)*n_orig+LL(:,1)) = ddm;
+    DD(1:n_orig+1:end)=0;
+
+    if is_orig | is_porig,        % if (a part of) test data is the original distance matrix
+      Dp = dspaths(DD);
+    end
+
+    if ~is_orig,
+      if is_porig,
+        pos = n;
+        Dp  = [Dp; zeros(m-n,n)];
+      else
+        pos = 0;
+        Dp  = zeros(m,n);
+      end
+
+      dmn = zeros(m-pos,2);
+      dd  = zeros(m-pos,1);
+      Ln  = zeros(m-pos,2);
+      D = D(pos+1:m,:);
+
+      [dmin,I] = min(D,[],2);
+      LL = L(:);
+      for i=1:length(I)
+        J = find(LL == I(i));
+        [dd(i),z] = min(ddm(J));
+        Ln(i,1:2) = [I(i) LL(J(z))];
+      end
+
+      % Use the cosine law to determine the distances of the points
+      % projected onto the closest edge
+      X   = (dmin.^2 + dd.^2 - D(Ln(I,2)*(m-pos)+I).^2) ./(2*dd);
+      dmn = [X dd-X];
+      Z   = find(X < 0);  % make corrections if distances are negative
+      if ~isempty(Z)
+        dmn(Z,:) = [-X(Z) dd(Z)-X(Z)];
+      end
+      Z = find(X > dd); % make corrections if distances are too large
+      if ~isempty(Z)
+        dmn(Z,:) = [X(Z) -dd(Z)+X(Z)];
+      end
+
+      for i=1:length(I)
+        dnew = inf*ones(1,n);
+        dnew(Ln(i,:)) = dmn(i,:);
+        Q = dspaths([DD dnew'; dnew 0]);  % Floyd's algorithm is used, since it is fast in Matlab
+        Dp(pos+i,:) = Q(n+1,1:n);
+      end
+    end
+
+
+    if isdataset(W),
+      W = setdata(W,Dp);
+    else
+      W = Dp;
+    end
+    return;
+
+  else
+
+    D = +D;
+    [n,m] = size(D);
+    if n ~= m | ~issym(D,1e-12),
+      error('D should be symmetric.')
+    end
+    D = 0.5*(D+D');
+
+    [Lmst,d] = kdmst(D,K,p);
+    W = mapping(mfilename,'trained',{Lmst,d,K},[],n,n);
+    W = setname(W,'dmstspm');
+  end
+end
+return;
Index: distools/dprocrustdm.m
===================================================================
--- distools/dprocrustdm.m	(revision 10)
+++ distools/dprocrustdm.m	(revision 10)
@@ -0,0 +1,193 @@
+% DPROCRUSTDM Distance Matrix between Datasets based on Extended Procrustes Problem
+%
+%   [D,T] = DPROCRUSTDM(X,Y,SC,EXT)
+%
+% INPUT
+%   X   N x Mx or N x Mx x Kx data
+%   Y   N x My or N x My x Ky data; My <= Mx
+%   SC  Parameter (1/0) indicating whether to scale the distance to [0,1]
+%       by normalizing X and Y by their Frobenius norms (optional; default: 1)
+%   EXT Parameter (1/0) indicating extended (1) or orthogonal (0)
+%       Procrustes problem (optional; default: 1)
+%
+% OUTPUT
+%   D   Kx x Ky Distance matrix
+%   T   Kx x Ky Transformation structure
+%
+% DEFAULT
+%   SC  = 1
+%   EXT = 1
+%
+% DESCRIPTION
+% Given two 2D matrices X and Y, extended Procrustes analysis, EXT = 1, finds
+% a linear transformation based on shift, orthogonal transformation and scaling
+% of the points in Y to fit the points in X.  This is done by minimizing the sum
+% of squared differences, which is also the Frobenius norm between X and the
+% transformed Yt. Yt = alpha*Y*Q+1*beta^T, where alpha is the scaling scalar,
+% Q is the orthogonal transformation, beta is the shift vector and 1 is the
+% vector of all ones. If SC = 0, then the resulting difference is returned as
+% the dissimilarity D. So, the parameters are found in the least square sense
+% such that  min ||X - alpha*Y*Q - 1*beta^T||^2 holds.
+% Then, D = norm(X-Yt,'Frobenius').
+% If SC = 1, then the resulting distance D is scaled to [0,1] by normalizing it
+% by NORM(Xc,'Frobenius'), where Xc is X shifted to the origin.
+%
+% Orthogonal Procrustes analysis, EXT = 0, neglects alpha and beta and focuses
+% on the orthogonal transformation only. So, the above holds for Yt = Y*Q.
+%
+% X and Y should have the same number of points, as Procrustes analysis matches
+% X(i,:) to Y(i,:). If dim(Y) < dim(X), then columns of zeros are added to Y.
+% If X and Y are 3D matrices, then we consider sets of 2D matrices to be
+% compared, which results in a Kx x Ky distance matrix D.
+%
+% IMPORTANT
+% Note that D = DPROCRUST(X,X,0,1) is assymetric and D = DPROCRUST(X,X,S,EXT)
+% is symmetric, otherwise.
+%
+% T is a structure of the size Kx x Ky with the fields of alpha, beta and Q
+% if EXT = 1 and with the field of Q, if EXT = 0. For instance, T(i,j).Q is the
+% orthogonal trnasformation of Y(:,:,j) to fit Y(:,:,i).
+%
+% This routine can be used to match two results of MDS, or KPCA/PSEM for
+% an Euclidean embedding, or two shapes (described by contour points) of
+% known point correspondences.
+%
+% SEE ALSO
+% MDS, PCA, PSEM, KPCA, MAPPINGS, DATASETS
+%
+% REFERENCE
+% 1. J.C. Gower, Generalized Procrustes analysis. Psychometrika, 40, 33-51, 1975.
+% 2. I. Borg, and P. Groenen, Modern Multidimensional Scaling. Springer, New York, 1997.
+% 3. http://e-collection.ethbib.ethz.ch/ecol-pool/bericht/bericht_363.pdf
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function [D,T] = dprocrustdm(X,Y,normalize,extPA)
+
+% Let X and Y be first centered at the origin.
+% [U,S,V]=preig(X'*Y);
+%
+% For non-normalized data, the transformation is given as
+% Q     = V*U';
+% alpha = trace(X'*Y*Q) / trace(Y'*Y) = sum(diag(S)) / norm(Y,'Frobenius')^2
+% beta  = (mean(X) - alpha*mean(Y)*Q);
+
+if nargin < 3,
+  normalize = 1;
+end
+if nargin < 4,
+  extPA = 1;
+end
+
+if normalize~=0 & normalize ~=1,
+  error('SC should be either 0 or 1.');
+end
+
+if extPA~=0 & extPA~=1,
+  error('EXT should be either 0 or 1.');
+end
+
+if isdataset(X), X = +X; end
+if isdataset(Y), Y = +Y; end
+
+[nx,mx,kx] = size(X);
+[ny,my,ky] = size(Y);
+
+if ny ~= nx,
+  error('X and Y should have the same number of points.');
+end
+if my > mx,
+  error('Y cannot have more columns (dimensions) than X.');
+end
+% Add columns of zero if dim(Y) < dim(X)
+if my < mx,
+  if ky == 1,
+    Y = [Y zeros(ny,mx-my)];
+  else
+    Y(:,my+1:mx,:) = zeros(ny,mx-my,ky);
+  end
+end
+
+XX = X;
+YY = Y;
+
+% Center the data at the origin
+Xme = mean(X,1);
+Yme = mean(Y,1);
+X   = X - repmat(Xme,nx,1);
+Y   = Y - repmat(Yme,ny,1);
+
+if normalize,
+  % Compute the square Frobenius norm and scale the data
+  % For data A, norm(A,'Frob') = sqrt(trace(A'*A)) = sqrt(sum(sum(A.^2))
+  Xfn = sqrt(sum(sum(X.^2,1),2));
+  Yfn = sqrt(sum(sum(Y.^2,1),2));
+  X   = X./repmat(Xfn,nx,mx);
+  Y   = Y./repmat(Yfn,ny,my);
+  Xfn = squeeze(Xfn);
+  Yfn = squeeze(Yfn);
+else
+  Yfn2 = squeeze(sum(sum(Y.^2,1),2));
+end
+
+
+% Find the optimal transformation parameters of Yt = alpha*YY*Q+1*beta^T,
+% rotation matrix Q, scaling alpha and shift vector beta
+if normalize,
+  for i=1:kx
+    for j=1:ky
+      G  = X(:,:,i)'*Y(:,:,j);
+      [U,S,V] = svd(G);
+      Q  = V*U';
+      scY(i,j) = sum(diag(S));
+      if nargout > 1,
+        T(i,j).Q = Q;
+        if extPA,
+          T(i,j).alpha = scY(i,j) * (Xfn(i) /Yfn(j));
+          T(i,j).beta  = squeeze(Xme(:,:,i)) - T(i,j).alpha*squeeze(Yme(:,:,j)) * T(i,j).Q;
+        end
+      end
+    end
+  end
+  % Distance between X and Yt = alpha*Y*Q+1*beta^T
+  D = real(sqrt(1 - scY.^2));
+else
+  for i=1:kx
+    for j=1:ky
+      G = X(:,:,i)'*Y(:,:,j);
+      [U,S,V] = svd(G);
+      Q = V*U';
+      scY(i,j) = sum(diag(S));
+      if nargout > 1,
+        T(i,j).Q = Q;
+        if extPA,
+          T(i,j).alpha = scY(i,j) ./ Yfn2(j);
+          T(i,j).beta  = squeeze(Xme(:,:,i)) - T(i,j).alpha*squeeze(Yme(:,:,j)) * T(i,j).Q;
+          D(i,j) = norm(XX(:,:,i) -T(i,j).alpha*YY(:,:,j)*T(i,j).Q+ones(ny,1)*T(i,j).beta,'fro');
+        else
+          D(i,j) = norm(XX(:,:,i) -YY(:,:,j)*T(i,j).Q,'fro');
+        end
+      else
+        if extPA,
+          alpha  = scY(i,j) ./ Yfn2(j);
+          beta   = squeeze(Xme(:,:,i)) - alpha*squeeze(Yme(:,:,j)) * Q;
+          D(i,j) = norm(XX(:,:,i) - alpha*YY(:,:,j)*Q + ones(ny,1)*beta,'fro');
+        else
+          D(i,j) = norm(XX(:,:,i) - YY(:,:,j)*Q,'fro');
+        end
+      end
+    end
+  end
+end
+
+% Take care that distances are real and nonnegative
+D = real(D);
+D(find (D < 0)) = 0;
+if kx == ky & kx > 1 & isymm(D,1e-12),
+  D(1:kx+1:end) = 0;
+  D = 0.5*(D+D');
+end
Index: distools/drsscc.m
===================================================================
--- distools/drsscc.m	(revision 10)
+++ distools/drsscc.m	(revision 10)
@@ -0,0 +1,82 @@
+%DRSSCC Dissimilarity-based Random Subspace Combining Classifier 
+%
+% 	W = DRSSCC(D,V,N,M,CRULE)
+%
+% INPUT
+%   D 		NxK Dissimilarity dataset
+% 	V 		Base untrained classifier
+% 	N 		Desired number of representation objects per class
+% 	M 		Number of base classifiers to be generated
+% 	CRULE Combining rule
+%
+% OUTPUT
+%   W 		Trained classifier
+%
+% DESCRIPTION
+%
+% DEFAULT
+% 	V 		= NMSC
+% 	N 		= 2
+% 	M 		= 11
+% 	CRULE = VOTEC   
+%
+
+% Copyright: R.P.W. Duin, duin@ieee.org and
+% Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function W = drsscc(D,v,N,M,crule)
+
+if nargin < 5, 
+	crule = votec; 
+end
+if nargin < 4, 
+	M = 11; 
+end
+if nargin < 3, 
+	N = 2; 
+end
+if nargin < 2, 
+	v = nmsc; 
+end
+if nargin < 1 | isempty(D)
+  W = mapping('DRSSCC',{v,N,M,crule});
+  return
+end
+
+
+nlab   = getnlab(D);
+[m,k]  = size(D);
+[flab,flist] = renumlab(getfeat(D));
+c = size(flist,1);
+
+if length(N) == 1,
+	N = N*ones(c,1);
+elseif length(N) ~= c,	
+	error('N should be either a scalar or a vector with the length C.');
+else
+	;	
+end	
+
+W = [];
+for j = 1:M
+  R = genreps(flab,N);
+  W = [W D*(cmapm(k,R)*v)];
+end
+W = traincc(D,W,crule);
+
+
+
+	
+function R = genreps(nlab,N)
+% Generate n objects per class
+c = max(nlab);
+R = [];
+for j = 1:c
+  J = find(nlab==j);
+  L = randperm(length(J))';
+  R = [R; J(L(1:N(j)))];
+end
Index: distools/dspath.m
===================================================================
--- distools/dspath.m	(revision 10)
+++ distools/dspath.m	(revision 10)
@@ -0,0 +1,73 @@
+%DSPATH  Single Shortest Path in a (Dissimilarity) Graph
+%
+%   [D,P] = DSPATH (A,i,j)
+%
+% INPUT
+%   A   NxN Weight / dissimilarity matrix or dataset
+%   i,j Vertices for which the shortest path should be found
+%
+% OUTPUT
+%   D   Distance of the shortest path
+%   P   List of edges of the shortest path
+%
+% DESCRIPTION
+% Determines the shortest path between two vertices i and j. The Dijkstra's
+% algorithm is used. Currently, it is not optimized fro speed in Matlab.
+% A is a NxN matrix of weights (or a distance matrix) representing a graph
+% G(V,E). V is a set of vertices, |V| = N, and E is a set of edges. If there
+% is no edge between i and j then A(i,j) = INF. Use DSPATHS(A,'F') if all
+% shortest paths should be computed.
+%
+% SEE ALSO
+% DSPATHS
+%
+% LITERATURE
+% Any book on graph algorithms or basic algorithms in computer science.
+
+% Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty of EWI, Delft University of Technology, The Netherlands and 
+% School of Computer Science, University of Manchester
+
+
+function [d, pt] = dspath(A,s,t)
+
+A = +A;
+[n,m] = size(A);
+
+I = (1:n);
+dmin(I)  = 1e10;
+final(I) = 0;
+pred(I)  = -1;
+
+
+I(s)     = [];
+dmin(s)  = 0;
+final(s) = 1;
+last     = s;
+
+while ~final(t)
+  dminnew = dmin(last) + A(last,I);
+  Z = find(dminnew < dmin(I));
+  dmin(I(Z)) = dminnew(Z);
+  pred(I(Z)) = last;
+  [ss,last]  = min(dmin(I));
+  last = I(last);
+  final(last) = 1;
+  I = setdiff(I,last);
+end
+
+if nargout > 1,
+  if pred(t) ~= -1   % there is a path
+    k  = t;
+    pt = t;
+    while k ~= s,
+      pt = [pred(k) pt];
+      k  = pred(k);
+    end
+  else
+    pt = [];
+  end
+end
+
+d = dmin(t);
+return;
Index: distools/dspaths.m
===================================================================
--- distools/dspaths.m	(revision 10)
+++ distools/dspaths.m	(revision 10)
@@ -0,0 +1,70 @@
+%DSPATHS  All Shortest Paths in a (Dissimilarity) Graph
+%
+%   D = DSPATHS (A,ALG)
+%
+% INPUT
+%   A   NxN Weight/dissimilarity matrix or dataset
+%   ALG Algorithm used (optional; default: 'F')
+%       'F' Floyd's algorithm; fast in Matlab
+%       'D' Dijkstra's algorithm; slow in Matlab
+%
+% OUTPUT
+%   D   NxN matrix of the shortest paths
+%
+% DESCRIPTION
+% Determines all shortest paths in a (dissimilarity) graph. A is a NxN matrix
+% of weights (or a dissimilarity matrix) representing a graph G(V,E). V is
+% a set of vertices, |V| = N, and E is a set of edges. If there is no edge
+% between i and j then A(i,j) = INF. D is the matrix of the values of shortest
+% paths between all pairs of vertices. Either Floyd's or Dijkstra's algorithm
+% is used.
+%
+% DEFAULT
+% ALG = 'F'
+%
+% SEE ALSO
+% DSPATH
+%
+% LITERATURE
+% Any book on graph algorithms or basic algorithms in computer science.
+
+% Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty of EWI, Delft University of Technology, The Netherlands and 
+% School of Computer Science, University of Manchester
+
+function A = dspaths (A,alg)
+
+if nargin < 2,
+  alg = 'F';
+else
+  alg = 'D';
+end
+
+V = +A;
+[n,m] = size(V);
+if n~=m,
+  error('Weight matrix W should be square.')
+end
+
+switch upper(alg)
+  case 'F',
+    for k=1:n
+      V = min(V,repmat(V(k,:),n,1)+repmat(V(:,k),1,n));
+    end
+  case 'D',
+    VV = zeros(n,n);
+    for i=1:n
+      for j=1:n
+        VV(i,j) = dspath(V,i,j);
+      end
+    end
+    V = VV;
+otherwise
+  error('Wrong algorithm.')
+end
+
+if isdataset(A),
+  A = setdata(A,V);
+else
+  A = V;
+end
Index: distools/edgedistm.m
===================================================================
--- distools/edgedistm.m	(revision 10)
+++ distools/edgedistm.m	(revision 10)
@@ -0,0 +1,156 @@
+%EDGEDISTM  Distance Matrix between Images based on Their Edges
+%
+%   D = EDGEDISTM (A,B,DIST,K)
+%
+% INPUT
+%   A     Matrix of N binary images
+%   B     Matrix of M binary images
+%   DIST  Distance measure (optional; default: 'MHAUS')
+%         'HAUS'  - Hausdorff distance
+%         'MHAUS' - modified Hausdorff distance
+%         'R75'   - based on the 75th quantile
+%         'R90'   - based on the 90th quantile
+%   K     Number of rows in an image if images are stored as row vectors
+%         (optional; default: sqrt(size(A,1)))
+%
+% OUTPUT
+%   D     NxM dissimilarity matrix or dataset
+%
+% DESCRIPTION
+% Computes the distance matrix D between two sets of binary images, A and B.
+% First edges are extracted, then a distance defined by DIST is computed.
+% If the size of A is N x P and the size of B is M x P, then images are
+% stored as row vectors. P should be such that P = K*L, where K and L are
+% image sizes.
+%
+% If the size of A is Kx x LX x N and the size of B is KY x LY x M, then
+% images are stored as 2D arrays.
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+
+% Copyright: Robert P.W. Duin, r.p.w.duin@prtoos.org, Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function D = edgedistm (A,B,dist,k)
+
+if nargin < 3,
+  dist = 'MHAUS';
+else
+  dist = upper(dist);
+end
+
+if nargin < 2,
+  B = A;
+end
+
+switch ndims(A)
+  case 2,
+    isda = isdataset(A);
+    isdb = isdataset(B);
+    a = +A;
+    b = +B;
+    [ma, na] = size(a);
+
+    if nargin < 4,
+      k = round(sqrt(na));
+    end
+    l = round(na/k);
+
+    if (k * l) ~= na,
+      error ('Sizes of the images are incorrect.');
+    end
+
+    [mb, nb] = size(b);
+    if na ~= nb,
+      error ('Number of features should be the same.');
+    end
+
+    D = zeros(ma,mb);
+    for i=1:ma
+      for j=1:mb
+        [Ia,Ja] = find (edge (reshape (a(i,:),k,l),'canny'));
+        [Ib,Jb] = find (edge (reshape (b(j,:),k,l),'canny'));
+        D(i,j)  = edist([Ia Ja],[Ib Jb],dist);
+      end
+    end
+
+  % Set object labels and feature labels
+  if xor(isda, isdb),
+    prwarning(1,'One matrix is a dataset and the other not. ')
+  end
+  if isda,
+    if isdb,
+      D = setdata(A,D,getlab(B));
+    else
+      D = setdata(A,D);
+    end
+    D.name = 'Distance matrix';
+    if ~isempty(A.name)
+      D.name = [D.name ' for ' A.name];
+    end
+  end
+
+  case 3,
+    [ka,la,ma] = size(a);
+    [kb,lb,mb] = size(b);
+
+    D = zeros(ma,mb);
+    for i=1:ma
+      for j=1:mb
+        [Ia,Ja] = find (edge (a(:,:,i),'canny'));
+        [Ib,Jb] = find (edge (b(:,:,j),'canny'));
+        D(i,j)  = edist ([Ia Ja],[Ib Jb],dist);
+      end
+    end
+
+  otherwise
+    error('The number of matrix''s dimensions should be 2 or 3.');
+end
+
+D(find(D < eps)) = 0;
+return
+
+
+
+
+
+
+
+
+function dd = edist (aa,bb,dist)
+dab   = sqrt(distm(aa,bb));
+minab = min(dab);
+
+dba   = sqrt(distm(bb,aa));
+minba = min(dba);
+
+switch dist,
+  case 'haus',
+    dAB = max(minab);
+    dBA = max(minba);
+
+  case 'mhaus'
+    dAB = mean(minab);
+    dBA = mean(minba);
+
+  case {'r75','r90'}
+    if strcmp(dist,'r75')
+      r = 75;
+    else
+      r = 90;
+    end;
+    minab = sort(minab);
+    dAB   = minab(round (r/ma));
+    minba = sort(minba);
+    dBA   = minba(round (r/mb));
+  otherwise
+    error ('Wrong distance measure.')
+end
+
+dd = max(dBA, dAB);
+return
Index: distools/editdistm.m
===================================================================
--- distools/editdistm.m	(revision 10)
+++ distools/editdistm.m	(revision 10)
@@ -0,0 +1,136 @@
+%EDITDISTM  Edit Distance Matrix between Strings
+%
+%   D = EDITDISTM (A,B,COST,SC)
+%
+% INPUT
+%   A     Cell structure of N strings
+%   B     Cell structure of M strings (optional; default: B = A)
+%   COST  Vector of edit costs, COST = [cost_ins cost_del cost_sub]
+%         (optional; default: all cost equal 1, COST = [1 1 1])
+%   SC    Scale (1) or not (0) the computed distance to [0,1] by
+%         max {K*COST(3)+(L-K)*COST(1), K*cost(2)+L*COST(1),...
+%         L*COST(2)+K*COST(1), K*cost(3)+(L-K)*COST(2)]}, where
+%         K =length(A{i}) and L = length(B{j}) and K > L.
+%         (optional; default: 0, i.e. no scaling)
+%
+% OUTPUT
+%   D     NxM Dissimilarity matrix
+%
+% DESCRIPTION
+% A and B are either sets of cell structures of strings or strings.
+% The edit distance is defined for strings of arbitrary lengths. It finds
+% the minimum total cost of transforming one string into another, given
+% the costs of insertion, deletion and substitution.
+%
+% Dynamic programming is used to compute the edit distance. Assume we are
+% given two strings S and T of the lengths K and L, respectively. An
+% (K+1)x(L+1) array M is filled with partial costs such that M(K,L)
+% yields the edit distance D(S,T). The definition of the entries of M is
+% recursive:
+%   M(0,j) = j*C_del,  j=0,1,...,L
+%   M(i,0) = i*C_ins,  i=0,1,...,K
+% For the pairs (i,j), use
+%   M(i,j) = min {M(i-1,j)+C_del, M(i,j-1)+C_ins, M(i-1,j-1)+C_subs(S(i)~=T(j)))
+%
+% DEFAULT
+%   B    = A
+%   COST = [1 1 1]
+%   SC   = 1
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function d = editdistm(a,b,cost,scale)
+if nargin < 4,
+  scale = 0;
+end
+if nargin < 3,
+  cost = [1 1 1];
+end
+if nargin < 2,
+  b = a;
+end
+
+if length(cost) ~= 3,
+  error('Wrong vector of edit costs.');
+end
+if any(cost) < 0,
+  error('Edit costs should be nonnegative.');
+end
+
+if ~iscell(a),
+  if isstr(a) | (~isstr(a) & min(size(a)) == 1)
+    a = {a};
+  else
+    error('A is improper.');
+  end
+end
+if ~iscell(b),
+  if isstr(b) | (~isstr(b) & min(size(b)) == 1)
+    b = {b};
+  else
+    error('B is improper.');
+  end
+end
+
+
+m = length(a);
+n = length(b);
+
+d = zeros(m,n);
+if scale == 1,
+  for i=1:m
+    al = length(a{i});
+    for j=1:n
+      bl = length(b{j});
+      if bl < al, h = bl; bl = al; al = h; end
+      scale = max([al*cost(3)+(bl-al)*cost(1), al*cost(2)+bl*cost(1),...
+                   bl*cost(2)+al*cost(1), al*cost(3)+(bl-al)*cost(2)]);
+      d(i,j) = editd(a{i},b{j},cost)/scale;
+    end
+  end
+elseif scale == 0,
+  for i=1:m
+    for j=1:n
+      d(i,j) = editd(a{i},b{j},cost);
+    end
+  end
+else
+  ;
+end
+return;
+
+
+
+
+function d = editd (s,t,cost)
+m = length(s);
+n = length(t);
+
+if isstr(s),
+  s = ['a',s];
+  t = ['a',t];
+else
+  if size(s,1) > size(s,2)
+    s = [s(1); s];
+    t = [s(1); t];
+  else
+    s = [s(1) s];
+    t = [s(1) t];
+  end
+end
+
+M = zeros(m+1,n+1);
+M(1,1) = 0;
+M(1,2:n+1) = (1:n) *cost(1);    % Insertions
+M(2:m+1,1) = (1:m)'*cost(2);    % Deletions
+
+for i=2:m+1
+  for j=2:n+1
+    M(i,j) = min ([M(i-1,j)+cost(2), M(i,j-1)+cost(1), M(i-1,j-1)+cost(3)*(s(i) ~= t(j))]);
+  end
+end
+d = M(m+1,n+1);
Index: distools/eudistm.m
===================================================================
--- distools/eudistm.m	(revision 10)
+++ distools/eudistm.m	(revision 10)
@@ -0,0 +1,84 @@
+%EUDISTM Euclidean Distance Matrix 
+%
+%   D = EUDISTM(A,B)
+%       OR
+%   D = EUDISTM(A)
+%
+% INPUT
+%   A   NxK Matrix or dataset
+%   B   MxK Matrix or dataset (optional; default: B = A)
+%
+% OUTPUT
+%   D   NxM Euclidean distance dataset or matrix
+%
+% DESCRIPTION
+% Computation of the Euclidean distance matrix D between two sets of vectors
+% A and B. If A and B are datasets, then D is a dataset as well with the labels
+% defined by the labels of A and the feature labels defined by the labels of B.
+% If A is not a dataset, but a matrix of doubles then D is also a matrix of
+% doubles.
+%
+% NOTE
+% EUDISTM(A,B) is equivalent to SQRT(DISTM(A,B)).
+%
+% DEFAULT
+%   B = A
+%
+% SEE ALSO
+% DATASETS, DISTM, PROXM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function D = eudistm(A,B)
+bisa = nargin < 2;
+if bisa,
+  B = A;
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a = +A;
+b = +B;
+
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+if ca ~= cb,
+  error ('Matrices should have equal numbers of columns');
+end
+
+
+% The order of operations below is good for the accuracy.
+D = ones(ra,1)*sum(b'.*b',1);
+D = D + sum(a'.*a',1)'*ones(1,rb);
+D = D - 2 .*(+a)*(+b)';
+
+% Check for a numerical inaccuracy
+D(find(D<eps)) = 0;
+
+D = sqrt(D);
+
+% Take care of symmetric distance matrix
+if bisa & ra == rb,
+  D = 0.5*(D + D');
+  D([1:ra+1:ra^2]) = 0;
+end
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/expdistm.m
===================================================================
--- distools/expdistm.m	(revision 10)
+++ distools/expdistm.m	(revision 10)
@@ -0,0 +1,95 @@
+%EXPDISTM  Exponential-type of Distance Matrix
+%
+%     D = EXPDISTM (A,B,R)
+%       or
+%     D = EXPDISTM (A,B)
+%       or
+%     D = EXPDISTM (A,R)
+%       or
+%     D = EXPDISTM (A)
+%
+% INPUT
+%   A   NxK Matrix or dataset
+%   B   MxK Matrix or dataset (optional; default: B=A)
+%   R   Parameter to scale the Gaussian function
+%       (optional; default: sqrt(N)*(max(max(A))- min(min(A))))
+%
+% OUTPUT
+%   D   NxM Dissimilarity matrix or dataset
+%
+% DESCRIPTION
+% Computes the distance matrix D between two sets of vectors, A and B.
+% Given the vectors X and Y, distances are computed as:
+%   D(X,Y) = 1 - exp (-(X-Y)'(X-Y)/R^2)
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% SEE ALSO
+% SIMDISTM, JACSIMDISTM, COSDISTM, CORRDISTM, LPDISTM, EUDISTM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [D,r] = expdistm(A,B,r)
+[ra,ca] = size(A);
+
+bisa = 0;
+if nargin < 2,
+  bisa = 1;
+  r = (max(max(+A)) - min(min(+A)))*sqrt(ra);
+  B = A;
+  [rb,cb] = size(B);
+else
+  [rb,cb] = size(B);
+
+  if nargin < 3,
+    if max (rb,cb) == 1,
+      bisa = 1;
+      r = B;
+      B = A;
+      [rb,cb] = size(B);
+    else
+      r = (max(max(+A)) - min(min(+A)))*sqrt(ra);
+    end
+  end
+end
+
+
+if ~bisa & ca ~= cb,
+  error ('The matrices should have the same number of columns.');
+end
+
+isda = isa(A,'dataset');
+isdb = isa(B,'dataset');
+a = +A;
+b = +B;
+
+
+%d = zeros(ra,rb);
+%d = sum ((abs (repmat (permute(a,[1 3 2]), [1 rb 1]) - ...
+%               repmat (permute(b,[3 1 2]), [ra 1 1]))).^2,3);
+
+D = 1 - exp (-distm(a,b)/r^2);
+D(find(D < eps)) = 0;
+
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/fastmapd.m
===================================================================
--- distools/fastmapd.m	(revision 10)
+++ distools/fastmapd.m	(revision 10)
@@ -0,0 +1,140 @@
+%FASTMAPD Fast Linear Map of Euclidean distances
+%
+% 	W = FASTMAPD(D,K)
+%
+% INPUT
+%   D   NxN symmetric dissimilarity matrix (dataset)
+%   K   Chosen dimensionality (optional; K is automatically detected)
+%
+% OUTPUT
+%   W   Linear map of Euclidean distances D into a Euclidean space
+%
+% DEFAULT
+%   K   = []
+%
+% DESCRIPTION
+% This is an implementation of the FastMap algorithm. D is assumed to be 
+% a square Euclidean distance matrix and K is the desired dimensionality of 
+% the projection. However, if the dimensionality M of the original data is
+% smaller than K, then only a mapping to a M-dimensional space is returned.
+%
+% If D does not have a Euclidean behavior, a projection is done to the fewest
+% dimensions that explain the Euclidean part the best, i.e. do not deal with
+% negative squared distances.
+%
+% LITERATURE
+% 1. C. Faloutsos and K.-I. Lin, FastMap: A Fast Algorithm for Indexing, 
+% Data-Mining and Visualization of Traditional and Multimedia Datasets, 
+% ACM SIGMOD, International Conference on Management of Data, 163-174, 1995.
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [W,P] = fastmapd(D,K)
+
+if nargin < 2, 
+	K = []; 
+end
+if nargin < 1 | isempty(D)
+   W = mapping(mfilename,K); 
+   W = setname(W,'Fastmapd');
+   return
+end
+
+
+if (isdataset(D) | isa(D,'double')) 
+  if ismapping(K),
+    % APPLY THE MAPPING
+    pars = getdata(K);
+    P    = pars{1};
+    dd   = pars{2}; 
+    X    = pars{3}; 
+    K    = pars{4}; 
+
+		nlab = getnlab(D);
+		n    = size(D,1);
+    D    = +D.^2;
+    if all(diag(D) == 0) & issym(D) & length(X) == n,
+      Y = X;
+    else
+      for k=1:K
+        Y(:,k) = (D(:,P(k,1)) + dd(k)*ones(n,1) - D(:,P(k,2)))./(2*sqrt(dd(k)));
+        D      = (D - distm(Y(:,k),X(:,k)));
+      end
+		end		
+    W = dataset(Y,nlab);
+    return
+  end
+end
+
+
+
+
+
+% TRAIN THE MAPPING
+if isdataset(D) 
+	nlab = getnlab(D);
+end
+discheck(D);
+
+n = size(D,1);
+D = +D.^2;
+if isempty(K), 
+	K = n-1; 
+end
+
+k      = 0;     % Current dimensionality
+Z      = 1:n; 	% Index of points
+tol    = 1e-12; % Tolerance when the distances become close to zero 
+tolNE  = 1e-10; % Tolerance for the non-Euclidean behavior
+NEucl  = 0; 		% Non-Euclidean behavior
+finito = 0;
+
+while ~finito,
+  k = k+1;
+  [mm,O] = max((D(Z,Z)),[],2);
+  [mm,i] = max(mm);
+ 	P(k,1) = Z(O(i));		% P is the index of pivots
+  P(k,2) = Z(i);
+  Z([O(i) i]) = [];
+	dd(k)  = D(P(k,1),P(k,2));
+
+  if dd(k) >= tol,
+    X(:,k) = (D(:,P(k,1)) + dd(k)*ones(n,1) - D(:,P(k,2)))./(2*sqrt(dd(k)));
+    D      = (D - distm(X(:,k)));    
+	else
+		P(k,:) = [];
+	end
+
+	if ~NEucl,
+		NEucl = NEucl | any(D(:) < -tolNE);
+		if NEucl,
+			KKe = k;
+			KK  = k;
+		end 
+	end
+
+  finito = (k >= K) | (dd(k) <= tol) | NEucl; 
+end
+if ~NEucl,
+	KK = k;
+end
+
+if NEucl,
+  disp('Distances do not have a Euclidean behavior!');
+	disp(['The Euclidean part of the distances is explained in ' num2str(KKe) 'D.']);
+else
+	if KK < K, 
+  	disp(['The distances are perfectly explained in ' num2str(KK) 'D.']);
+	end
+end
+
+W = mapping(mfilename,'trained',{P,dd,X,KK},[],n,KK);
+W = setname(W,'Fastmapd');
+return
+
+
+
Index: distools/flpdistm.m
===================================================================
--- distools/flpdistm.m	(revision 10)
+++ distools/flpdistm.m	(revision 10)
@@ -0,0 +1,117 @@
+%FLPDISTM  lp (p > 0) (Non)-Metric Distance Matrix
+%
+%     D = FLPDISTM (A,B,P)
+%       OR
+%     D = FLPDISTM (A,B)
+%       OR
+%     D = FLPDISTM (A,P)
+%       OR
+%     D = FLPDISTM (A)
+%
+% INPUT
+%   A   NxK Matrix or dataset
+%   B   MxK Matrix or dataset
+%   P   Parameter; P > 0
+%
+% OUTPUT
+%   D   NxM Dissimilarity matrix or dataset
+%
+% DEFAULT
+%   P = 1
+%   B = A
+%
+% DESCRIPTION
+% Fast computation of the distance matrix D between two sets of vectors, A and B.
+% This can ONLY be used for small sets A and B as the memory is significantly used
+% by computing 3D matrices of the size M x N x K.
+% Distances between vectors X and Y are computed using the lp distance:
+%     d(X,Y) = (sum (|X_i - Y_i|.^P))^(1/P)
+%                i
+% If P = Inf, then the max norm distance is computed:
+%     d(X,Y) = max (|X_i - Y_i|)
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% DEFAULT
+%   P = 1
+%   B = A
+%
+% REMARKS
+%   P >= 1      => D is metric
+%   P in (0,1)  => D is non-metric; D.^P is metric and l1-embeddable
+%   P = 1/2     => D is city block / Euclidean distance
+%
+% SEE ALSO
+%   LPDISTM, EUDISTM
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function D = flpdistm (A,B,p)
+bisa = 0;
+if nargin < 2,
+  p = 1;
+  B = A;
+  bisa = 1;
+else
+  if nargin < 3,
+    if max (size(B)) == 1,
+      p = B;
+      bisa = 1;
+      B = A;
+    else
+      p = 1;
+    end
+  end
+end
+
+if p <= 0,
+  error ('The parameter p must be positive.');
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a    = +A;
+b    = +B;
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+
+if ca ~= cb,
+  error ('The matrices should have the same number of columns.');
+end
+
+D = zeros(ra,rb);
+if p < Inf,
+  D = sum ((abs (repmat(permute(a,[1 3 2]), [1 rb 1]) - ...
+                 repmat(permute(b,[3 1 2]), [ra 1 1]))).^p,3).^(1/p);
+else
+  D = max ((abs (repmat(permute(a,[1 3 2]), [1 rb 1]) - ...
+                 repmat(permute(b,[3 1 2]), [ra 1 1]))),[],3);
+end
+
+
+% Check numerical inaccuracy
+D (find (D < eps)) = 0;   % Make sure that distances are nonnegative
+if bisa,
+  D = 0.5*(D+D');         % Make sure that distances are symmetric for D(A,A)
+end
+
+
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. The result is a matrix.')
+elseif isda & isdb,
+  D = setdata(A,D,getlab(B));
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+else
+  ;
+end
+return
Index: distools/fontsize.m
===================================================================
--- distools/fontsize.m	(revision 10)
+++ distools/fontsize.m	(revision 10)
@@ -0,0 +1,37 @@
+%FONT_SIZE Set large graphic font
+%
+%       font_size(size)
+%
+% Set font size for current figure
+
+function font_size(size)
+
+  V = axis;
+  H = get(gcf,'Children');
+	c1 = [];
+	for h = H'
+	if strcmp(get(h,'type'),'axes')
+  	set(get(h,'XLabel'), 'FontSize', size);
+  	set(get(h,'YLabel'), 'FontSize', size);
+  	set(get(h,'Title'),  'FontSize', size);
+  	set(h, 'FontSize', size);
+  	c1 = [c1; get(gca, 'Children')];
+	end
+	end
+ 	axis(V);
+  for h1 = c1'
+    v1 = get (h1);
+    if (isfield (v1, 'FontSize'))
+      set (h1, 'FontSize', size);
+    end;
+    c2 = get (h1, 'Children');
+    for h2 = c2'
+      v2 = get (h2);
+      if (isfield (v2, 'FontSize'))
+        set (h2, 'FontSize', size);
+      end;
+    end;
+  end;
+
+return
+
Index: distools/genballd.m
===================================================================
--- distools/genballd.m	(revision 10)
+++ distools/genballd.m	(revision 10)
@@ -0,0 +1,69 @@
+%GENBALLD Generate ball distance matrix
+%
+%   D = GENBALLD(N,K,E)
+%
+%  N 1xC vector with number of objects per class
+%  K Dimensionality
+%  E 1xC with ball sizes, default: class number/100
+%
+% This routine generates C classes of balls in a K-dimensional hypercube 
+% with edges of length 1. The radii for class n is given in E(n). Balls do
+% not intersect. The distances between the ball surfaces are returned in D.
+
+function d = genballd(n,k,e)
+
+c = length(n); % number of classes
+if nargin < 2, k = 1; end
+if nargin < 3, e = [1:c]/100; end
+m = sum(n); 
+
+x = 100*rand(m,k); % to avoid numerical inaccurcies
+r = [];
+for j=1:c
+    r = [r; e(j).*ones(n(j),1)];
+end
+%r = r*100;
+
+d = sqrt(distm(x)) - repmat(r,1,m) - repmat(r',m,1); 
+d = d - diag(diag(d));
+attempts = 0;
+while(any(d(:)<0))
+for j=2:m
+    while any(d(j,:) < 0)
+				attempts = attempts + 1;
+				if attempts > 50*m
+					error('No solution found, shrink ball sizes or number of balls, or enlarge dimensionality')
+				end
+        x(j,:) = 100*rand(1,k);
+        d(j,:) = sqrt(distm(x(j,:),x)) - repmat(r(j),1,m) - repmat(r',1,1);
+        d(:,j) = d(j,:)';
+        d(j,j) = 0;
+    end
+end
+
+end         
+
+labs = genlab(n);
+d = dataset(d,labs);
+d = setfeatlab(d,labs);
+d = setprior(d,0);
+desc = ['This dataset has been generated by the DisTools command GENBALLD(['...
+    num2str(classsizes(d)) '], ' int2str(k) ', [' num2str(e) ']) which generates the' ...
+    ' given numbers of ' int2str(k) '-D balls with sizes [' num2str(e) '] in a' ...
+      int2str(k) '-D hypercube. Balls do not overlap. Dissimilarities are computed as the' ...
+    ' shortest distance between two points on the surface of two balls.' ...
+    ' The intention is to study strong examples in which non-Euclidean dissimilarities are informative.'];
+ref = {['E. Pekalska, A. Harol, R.P.W. Duin, D. Spillman, and H. Bunke, Non-Euclidean'...
+     ' or non-metric measures can be informative, in: D.-Y. Yeung et al., Proc. SSSPR2006'... 
+     ' Lecture Notes in Comp. Sc., vol. 4109, Springer, Berlin, 2006, 871-880.'], ...
+      ['R.P.W. Duin, E. Pekalska, A. Harol, W.J. Lee, and H. Bunke, On Euclidean'...
+     ' corrections for non-Euclidean dissimilarities, in: N. da Vitoria Lobo et al.,'...
+     ' Proc. SSSPR2008, Lecture Notes in Comp.Sc., vol. 5342, Springer, Berlin, 2008, 551-561.'], ...
+     ['J. Laub, V. Roth, J.M. Buhmann, K.R. Mueller, On the information'...
+     ' and representation of non-euclidean pairwise data, Pattern Recognition, vol. 39, 2006, 1815-1826.']};
+link = {'The PRTools version of the data:','http://prtools.org/files/CoilYork.zip'; ...
+    'The DisTools package which contains the routine','http://prtools.org/files/DisTools.zip'};
+d = setname(d,'Ball Dissimilarities');
+d = setuser(d,desc,'desc');
+d = setuser(d,ref,'ref');
+d = setuser(d,link,'link');
Index: distools/genddat.m
===================================================================
--- distools/genddat.m	(revision 10)
+++ distools/genddat.m	(revision 10)
@@ -0,0 +1,109 @@
+%GENDDAT Generate random training and test sets for dissimilarity data
+%
+% 	[DTR,DTE,I,J] = GENDDAT(D,M,K)
+%
+% INPUT
+% 	D 	NxN dissimilarity dataset
+% 	M 	Cx1 vector of class sizes or frequencies, or a single number / frequency in(0,1)
+% 	K 	Cx1 vector of class sizes or frequencies, or a single number / frequency in(0,1)
+% 			(optional, default: K = M)
+%
+% OUTPUT
+%   DTR Training dissimilarity dataset
+%   DTE Test dissimilarity dataset
+% 	I 	Indices of the training objects
+% 	J 	Indices of the test objects
+%
+% DESCRIPTION
+% Generates random training and test sets from a square dissimilarity dataset D.
+% Feature labels and object labels of D should be equal. Note that M and K can be 
+% either scalars or vectors with as many components as classes (=C), defining 
+% specific sizes/fractions per class.
+%
+% Per default, all training are used as a represenation set (M=K). If M is Cx1 vector, 
+% then GENDDAT selects at random M(i) vectors out of the i-th class in D and stores them 
+% in the dataset DTR of the size [sum(M)]x[sum(M)]. The remaining  objects are stored in 
+% [N-sum(M)]x[sum(M)] dissimilarity data DTE. Classes are ordered by using RENUMLAB(GETLAB(D)). 
+% If M is a scalar, then M objects in total (given by number or frequency) are selected 
+% at random according to the class priors. I and J are the indices of the training 
+% and testing objects, respectively.
+%
+% If K is provided, then the first K(i) training objects per i-the class are used 
+% for the representation set. Note that K(i) can be a frequency.
+% 
+% DEFAULT
+% 	K = M
+% 
+% EXAMPLE
+% Let D be 100 x 100 dataset with two classes [40 60] and class priors [0.4 0.6].
+% 1)	[DTR,DTE] = GENDDAT(D,0.6) 
+% DTR is 60x60 and DTE is 40x60. 60% of objects of the first class (24 in total) 
+% and 40% of the objects of the second class (36 in total) are selected for DTR.
+%
+% 2) [DTR,DTE] = GENDDAT(D,0.6,0.1) 
+% DTR is 60x6 and DTE is 40x6. 60% of objects of the first class (24 in total) 
+% and 40% of the objects of the second class (36 in total) are selected for training.
+% From that, 10% of the first training objects per class are selected for the 
+% represenatation set. 10% from 24 rounds to 2 objects for the first class, while
+% 10% of 36 rounds to 4 objects for the second class. 
+%
+% SEE ALSO
+% DATASETS, RENUMLAB
+%
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org, and
+% Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology, and
+% School of Computer Science, University of Manchester
+
+
+function [DTR,DTE,Itr,Ite] = genddat(D,m,k);
+
+[n,nk,c] = getsize(D);
+nlab     = getnlab(D);
+discheck(D,[],1);   % allow for similarities     
+
+if nargin < 3, 
+	k = []; 
+else
+	if length(k) == 1
+		k = k*ones(1,c);
+	elseif length(k) == c
+		;
+	else
+		error('Vector length of the number of objects should equal the number of classes.')
+	end
+	
+	if ~(all(k == round(k))) & ~(all(k > 0 & k < 1))
+		error('K should be given either by integers or frequencies in (0,1).')	
+	end
+end  
+if ~(all(m == round(m))) & ~(all(m > 0 & m < 1))
+	error('M should be given either by integers or frequencies in (0,1).')	
+end
+
+[ja,jb] = gendat(dataset([1:n]',nlab),m);
+ja = +ja; 
+jb = +jb;
+
+J  = [];
+for j=1:c
+	K = find(nlab(ja)==j);
+	if ~isempty(k)
+		if k(j) < 1, 
+			k(j) = round(k(j)*length(K)); 
+		end
+		if k(j) > length(K)
+			error('Requested size of the representation set is not possible.')
+		end
+		K = K(1:k(j));
+	end
+	J = [J; K(:)];
+end
+M = setdiff([1:length(ja)]',J);
+
+Itr = [ja(J); ja(M)];
+Ite = jb;
+DTR = D(Itr,ja(J));
+DTE = D(Ite,ja(J));
+
Index: distools/genrep.m
===================================================================
--- distools/genrep.m	(revision 10)
+++ distools/genrep.m	(revision 10)
@@ -0,0 +1,101 @@
+%GENREP Generate a representation set
+%
+%   DR = GENREP(D,M,OPT)
+%         OR
+%   [DR,DT] = GENREP(D,M)
+%
+% INPUT
+%   D   NxN dissimilarity dataset
+%   M   Cx1 vector or scalar
+%   OPT 'include' or 'exclude'
+%
+% OUTPUT
+%   DR  - NxK dissimilarity dataset, if OPT = 'include' (DEFAULT);
+%         K=CM or K=SUM(M)
+%       - [N-K]xK dissimilarity dataset, if OPT = 'exlude';
+%         K=CM or K=SUM(M)
+%       - KxK dissimilarity dataset, if there is no third parameter;
+%         K=CM or K=SUM(M)
+%   DT  [N-K]xK remaining dissimilarity dataset, if there is no third
+%       parameter; K=CM or K=SUM(M)
+%
+% DESCRIPTION
+% If M is a scalar then a representation set of M objects per class is
+% generated for the square (dis)similarity matrix D. D should be a dataset.
+% DR has C*M columns if D has C classes. If M is a vector of length C,
+% its elements determine the number of representation objects of the
+% corresponding classes.
+%
+% If there is no third parameter, K=CM or K=SUM(M) objects are chosen
+% for the represenation set. The resulting dissimilarity dataset DR is
+% KxK and the remaining DT is [N-K]xK.
+% If desired (OPT = 'exclude'), the objects used for the representation
+% set are excluded from D. Per default, they are included.
+%
+% DEFAULT
+% M   = 1
+% OPT = 'include'
+%
+
+% Copyright: Robert Duin, r.duin@ieee.org, and
+% Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function [DR,DT] = genrep(D,N,str)
+
+if nargin < 3,
+  str = 'include';
+end
+if nargin < 2,
+  N = 1;
+end
+
+nlab    = getnlab(D);
+[m,k,c] = getsize(D);
+labels  = getlab(D);
+if size(N) == 1
+  N = N*ones(1,c);
+end
+if length(N) ~= c
+  error('Number of classes does not match the vector length.')
+end
+
+R = [];
+for j = 1:c
+  J = find(nlab==j);
+  if length(J) < N(j)
+    error('More objects requested than supplied.')
+  end
+  L = randperm(length(J));
+  R = [R; J(L(1:N(j)))];
+end
+
+strl = lower(str);
+if ~strcmp(strl,'exclude') & ~strcmp(strl,'include')
+  error(['Unknown option demanded: ' str])
+end
+
+if nargout == 1
+  L = [1:m]';
+  if strcmp(strl,'exclude')
+    L(R) = [];
+  else
+    L = [R; setdiff(L,R)];
+  end
+  DR = dataset(D(L,R),labels(L,:),'featlab',labels(R,:));
+else
+  if strcmp(strl,'exclude')
+    error('EXCLUDE does not match here.')
+  elseif strcmp(strl,'include')
+    L = R;
+    T = setdiff((1:m)',R);
+  else
+    ;
+  end
+  DR = dataset(D(L,R),labels(L,:),'featlab',labels(R,:));
+  DT = dataset(D(T,R),labels(T,:),'featlab',labels(R,:));
+end
+return
Index: distools/genrepi.m
===================================================================
--- distools/genrepi.m	(revision 10)
+++ distools/genrepi.m	(revision 10)
@@ -0,0 +1,62 @@
+%GENREPI Generate indices for representation, learning and testing sets
+%
+% 	[R,L,T] = GENREPI(D,K,M)
+%
+% INPUT
+%   D   NxN dissimilarity dataset
+%   K   Number of objects for the representation set R
+%   M   Number of objects for the learning set L; M >= K
+%
+% OUTPUT
+%   R  Indices for the representation set
+%   L  Indices for the learning set
+%   T  Indices for the test set
+%
+% DESCRIPTION
+% Random selection of M indices for a representation set R and N indices for 
+% a learning set L. L contains R (M <= N). Indices of the remaining objects 
+% are stored in T.
+%
+% DEFAULT
+% M   = N
+%
+
+% Copyright: Robert Duin, r.duin@ieee.org, and
+% Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+%
+
+function [R,L,T] = genrepi(D,k,m)
+if nargin < 3, 
+	m = k; 
+end
+
+[nr,nc,c] = getsize(D);
+if nr ~= nc,
+	error('Dissimilarity matrix should be square.');	
+end
+
+if m > nr | k > nr
+	error('K and M should not exceed the total number of objects in D.')
+end
+
+if k > m
+	error('K should not be larger than M.');
+end
+		
+R = []; 
+L = []; 
+T = [];
+C = classsizes(D);
+
+for j = 1:c
+	J  = findnlab(D,j); 
+	LL = randperm(C(j)); 
+	LL = LL(1:m); 
+	RR = LL(1:k);
+	R  = [R;J(RR)]; 
+	L  = [L;J(LL)];
+end
+T = setdiff([1:nr]',L);
+	
Index: distools/getsig.m
===================================================================
--- distools/getsig.m	(revision 10)
+++ distools/getsig.m	(revision 10)
@@ -0,0 +1,44 @@
+%GETSIG Retrieve the signature from a pseudo-Euclidean dataset or mapping
+%
+%   SIG = GETSIG(W)
+%   SIG = GETSIG(A)
+%
+% INPUT
+%   W    PE mapping, W = PE_EM(D), if D is a dissimilarity matrix
+%   A    Dataset, vectors in PE space, A = D*W
+%
+% OUTPUT 
+%   SIG  Signature, 2-element vector with numbers of 
+%        positive and negative dimensions
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, SETSIG, PE_EM, PE_DISTM
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function sig = getsig(a)
+
+  if isdataset(a)
+    sig = getuser(a,'pe_signature');
+    if isempty(sig)
+      sig = [size(a,2) 0];
+    end
+  elseif ismapping(a)
+    if ispsem(a)
+      a = pe_em(a);
+    end
+    if ispe_em(a)
+      sig = getdata(a,'sig');
+    else
+      sig = [size(a,2) 0];
+    end
+  else % doubles
+    sig = [size(a,2) 0];
+  end
+    
+return
+  
+  
+  
Index: distools/gofcl.m
===================================================================
--- distools/gofcl.m	(revision 10)
+++ distools/gofcl.m	(revision 10)
@@ -0,0 +1,57 @@
+%GOFCL  Goodness of clusters/classes separability vs compactness
+%
+%   J = GOFCL(D)
+%
+% INPUT
+%   D	NxN Dissimilarity dataset
+%
+% OUTPUT
+%   J	Criterion value
+%
+% DESCRIPTION
+% Computes a goodness of clusters/classes in an NxN dissimilarity dataset D.
+% D is labeled. The criterion provides a trade-off between the cluster/class 
+% compactness and cluster/class separability. Consider K classes, with the total
+% numbr of objects N and N_i elements in the i-th class. Let A_ij be the average 
+% dissimilarity between the i-th and j-th clusters. Then the criterion is computed
+% as:
+%     J = sum_i (n_i sum_{j neq i} N_i/(N-N_i) A_ij)  / (2 sum_i n_i A_ii )
+%
+% The larger value, the better the separability between the classes.
+%
+% EXAMPLE
+% Compare:
+% 1) rand('seed',37); randn('seed',37); a=gendats(40,2,1); d=sqrt(distm(a)); 
+%    scatterd(a); j1 = gofcl(d);
+% 2) rand('seed',37); randn('seed',37); a=gendats(40,2,7); d=sqrt(distm(a)); 
+%    scatterd(a); j2 = gofcl(d);
+
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+function J = gofcl(d);
+
+issym(d);
+lab = getnlab(d);
+cc  = max(lab);
+
+for i=1:cc
+  Z = find(lab == i);
+  dw(i) = mean(mean(d(Z,Z)));
+	for j=i+1:cc
+    ZZ = find(lab == j);
+    db(i,j) =  mean(mean(d(Z,ZZ)));
+    db(j,i) =  mean(mean(d(Z,ZZ)));
+	end
+end
+
+
+J = 0;
+for i=1:cc
+  for j=i+1:cc
+    J = J + db(i,j)/((dw(i)+dw(j)));
+  end
+end
+J = J /((cc-1)*cc);
Index: distools/graphpath.m
===================================================================
--- distools/graphpath.m	(revision 10)
+++ distools/graphpath.m	(revision 10)
@@ -0,0 +1,68 @@
+%GRAPHPATH Compute shortest paths in a graph
+%
+%	[PATH,D] = GRAPHPATH(N,L,E)
+%
+% INPUT
+%   N   Index of start node
+%   L   Nx2 array with indices of all connected nodes in the graph
+%   E   Vector with N corresponding distances
+%       Default: all distances equal to 1
+%
+% OUTPUT
+%   PATH Cell array with paths from node N to all other nodes
+%   D    Cell array with edge length of paths in PATH
+%
+% DESCRIPTION
+% The shortest paths are found from node N to all other nodes 
+% in the graph defined by {L,E}
+%
+% SEE ALSO
+% DISTGRAPH, PLOTGRAPH, KMST
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function [nodepath,pathdist] = graphpath(nstart,L,e);
+
+L = [L; fliplr(L)];
+n = size(L,1);
+if nargin < 3
+	e = ones(n,1);
+else
+	e = [e(:);e(:)];
+end
+k = max(L(:));
+
+nodedist = repmat(inf,1,k);  % distance of node to source
+nodeconn = cell(1,k);        % connections per node
+nodepath = cell(1,k);        % path from source to each node
+pathdist = cell(1,k);        % distances along path
+edgelen  = cell(1,k);
+for j=1:k
+	J = find(L(:,1)==j);
+	nodeconn{j} = L(J,2);
+	edgelen{j} = e(J);
+end
+
+K = nstart;                  % active nodes
+nodepath{nstart} = nstart;
+nodedist(nstart) = 0;
+pathdist{nstart} = 0;
+
+while ~isempty(K)
+	Knew = [];
+	for j=1:length(K)
+		C = nodeconn{K(j)};         % connecting nodes
+		for i=1:length(C)
+			ndist = nodedist(K(j)) + edgelen{K(j)}(i);
+			if ndist < nodedist(C(i))
+				nodedist(C(i)) = ndist;
+				nodepath{C(i)} = [nodepath{K(j)} C(i)];
+				pathdist{C(i)} = [pathdist{K(j)} edgelen{K(j)}(i)];
+				Knew = [Knew C(i)];
+			end
+		end
+	end
+	K = Knew;
+end
Index: distools/hamdistm.m
===================================================================
--- distools/hamdistm.m	(revision 10)
+++ distools/hamdistm.m	(revision 10)
@@ -0,0 +1,67 @@
+%HAMDISTM Hamming Distance Matrix between Binary Vectors
+%
+%   D = HAMDISTM(A,B)
+%       OR
+%   D = HAMDISTM(A)
+%
+% INPUT
+%   A   NxK Binary matrix or dataset
+%   B   MxK Binary matrix or dataset
+%
+% OUTPUT
+%   D   NxM Dissimilarity matrix or dataset
+%
+% DESCRIPTION
+% Hamming distance between sets of binary vectors.
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function d = hamdistm(A,B)
+bisa = nargin < 2;
+if bisa,
+  B = A;
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a = +A;
+b = +B;
+
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+if ca ~= cb,
+  error ('Matrices should have equal numbers of columns');
+end
+
+if any(a~=0) | any(a~=1) | any(b~=0) | any(b~=1),
+  error('Data should be binary.');
+end
+
+D = zeros(ra,rb);
+for i=1:rb
+  D(:,i) = sum((repmat(b(i,:),ra,1) ~= a),2);
+end
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/hausdm.m
===================================================================
--- distools/hausdm.m	(revision 10)
+++ distools/hausdm.m	(revision 10)
@@ -0,0 +1,82 @@
+%HAUSDM Hausdorff and modified Hausdorff distance between datasets of image blobs
+%
+%  [DH,DM] = HAUSDM(A,B,FID)
+%
+% INPUT
+%   A     XAxYAxNA matrix of NA binary images of the size XA x YA
+%   B     XBxYBxNB matrix of NB binary images of the size XB x YB
+%   FID   0/1 Report progress on the screen (default: 0)
+%
+% OUTPUT
+%   DH    NAxNB Hausdorff distance matrix
+%   DM    NAxNB Modified Hausdorff distance matrix
+%
+% DESCRIPTION
+% Computes a Hausdorff distance matrix DH and a modified Hausdorff distance
+% matrix DM between the sets of binary images A and B, or datasets containing 
+% them as features. Preferably, NA <= NB (faster computation).
+% Progress is reported in fid (fid = 1: on the sreeen).
+%
+% LITERATURE
+% M.-P. Dubuisson and A.K. Jain, "Modified Hausdorff distance for object matching", 
+% International Conference on Pattern Recognition, vol. 1, 566-568, 1994.
+%
+
+% Copyright: R.P.W. Duin, r.duin@ieee.org
+% Faculty of EWI, Delft University of Technology
+
+
+function [dh,dm] = hausdm(A,B,fid)
+
+if nargin < 3, fid = 0; end
+if isdataset(A) & isdataset(B)
+	[dh,dm] = hausdm(data2im(A),data2im(B),fid);
+	dh = setdata(A,dh);
+	dm = setdata(A,dm);
+	return
+end
+
+[ma1,ma2,na] = size(A);
+[mb1,mb2,nb] = size(B);
+dh = zeros(na,nb);
+dm = zeros(na,nb);
+for i=1:na
+	a = A(:,:,i); 
+	J = find(any(a));
+	J = [min(J):max(J)];
+	K = find(any(a'));
+	K = [min(K):max(K)];
+	a = double(a(K,J));
+	if length(a(:)) > 0
+		a = bord(a,0);
+	end
+	ca = contourc(a,[0.5,0.5]);
+	J = find(ca(1,:) == 0.5);
+	ca(:,[J J+1]) =[];
+	ca = ca - repmat([1.5;1.5],1,size(ca,2));
+	ca = ca/max(ca(:));
+	ca = ca - repmat(max(ca,[],2)/2,1,size(ca,2));
+	for j = 1:nb
+		b = B(:,:,j);
+		J = find(any(b));
+		J = [min(J):max(J)];
+		K = find(any(b'));
+		K = [min(K):max(K)];
+		b = double(b(K,J));
+		if length(b(:)) > 0
+			b = bord(b,0);
+		end
+		cb = contourc(b,[0.5,0.5]);
+		J = find(cb(1,:) == 0.5);
+		cb(:,[J J+1]) =[];
+		cb = cb - repmat([1.5;1.5],1,size(cb,2));
+		cb = cb/max(cb(:));
+		cb = cb - repmat(max(cb,[],2)/2,1,size(cb,2));
+		dab = sqrt(distm(ca',cb'));
+		dh(i,j) = max(max(min(dab)),max(min(dab')));
+		dm(i,j) = max(mean(min(dab)),mean(min(dab')));
+		if fid, disp([i,j,dh(i,j),dm(i,j)]); end
+%		fprintf(fid,'%5d %5d %10.3f %8.3f \n',i,j,dh(i,j),dm(i,j));
+	end
+end
+	
Index: distools/ikfd.m
===================================================================
--- distools/ikfd.m	(revision 10)
+++ distools/ikfd.m	(revision 10)
@@ -0,0 +1,116 @@
+%IKFD Indefinite Kernel Fisher Discriminant
+%
+%   W = IKFD(K,ALF,BIAS)
+%
+% INPUT
+%   K     NxN kernel or similarity matrix (dataset)
+%   ALF   Regularization constant
+%   BIAS  Use bias (1) or not (0)
+%
+% OUTPUT
+%   W     Trained Kernel Fisher discriminant
+%
+% DEFAULT
+%   ALF  = 0.0001
+%   BIAS = 1
+%
+% DESCRIPTION
+% Finds a Fisher linear discriminant in a kernel-induced space.
+% Regularization is necessary.
+% Multi-class classifier is trained one-vs-all classes.
+%
+% SEE ALSO
+% KPCA, KFD, FISHERC, MAPPINGS, DATASETS
+%
+% REFERENCE
+% S. Mika, G. Ratsch, J. Weston, B. Scholkopf, and K.-R. Muller.
+% Fisher discriminant analysis with kernels. In: Neural Networks for
+% Signal Processing IX, pages 41-48, 1999.
+%
+
+% Copyright: Ela Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+%
+
+
+function W = ikfd(K,alf,isb0)
+if nargin < 3,
+  isb0 = 1;
+end
+if nargin < 2 | isempty(alf),
+  alf = 0.0001;
+end
+if nargin < 1 | isempty(K),
+  W = mapping(mfilename,{alf,isb0});
+  W = setname(W,'IKFD');
+  return
+end
+
+if alf <= 0,
+  error('A small positive regularization ALF is necessary.');
+end
+
+islabtype(K,'crisp');
+isvaldset(K,1,2);     % At least one object per class and two classes
+
+lab      = getnlab(K);
+lablist  = getlablist(K);
+[n,k,C]  = getsize(K);
+
+
+% If more than two classes, train in the one-against-all strategy.
+if C > 2,
+  W = [];
+  for i=1:C
+    mlab = 2 - (lab == i);
+    KK   = setlabels(K,mlab);
+    KK   = remclass(KK,0);
+    if ~isempty(K.prior)
+      KK = setprior(KK,[K.prior(i),1-K.prior(i)]');
+    end
+
+    v  = ikfd(KK,alf,isb0);
+    W  = [W,setlabels(v(:,1),lablist(i,:))];
+  end
+  return
+
+else    % Two classes
+
+%  V  = kcenterm(K);   % Center the kernel
+%  KK = +(K*V);        % but ... centering is not necessary
+
+  KK = +K;
+  Y  = 3 - 2 * lab;   % Set labels to +/-1
+  I1 = find(Y==1);
+  I2 = find(Y==-1);
+  n1 = length(I1);
+  n2 = length(I2);
+
+  M1 = sum(KK(:,I1),2)/n1;
+  M2 = sum(KK(:,I2),2)/n2;
+  M  = (M1-M2)*(M1-M2)';
+  N  = KK(:,I1)*(eye(n1) - ones(n1)/n1)*KK(:,I1)' + KK(:,I2)*(eye(n2) - ones(n2)/n2)*KK(:,I2)';
+
+  % Regularization
+  N = N + alf * eye(n);
+
+  % Optimization
+  %[W,V,U] = svds(prinv(N)*M,1);
+  W = prinv(N)*(M1-M2);   % The same as above up to scaling
+
+  % Project data on the found direction
+  b0 = 0;
+  if isb0,
+    % Find the free parameter
+    b0 = -W'*(M1+M2)/2;
+  end
+end
+
+
+% Determine the mapping
+W = affine(W,b0,K,lablist,k,2);
+%W = cnormc(W,K);
+%W = V*W;
+W = setname(W,'IKFD');
+return;
Index: distools/ikpca.m
===================================================================
--- distools/ikpca.m	(revision 10)
+++ distools/ikpca.m	(revision 10)
@@ -0,0 +1,177 @@
+%IKPCA Indefinite Kernel Principal Component Analysis
+%
+%   [W,SIG,L] = IKPCA(K,ALF)
+%             OR
+%   [W,SIG,L] = IKPCA(W,ALF)
+%
+% INPUT
+%   K   NxN kernel or symmetric similarity matrix (dataset)
+%   W   Trained IKPCA projection into a kernel-induced pseudo-Euclidean subspace
+%   ALF Parameter determining the dimension and the mapping (optional, default: Inf)
+%       (0,1) - fraction of the total magnitude of the preserved variance
+%       Inf   - no dimension reduction; keeping all dimensions (it's VERY noisy)
+%       'p'   - projection into a Euclidean space based on the positive eigenvalues only
+%       'PARp'- projection into a Euclidean space based on the PAR fraction of
+%               positive eigenvalues; e.g. ALF = '0.9p'
+%       'n'   - projection into a Euclidean space based on the negative eigenvalues only
+%       'PARn'- projection into a (negative) Euclidean space based on the PAR fraction
+%               of negative eigenvalues; e.g. ALF = '0.7n'
+%     'P1pP2n'- projection into a Euclidean space based on the P1 positive eigenvalues
+%               and P2 negative eigenvalues; e.g. ALF = '0.7p0.1n', ALF = '7p2n'
+%     1 .. N  - total number of significant dimensions
+%     [P1 P2] - P1 dimensions or a fraction of preserved variance in the positive
+%               subspace and P2 dimensions or a fraction of preserved variance in
+%               the negative subspace; e.g. ALF = [5 10], ALF = [0.9 0.1]
+%
+% OUTPUT
+%   W   Indefinite Kernel PCA mapping
+%   SIG Signature of the kernel Pseudo-Euclidean subspace
+%   L   Sorted list of eigenvalues
+%
+% DEFAULTS
+%   ALF = Inf
+%
+% DESCRIPTION
+% Performs principal component analysis in a kernel space (either Hilbert or Krein
+% space) by finding M significant principal components. M is determined by ALF,
+% e.g. such that at least the fraction ALF of the total variance is preserved.
+% The parameter SIG describes the signature of the subspace. L is a sorted list
+% of eigenvalues describing the variances in the (pseudo-)Euclidean subspace.
+% The projection X is found as X = K*W. The signature is also stored in X.user.
+%
+% A trained mapping can be reduced by:
+%   [W,SIG,L] = IKPCA(W,ALF)
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, PCA, PSEM
+%
+% REFERENCE
+% 1. E. Pekalska and R.P.W. Duin. Indefinite Kernel Principal Component Analysis.
+%    Technical Report, 2006.
+% 2. B. Schölkopf, A. Smola, and K.-R. Müller. Kernel Principal Component Analysis.
+%    in Advances in Kernel Methods - SV Learning, pages 327-352. MIT Press, Cambridge, MA, 1999.
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester, UK
+
+
+function [W,sig,L] = ikpca (K,alf,prec)
+
+% PREC is the precision parameter used for the automatic
+% selection (heuristic) of the number of dominant eigenvalues.
+% This happens when SELEIGS is called with the parameter 'CUT'.
+
+if nargin < 3 | isempty(prec),
+  prec = 1e-4;
+end
+if nargin < 2 | isempty(alf),
+  alf = inf;
+end
+if nargin < 1 | isempty(K),
+  W = mapping(mfilename,alf,prec);
+  W = setname(W,'IKPCA');
+  return
+end
+
+
+if (isdataset(K) | isa(K,'double')),
+  if ismapping(alf),
+    % APPLY THE MAPPING: project new data using the trained mapping
+    [m,n] = size(K);
+    pars  = getdata(alf);
+
+    % Parameters
+    QL  = pars{1};    % Normalized eigenvectors
+    Kme = pars{2};    % Row vector of the average original kernel values
+
+    % Centering the kernel
+    H = -repmat(1/n,n,n);
+    H(1:n+1:end) = H(1:n+1:end) + 1;     % H = eye(n) - ones(n,n)/n
+    K = (K - repmat(Kme,m,1)) * H;
+    W = K*QL;
+    if isdataset(W),
+      W.name = ['Projected '  updname(W.name)];
+      W.user = pars{4};  % Signature of the PE subspace
+    end
+    return;
+  end
+end
+
+
+
+% REDUCE ALREADY TRAINED MAPPING
+if ismapping(K),
+  pars  = getdata(K);
+
+  QL = pars{1};
+  L  = pars{3};
+  m  = size(Q,1);
+
+  [ll,P]  = sort(-abs(L));
+  L       = L(P);
+  QL      = QL(:,P);
+  [J,sig] = seleigs(L,alf,pars{5});% J is the index of selected eigenvalues
+  QL      = QL(:,J);               % Eigenvectors
+  L       = L(J);                  % Eigenvalues
+
+  W = mapping(mfilename,'trained',{QL,pars{2},L,sig,pars{5}},[],m,length(J));
+  W = setname(W,'IKPCA');
+  return
+end
+
+
+
+
+% TRAIN THE MAPPING
+K  = +K;
+[n,m] = size(K);
+
+% Tolerance value used in comparisons
+if mean(diag(+K)) < 1,
+  tol = 1e-12;
+else
+  tol = 1e-10;
+end
+
+if ~issym(K,tol),
+  prwarning(1,'Kernel should be symmetric. It is made so by averaging.')
+  K  = 0.5 * (K+K');
+end
+
+eigmin = min(preig(K));
+if eigmin < 0 & abs(eigmin) < 1e-12
+  disp(['Minimum eig(K) = ' num2str(eigmin) '. K might be indefinite due to numerical inaccuracies.']);
+end
+
+
+Kme = mean(K,2)';
+
+% Project the data such that the mean lies at the origin
+H = -repmat(1/n,n,n);
+H(1:n+1:end) = H(1:n+1:end) + 1;  % H = eye(n) - ones(n,n)/n
+K  = H * K * H;            % K is now a centered kernel
+K  = 0.5 * (K+K');         % Make sure that K is symmetric after centering
+
+[Q, L] = preig(K);
+Q      = real(Q);
+l      = diag(real(L));
+[lm,Z] = sort(-abs(l));
+Q      = Q(:,Z);
+l      = l(Z);
+
+% Eigenvalues are now sorted by decreasing absolute value
+
+[J,sig] = seleigs(l,alf,prec);  % J is the index of selected eigenvalues
+L = l(J);                       % Eigenvalues
+Q = Q(:,J);                     % Eigenvectors
+
+% Normalize Q such that the eigenvectors of the corresponding
+% covariance matrix are J-orthonormal
+QL = Q * diag(1./sqrt(abs(L)));
+
+% Determine the mapping
+W = mapping(mfilename,'trained',{QL,Kme,L,sig,prec},[],m,sum(sig));
+W = setname(W,'IKPCA');
+return
Index: distools/intrdim.m
===================================================================
--- distools/intrdim.m	(revision 10)
+++ distools/intrdim.m	(revision 10)
@@ -0,0 +1,42 @@
+%INTRDIM Estimate Intrinsic dimension from dissimilarity data
+%
+%	K = INTRDIM(D)
+%
+% INPUT
+%   D	NxN Dissimilarity dataset
+%
+% OUTPUT
+%   K	Estimated intrinsic dimension
+%
+% DESCRIPTION
+% It is assumed that the data is generated from a normal distribution
+% in K dimensions and that the Eulcidean distance measure has been used
+% to compute D. 
+% Do NOT supply squared distances! They will definitely generate the wrong
+% result.
+%
+% EXAMPLE
+% A = GENDATB(100);
+% D = SQRT(DISTM(A));
+% K = INTRDIM(D);
+%
+% A = GENDATD(100,10);
+% D = SQRT(DISTM(A*SCALEM(A,'VARIANCE')));
+% K = INTRDIM(D);
+%
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function k = intrdim(d)
+
+d = +d.^2;
+[m,n] = size(d);
+
+% Assume selfreflecting dissim matrix
+if m==n & all(diag(+d) == 0)  
+	d(1:n+1:n*n) = [];
+end
+
+k = round(2*(mean(d(:)).^2)/var(d(:))); % based on Chi square distribution
Index: distools/ispe_em.m
===================================================================
--- distools/ispe_em.m	(revision 10)
+++ distools/ispe_em.m	(revision 10)
@@ -0,0 +1,37 @@
+%ISPE_EM Test on pseudo-Euclidean mapping
+%
+%  N = ISPE_EM(W)
+%      ISPE_EM(W)
+%
+% INPUT
+%  W    input mapping
+%
+% OUTPUT
+%  N    logical value
+%
+% DESCRIPTION
+% Returns true for pe_em mappings. If no output is required,
+% false outputs are turned into errors. This may be used for
+% assertion.
+%
+% SEE ALSO
+% ISPE_EM
+
+function n = ispe_em(w)
+
+	prtrace(mfilename);
+	
+	if isa(w,'mapping') & strcmp(w.mapping_file,'pe_em')
+		n = 1;
+	else
+		n = 0;
+	end
+
+	% generate error if input is not a psem mapping
+	% AND no output is requested (assertion)
+
+	if nargout == 0 & n == 0
+		error([newline '---- pe_em mapping expected -----'])
+	end
+
+return
Index: distools/ispsem.m
===================================================================
--- distools/ispsem.m	(revision 10)
+++ distools/ispsem.m	(revision 10)
@@ -0,0 +1,37 @@
+%ISPSEM Test on pseudo-Euclidean mapping
+%
+%  N = ISPSEM(W)
+%      ISPSEM(W)
+%
+% INPUT
+%  W    input mapping
+%
+% OUTPUT
+%  N    logical value
+%
+% DESCRIPTION
+% Returns true for psem mappings. If no output is required,
+% false outputs are turned into errors. This may be used for
+% assertion.
+%
+% SEE ALSO
+% PSEM
+
+function n = ispsem(w)
+
+	prtrace(mfilename);
+	
+	if isa(w,'mapping') & strcmp(w.mapping_file,'psem')
+		n = 1;
+	else
+		n = 0;
+	end
+
+	% generate error if input is not a psem mapping
+	% AND no output is requested (assertion)
+
+	if nargout == 0 & n == 0
+		error([newline '---- psem mapping expected -----'])
+	end
+
+return
Index: distools/issquare.m
===================================================================
--- distools/issquare.m	(revision 10)
+++ distools/issquare.m	(revision 10)
@@ -0,0 +1,36 @@
+%ISSQUARE Test on square dissimilarity matrix
+%
+%   OK = ISSQUARE(D)
+%   ISSQUARE(D)
+%
+% INPUT
+%   D      Dataset
+%
+% OUTPUT
+%   OK     1 if the matrix D is square and 0, otherwise.
+%
+% DESCRIPTION
+% True is D is a square dissimilarity matrix dataset. This includes
+% the check whether feature labels equal object labels.
+% If called without an output argument ISSQUARE generates an error
+% if D is not square.
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function OK = issquare(d)
+isdataset(d);
+[m,k] = size(d);
+
+if m == k
+  n  = nlabcmp(getfeatlab(d),getlabels(d));
+  OK = (n == 0);
+else
+  OK = 0;
+end
+
+if nargout == 0 & OK == 0
+  error([newline '---- Square dissimilarity matrix expected ----'])
+end
Index: distools/issym.m
===================================================================
--- distools/issym.m	(revision 10)
+++ distools/issym.m	(revision 10)
@@ -0,0 +1,41 @@
+%ISSYM Check whether a Matrix is Symmetric
+%
+%   OK = ISSYM(A,DELTA)
+%
+% INPUT
+%   A      Dataset
+%   DELTA  Parameter for the precision check (optional; default: 1e-13)
+%
+% OUTPUT
+%   OK     1 if the matrix A is symmetric and error otherwise.
+%
+% DESCRIPTION
+% A is considered as a symmetric matrix, when it is square and
+% max(max(A-A')) is smaller than DELTA.
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [ok,nn] = issym(A,delta)
+
+if nargin < 2,
+  prwarning(6,'The precision is not provided, set up to 1e-13.');
+  delta = 1e-13;
+end
+
+A = +A;
+[m,k] = size(A);
+if m ~= k,
+  error ('Matrix should be square.')
+end
+nn = max(max((A-A')));
+ok = (nn < delta);
+
+if ~ok & nargout == 0
+  error('Symmetric matrix expected.')
+end
+	
+return;
Index: distools/jacsimdistm.m
===================================================================
--- distools/jacsimdistm.m	(revision 10)
+++ distools/jacsimdistm.m	(revision 10)
@@ -0,0 +1,82 @@
+%JACSIMDISTM  Jaccard-like Distance Matrix based on Similarities;
+%
+%   D = JACSIMDISTM (A,B)
+%       OR
+%   D = JACSIMDISTM (A)
+%
+% INPUT
+%   A   NxK Matrix or dataset
+%   B   MxK Matrix or dataset (optional; default: B=A)
+%
+% OUTPUT
+%   D   NxM Dissimilarity matrix or dataset; D in [0,1]
+%
+% DESCRIPTION
+% Computes the distance matrix D between two sets of vectors, A and B.
+% Distances between vectors X and Y are computed based on the similarity
+% formula:
+%     SIM(X,Y) = (X'Y) / (||X||^2 + ||Y||^2 - ||x||*||y||)
+%     D(X,Y)   = SQRT(1 - SIM(X,Y))
+% This is an extension of the binary Jaccard distance.
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% DEFAULT
+%   B = A
+%
+% SEE ALSO
+% SIMDISTM, CORRDISTM, COSDISTM, LPDISTM, EUDISTM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function D = jacsimdistm(A,B)
+bisa = nargin < 2;
+if bisa,
+  B = A;
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a = +A;
+b = +B;
+
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+
+if ca ~= cb,
+  error ('Matrices should have equal numbers of columns');
+end
+
+aa = sum(a.*a,2);
+bb = sum(b.*b,2)';
+D  = (a*b') ./ (aa(:,ones(rb,1)) + bb(ones(ra,1),:) - sqrt(aa(:,ones(rb,1)) .* bb(ones(ra,1),:)));
+D = sqrt(1 - D);
+
+% Check numerical inaccuracy
+D (find (D < eps)) = 0;   % Make sure that distances are nonnegative
+if bisa,
+  D = 0.5*(D+D');         % Make sure that distances are symmetric for D(A,A)
+end
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/kcenterm.m
===================================================================
--- distools/kcenterm.m	(revision 10)
+++ distools/kcenterm.m	(revision 10)
@@ -0,0 +1,105 @@
+%KCENTERM Kernel Weighted Centering Mapping
+%
+%   W = kcenterm(K,V)
+%
+% INPUT
+%   K   NxN kernel or similarity matrix (dataset)
+%   V   'C' (default) or Nx1 weight vector of nonnegative values; sum(V)=1
+%
+% OUTPUT
+%   W   Kernel weighted centering mapping
+%
+% DEFAULT
+%   V   = 'C';
+%
+% DESCRIPTION
+% Defines a mapping that centers the given NxN kernel matrix K:=K(X,X)
+% such that the weighted mean coincides with the origin in the vector space
+% induced by K. The nonnegative weights of the mean are defined by an
+% Nx1 vector V; sum(V) = 1. V = 'C' stands for V=ones(N,1)/N, hence
+% the true centering.
+%
+% The mapping works with both positive (semi-)definite and indefinite
+% kernels. V can be applied to a new MxN kernel Knew:=K(Xnew,X).
+%
+% SEE ALSO
+% KPCA, MAPPINGS, DATASETS
+%
+
+% Copyright: Ela Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+%
+
+function [V,KK] = kcenterm(K,v)
+
+if nargin < 2 | isempty(v)
+  v = 'c';
+end
+
+if nargin < 1 | isempty(K)
+   V = mapping(mfilename);
+   V = setname(V,'kcenterm');
+   return
+end
+
+
+if (isdataset(K) | isa(K,'double'))
+  if ismapping(v)
+
+    [m,n] = size(K);
+    pars  = getdata(v);
+
+    v   = pars{1};
+    Kwm = pars{2};
+
+    H  = eye(n) - v*ones(1,n);
+    V  = (K - repmat(Kwm',m,1))* H;
+    return;
+  end
+end
+
+
+
+lab      = getlab(K);
+lablist  = getlablist(K);
+[n,m,c]  = getsize(K);
+
+tol = 1e-12;
+if ~issym(K,tol),
+  error('Kernel matrix K should be symmetric.')
+end
+
+if v == 'c',
+  v = ones(n,1)/n;
+end
+
+if length(v)==1
+  l = intersect(v,1:n)
+  v = zeros(n,1);
+  v(l) = 1;
+end
+
+if length(v) ~= n,
+  error('V has a wrong size.');
+end
+
+if any(v) < 0 | any(v) > 1,
+  error('V should have elements in [0,1].');
+end
+
+if abs(sum(v) - 1) > tol
+  error('sum(V) ~= 1.');
+end
+
+
+% Center K such that the weighted mean coincides with the origin
+Kwm  = K*v;
+if nargout > 1
+  H  = eye(n) - v*ones(1,n);
+  KK = H * K * H;
+end
+
+V = mapping(mfilename,'trained',{v,Kwm},[],m,m);
+V = setname(V,'kcenterm');
+return
Index: distools/kfd.m
===================================================================
--- distools/kfd.m	(revision 10)
+++ distools/kfd.m	(revision 10)
@@ -0,0 +1,116 @@
+%KFD Kernel Fisher Discriminant
+%
+%   W = KFD(K,ALF,BIAS)
+%
+% INPUT
+%   K     NxN kernel or similarity matrix (dataset)
+%   ALF   Regularization constant
+%   BIAS  Use bias (1) or not (0)
+%
+% OUTPUT
+%   W     Trained Kernel Fisher discriminant
+%
+% DEFAULT
+%   ALF  = 0.0001
+%   BIAS = 1
+%
+% DESCRIPTION
+% Finds a Fisher linear discriminant in a kernel-induced space.
+% Regularization is necessary.
+% Multi-class classifier is trained one-vs-all classes.
+%
+% SEE ALSO
+% KPCA, FISHERC, MAPPINGS, DATASETS
+%
+% REFERENCE
+% S. Mika, G. Ratsch, J. Weston, B. Scholkopf, and K.-R. Muller.
+% Fisher discriminant analysis with kernels. In: Neural Networks for
+% Signal Processing IX, pages 41-48, 1999.
+%
+
+% Copyright: Ela Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+%
+
+
+function W = kfd(K,alf,isb0)
+if nargin < 3,
+  isb0 = 1;
+end
+if nargin < 2 | isempty(alf),
+  alf = 0.0001;
+end
+if nargin < 1 | isempty(K),
+  W = mapping(mfilename,{alf,isb0});
+  W = setname(W,'KFD');
+  return
+end
+
+if alf <= 0,
+  error('A small positive regularization ALF is necessary.');
+end
+
+islabtype(K,'crisp');
+isvaldset(K,1,2);     % At least one object per class and two classes
+
+lab      = getnlab(K);
+lablist  = getlablist(K);
+[n,k,C]  = getsize(K);
+
+
+% If more than two classes, train in the one-against-all strategy.
+if C > 2,
+  W = [];
+  for i=1:C
+    mlab = 2 - (lab == i);
+    KK   = setlabels(K,mlab);
+    KK   = remclass(KK,0);
+    if ~isempty(K.prior)
+      KK = setprior(KK,[K.prior(i),1-K.prior(i)]');
+    end
+
+    v  = kfd(KK,alf,isb0);
+    W  = [W,setlabels(v(:,1),lablist(i,:))];
+  end
+  return
+
+else    % Two classes
+
+%  V  = kcenterm(K);   % Center the kernel
+%  KK = +(K*V);        % but ... centering is not necessary
+
+  KK = +K;
+  Y  = 3 - 2 * lab;   % Set labels to +/-1
+  I1 = find(Y==1);
+  I2 = find(Y==-1);
+  n1 = length(I1);
+  n2 = length(I2);
+
+  M1 = sum(KK(:,I1),2)/n1;
+  M2 = sum(KK(:,I2),2)/n2;
+  M  = (M1-M2)*(M1-M2)';
+  N  = KK(:,I1)*(eye(n1) - ones(n1)/n1)*KK(:,I1)' + KK(:,I2)*(eye(n2) - ones(n2)/n2)*KK(:,I2)';
+
+  % Regularization
+  N = N + alf * eye(n);
+
+  % Optimization
+  %[W,V,U] = svds(prinv(N)*M,1);
+  W = prinv(N)*(M1-M2);   % The same as above up to scaling
+
+  % Project data on the found direction
+  b0 = 0;
+  if isb0,
+    % Find the free parameter
+    b0 = -W'*(M1+M2)/2;
+  end
+end
+
+
+% Determine the mapping
+W = affine(W,b0,K,lablist,k,2);
+%W = cnormc(W,K);
+%W = V*W;
+W = setname(W,'KFD');
+return;
Index: distools/kmst.m
===================================================================
--- distools/kmst.m	(revision 10)
+++ distools/kmst.m	(revision 10)
@@ -0,0 +1,100 @@
+%KMST Finds K Minimum Spanning Trees based on a Distance Matrix
+%
+%   [L,DL,D] = KMST(D,K,P)
+%
+% INPUT
+%   D   NxN Symmetric dissimilarity matrix  or dataset
+%   K   Number of minimum spanning trees (optional, default: 1)
+%   P   Object number, P = 1..N (optional, default: object P with the
+%       largest distances to all other objects)
+%
+% OUTPUT
+%   L   K(N-1)x2 List of edges in the minimum spanning tree
+%   DL  K(N-1)x1 List of the corresponding minimal distances
+%   D   NxN Dissimilarity matrix (dataset) with removed edges of L
+%       (set to INF)
+% DEFAULT
+%   K = 1
+%   P = Object number which has the largest distances to all other objects
+%
+% DESCRIPTION
+% Finds K minimum spanning trees (MSTs) based on the given symmetric distance
+% matrix D. D(i,j)=INF and D(j,i)=INF denote the lack of edge (connection)
+% between i and j. Starting from the first MST, the procedure finds the
+% current MST and then removes all the edges from D. It repeats until K MSTs
+% are determined. The search for MSTs starts from the object P. The result does
+% not depend on P, however, the ordering does.
+%
+% The implementation relies on the Prim's algorithm.
+%
+% SEE ALSO
+% PLOTGRAPH, DISTGRAPH, GRAPHPATH
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function [L,d,D] = kmst(D,k,p)
+
+if nargin < 3,
+  [ss,p]= max(sum(+D));
+end
+
+if nargin < 2,
+  k = 1;
+end
+
+[n,m] = size(D);
+if n ~= m,
+  error('D should be a square matrix.');
+end
+prec = 1e-12;
+if ~issym(D,prec),
+  prwarning(1,'D should be symmetric. It is made so by averaging.');
+end
+D = 0.5*(D+D');
+
+if p < 0 | p > n |  p ~= round(p),
+  error(['P should be an integer in [1,' int2str(n) ']']);
+end
+if k < 0 | k > n | k ~= round(k),
+  error(['K should be an integer in [1,' int2str(n) ']']);
+end
+
+isdset = isdataset(D);
+
+if isdset,
+  DD = D;
+  D  = +D;
+end
+L  = [];
+d  = [];
+for z=1:k
+  Lmst = zeros(n-1,2);
+  dmst = zeros(n-1,1);
+  Z    = setdiff(1:n,p);
+  [dmst(1),z] = min(D(p,Z));
+  Lmst(1,:)   = [p Z(z)];
+  for i=2:n-1
+    LL   = Lmst(1:i-1,:);
+    Jmst = unique(LL(:))';
+    J    = setdiff(1:n,Jmst);
+    [Dmin,Z]    = min(D(Jmst,J),[],2);
+    [dmst(i),k] = min(Dmin);
+    Lmst(i,:)   = [Jmst(k) J(Z(k))];
+  end
+
+  LL = [Lmst; Lmst(:,[2 1])];
+  %for u=1:length(LL), D(LL(u,1),LL(u,2)) = inf; end
+  D((LL(:,2)-1)*n+LL(:,1)) = inf;
+
+  L = [L; Lmst];
+  d = [d; dmst];
+end
+
+if isdset,
+  D = setdata(DD,D);
+end
+return;
Index: distools/knndc.m
===================================================================
--- distools/knndc.m	(revision 10)
+++ distools/knndc.m	(revision 10)
@@ -0,0 +1,151 @@
+%KNNDC K-Nearest Neighbor Classifier for dissimilarity matrices
+%
+%	[W,K,E] = KNNDC(D,K,PAR,EDIT,PAR1,PAR2,PAR3)
+%	[W,K,E] = D*KNNDC([],K,PAR,EDIT,PAR1,PAR2,PAR3)
+%
+% INPUT
+%   D     NxN dissimilarity matrix or dataset
+%	K	  Number of nearest neighbors; if [], then K is optimized	
+%	PAR = 'LOO' - (default) compute leave-one-out optimization for K
+%               it is assumed that the first objects in the training set
+%               constitute the representation set.
+%		  'ALL' - include all dissimilarities for optimization of K
+%               (representation set should not be included in training set)
+%   EDIT = 'ORG' editting and condensing is done by EDICON_ORG using 
+%			K = PAR1 and N = PAR2. K is set to 1. This only affects the
+%			representation set. During testing the reduced representation set 
+%			is used.
+%        = 'DANDK', editting and condensing is done by EDICON using NSETS = PAR1, 
+%		    NITERS = PAR2 and NTRIES = PAR3. K is set to 1. This only affects 
+%			the representation set. During testing the reduced representation
+% 			set is used.
+% OUTPUT
+%   W	  Classifier
+%   K	  Number of nearest neighbors
+%	E	  Error on D
+%
+% DESCRIPTION
+% Compute K-Nearest Neigbor classifier for the dissimilarity set D by optimizing K 
+% (if the routine is called with K = []), the error on D is returned in E.
+% A test dissimilarity set DTE defined by the same representation set can now be mapped 
+% by C = DTE*W:
+%    C        - estimated class confidences
+%    C*LABELD - assigned class labels
+%    C*TESTC  - classification error
+%
+% NOTE
+% NN errors for dissimilarity data can be directly estimated by TESTKD.
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, TESTKD, CROSSVALD, EDICON
+%
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% and Ela Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology
+% and University of Manchester, UK
+
+
+function [W,knn,e] = knndc(d,knn,par,edit,par1,par2,par3)
+
+if nargin < 7, par3 = []; end
+if nargin < 6, par2 = []; end
+if nargin < 5, par1 = []; end
+if nargin < 4, edit = ''; end
+if nargin < 3 | isempty(par), par = 'loo'; end
+if nargin < 2,	knn = []; end
+
+
+% empty call, to handle d*knnd, or d*knnd([],par)			
+if nargin < 1 | isempty(d)
+	W = mapping(mfilename,'untrained',knn,par);
+	W = setname(W,'KNND');
+	return
+end
+
+nlab     = getnlab(d);
+lablist  = getlablist(d);
+featlist = getfeat(d);
+[m,k,c]  = getsize(d);
+p        = getprior(d);
+
+%[nlab,lablist,m,k,c,p,featlist] = dataset(d);
+[clab,classlist] = renumlab(featlist);
+[cl,nc] = renumlab(classlist,lablist);
+
+if size(nc,1) > c
+	error('Object labels do not match representation set')
+end
+                   % correct for different classlist - lablist orders
+J = matchlablist(classlist,lablist);
+classlist = lablist;
+clab = J(clab);
+
+if ~ismapping(knn)  % training (find knn)
+			
+	if strcmp(par,'loo')
+		% get rid of leave-one-out problems
+		km = min(k,m);
+		dmax=max(max(+d))*2;
+		d(1:km,1:km) = d(1:km,1:km) + dmax*eye(km);
+	elseif ~strcmp(par,'all')
+		error(['Unknown option ''' par ''''])
+	end
+
+	switch upper(edit)
+		case 'ORG'
+			if isempty(par1) & isempty(par2)
+				JJ = edicon_org(d); 
+			elseif isempty(par2)
+				JJ = edicon_org(d,par1); 
+			else
+				JJ = edicon_org(d,par,par2); 
+			end
+			knn = 1;
+		case 'DANDK'
+			JJ = edicon(d,par1,par2,par3);
+			knn = 1;
+		otherwise
+			JJ = [1:k];
+	end
+	if isempty(knn) % optimize knn
+		[Y,L] = sort(+d,2);
+		L = clab(L);
+		Ymax = zeros(m,k);
+		Yc = zeros(m,k);
+		for j = 1:c
+			Y = double(L == j);
+			for n = 2:k
+				Y(:,n) = Y(:,n-1) + Y(:,n);
+			end
+			J = Y > Ymax;
+			Ymax(J) = Y(J);
+			Yc(J) = j*ones(size(Yc(J)));
+		end
+		z = sum(Yc == nlab*ones(1,k),1);
+		[e,knn]=max(z);
+		e = 1 - e/m;
+		z = 1 - z/m;
+	elseif nargout == 3
+		e = testkd(d,knn,par);
+	end
+	
+	W = mapping(mfilename,'trained',{knn,JJ},lablist,k,c);
+	W = setname(W,'KNNDC');
+	
+else        % testing for given mapping or knn
+
+	w = knn; % mapping stored in knn
+  wdata  = getdata(w); 
+	knn = wdata{1};
+	J = wdata{2};
+  classlist = getlab(w);
+  c = size(w,2);
+  [nn,nf,fl] = renumlab(classlist,lablist);
+	if max(nf) > c
+		error('Representation set labels do not match with classifier')
+	end
+	[e,q] = testkd(d(:,J),knn);
+	W = q;
+	
+end
Index: distools/kpca.m
===================================================================
--- distools/kpca.m	(revision 10)
+++ distools/kpca.m	(revision 10)
@@ -0,0 +1,158 @@
+%KPCA Kernel Principal Component Analysis
+%
+%   [W,L] = KPCA(K,ALF)
+%         OR
+%   [W,L] = KPCA(W,ALF)
+%
+% INPUT
+%   K   NxN kernel or symmetric similarity matrix (dataset)
+%   W   Trained KPCA projection a kernel-induced space
+%   ALF Parameter determining the dimensionality and the mapping (optional, default: Inf)
+%       (0,1) - fraction of the total preserved variance; e.g. ALF = 0.9
+%       M     - Number of dimensions in the subspace; e.g. ALF = 5
+%       Inf   - No dimensionality reduction, keeping all dimensions (it's VERY noisy)
+%
+% OUTPUT
+%   W   Kernel PCA mapping
+%   L   Sorted list of eigenvalues
+%
+% DEFAULTS
+%   ALF = Inf
+%
+% DESCRIPTION
+% Performs principal component analysis in a kernel-induced space by finding
+% M significant directions. M is provided directly or determined by ALF such
+% that the fraction ALF of the total variance is preserved. L is a sorted list
+% of eigenvalues describing the variances in the kernel subspace.
+% The projection X is found as X = K*W.
+%
+% A trained mapping can be reduced further by:
+%   W = KPCA(W,ALF)
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, PCA, PSEM
+%
+% REFERENCE
+% B. Scholkopf, A. Smola, and K.-R. Muller. Kernel Principal Component Analysis.
+% in Advances in Kernel Methods - SV Learning, pages 327-352. MIT Press, Cambridge, MA, 1999.
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester, UK
+
+
+function [W,L] = kpca (K,alf)
+
+if nargin < 2 | isempty(alf),
+  alf = inf;
+end
+if nargin < 1 | isempty(K),
+  W = mapping(mfilename,alf);
+  W = setname(W,'Kernel PCA');
+  return
+end
+
+
+if (isdataset(K) | isa(K,'double')),
+  if ismapping(alf),
+    % APPLY MAPPING: project new data using the trained mapping.
+    [m,n] = size(K);
+    pars  = getdata(alf);
+
+    % Parameters
+    Q   = pars{1};  % Eigenvectors
+    Kme = pars{2};  % Vector of averaged kernel values
+
+    % Centering the kernel
+    H = -repmat(1/n,n,n);
+    H(1:n+1:end) = H(1:n+1:end) + 1;     % H = eye(n) - ones(n,n)/n
+    K = (K - Kme(ones(m,1),:)) * H;
+    W = K*Q;
+    if isdataset(W),
+      W.name = ['Projected '  updname(W.name)];
+    end
+    return;
+  end
+end
+
+
+if ~isnumeric(alf) & ~isinf(alf)
+  error('Wrong ALF.')
+end
+if alf <= 0
+  error('ALF should be positive.')
+end
+
+
+% REDUCE ALREADY TRAINED MAPPING
+if ismapping(K),
+  pars  = getdata(K);
+
+  Q  = pars{1};
+  L  = pars{3};
+  m  = size(Q,1);
+
+  [ll,P] = sort(-abs(L));
+  L = L(P);
+  Q = Q(:,P);
+  J = seleigs(L,alf);       % J is the index of selected eigenvalues
+  Q = Q(:,J);               % Eigenvectors
+  L = L(J);                 % Eigenvalues
+
+  W = mapping(mfilename,'trained',{Q,pars{2},L},[],m,length(J));
+  W = setname(W,'KPCA');
+  return
+end
+
+
+
+% TRAIN MAPPING
+K  = +K;
+[n,m] = size(K);
+
+% Tolerance value used in comparisons
+if mean(diag(+K)) < 1,
+  tol = 1e-12;
+else
+  tol = 1e-10;
+end
+
+if ~issym(K,tol),
+  prwarning(1,'Kernel should be symmetric. It is made so by averaging.')
+  K  = 0.5 * (K+K');
+end
+
+eigmin = min(preig(K));
+if eigmin < 0,
+  error(['K is not psd. Minimum eig(K) = ' ...
+  num2str(eigmin) '. Please regularize the kernel appropriately or use IKPCA.']);
+end
+
+Kme = mean(K,2)';
+
+% Project the data such that the mean lies at the origin
+H = -repmat(1/n,n,n);
+H(1:n+1:end) = H(1:n+1:end) + 1;  % H = eye(n) - ones(n,n)/n
+K  = H * K * H;            % K is now the centered kernel
+K  = 0.5 * (K+K');         % Make sure that K is symmetric after centering
+
+[Q,L]  = preig(K);
+Q      = real(Q);
+l      = diag(real(L));
+[lm,Z] = sort(-l);
+Q      = Q(:,Z);
+l      = l(Z);             % Eigenvalues are sorted by decreasing value
+
+
+J = seleigs(l,alf);        % J is the index of selected eigenvalues
+L = l(J);                  % Eigenvalues
+Q = Q(:,J);                % Eigenvectors
+
+% Normalize Q such that the eigenvectors of the covariance
+% matrix are orthonormal
+Q = Q* diag(1./sqrt(diag(Q'*K*Q)));
+
+% Determine the mapping
+W = mapping(mfilename,'trained',{Q,Kme,L},[],m,length(J));
+W = setname(W,'KPCA');
+return
Index: distools/ksvc.m
===================================================================
--- distools/ksvc.m	(revision 10)
+++ distools/ksvc.m	(revision 10)
@@ -0,0 +1,247 @@
+%KSVC Kernel Support Vector Classifier on a kernel matrix
+%
+%   [W,J,REG] = KSVC(K,C,KC,R)
+%
+% INPUT
+%   K   NxN Kernel dataset
+%   C   Regularization parameter (optional; default: 1)
+%   KC  Kernel centering, 1/0, (optional; default: 1)
+%   R   Parameter: -1,0,1,2
+%       -1 or 'flip',   Changes the kernel by flipping negative eigenvalues to
+%          positive
+%        0 or '',       Uses the kernel as it is
+%        1 or 'reg',    Checks positive definiteness and regularizes the kernel by
+%          adding the minimal constant in the form of 10^i to the diagonal
+%        2 or 'lamreg', Checks positive definiteness and regularizes the kernel by
+%          adding the minimal constant to the diagonal (equal to the magnitude of
+%          the smallest negative eigenvalue)
+%          (optional; default: 0, do not change the kernel)
+%
+% OUTPUT
+%   W   Mapping: Support Vector Classifier
+%   J   Object identifiers of support objects
+%   REG Regularization parameter added to the diagonal, if used (R=1,2); a vector
+%       of eigenvalues of K (R=-1), or -1 if not checked (R=0)
+%
+% DEFAULT
+%   C  = 1
+%   KC = 1
+%   R  = 0 (use the kernel as it is)
+%
+% DESCRIPTION
+% Determines a support vector machine (SVM) for the kernel K. Quadratic programming
+% formulation is used to solve the problem. K can be positive definite or indefinite.
+% J is a list of the indices of the support objects from K. The smaller C, e.g.
+% C < 1, the larger class overlap imposed. Optimal C will be different for regularized
+% and indefinite kernels.
+%
+% If R = 2, then K is regularized by adding the smallest constant possible to the
+% diagonal to make it positive definite. If R = 1, then K is regularized by adding
+% the smallest constant in the form of 10^i to the diagonal. If R = -1, then the
+% eigendecomposition of K is found as K = Q*L*Q' and the negative eigenvalues are
+% flipped, so the SVM is built on K = Q*abs(L)*Q'.
+%
+% IMPORTANT
+% The classifier cannot always be constructed for an indefinite kernel. If the norm
+% of the determined weight vector V in the Krein (pseudo-Euclidean) space induced
+% by K is negative, i.e. if V'*K*V < 0, then the proper SVM cannot be built. This
+% happens when the hyperplane in the Krein space lies 'more' in the negative
+% subspace than in the positive one. This means that the kernel is strongly
+% indefinite. Currently, a warning is given and a pseudo-Fisher classifier is trained,
+% instead. The pseudo-Fisher classifier is also trained in any situation when the
+% quadratic optimization fails to find a solution.
+%
+% REMARK
+% Note that if D is a symmetric distance/dissimilarity matrix, then K = -D is an
+% (indefinite) kernel. If D.^2 is a square Euclidean distance matrix, then K = -D.^2
+% is a proper (conditionally negative definite) kernel. So, a linear SVM on the
+% vectorial data X, based on the kernel K = X*X', is equivalent to the kernel-based
+% SVM on K = -D(X,X).^2.
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, KSVO, SVC,
+%
+% LITERATURE
+% 1. B.Scholkopf, A. Smola, Learning with kernels, MIT press, 2001,
+%    http://www.learning-with-kernels.org/.
+% 2. B. Haasdonk, Feature Space Interpretation of SVMs with Indefinite Kernels.
+%    IEEE Trans. on PAMI, 27(4):482-492, 2005.
+% 3. E. Pekalska, P. Paclik, R.P.W. Duin,  A Generalized Kernel Approach to
+%    Dissimilarity-based Classification, JMLR, vol.2, no.2, 175-211, 2002.
+
+% Copyright: Elzbieta Pekalska, Robert P.W. Duin, ela.pekalska@googlemail.com
+% Based on SVC.M by D.M.J. Tax, D. de Ridder and R.P.W. Duin
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [W,J,reg,err,K] = ksvc(K,C,kc,r,no)
+prtrace(mfilename);
+
+if nargin < 5,
+  % Multi-class problems are solved by one-vs-all by calling KSVC.
+  % no is the class number in such a situation; 0 is the standard 2-class case
+  no = 0;
+end
+if nargin < 4,
+  r = 0;
+end
+if nargin < 3,
+  kc = 1;
+end
+if nargin < 2 | isempty(C),
+  C = 1;
+  prwarning(3,'Regularization parameter C set to 1.\n');
+end
+if nargin < 1 | isempty(K),
+  W = mapping(mfilename,{C,kc,r});
+  W = setname(W,'Kernel Support Vector Classifier (KSVC)');
+  return;
+end
+
+if all(kc ~= [0 1]),
+  error('Wrong KC parameter.');
+end
+
+switch lower(r)
+  case {'flip', -1},  r = -1;
+  case {'', 0},       r = 0;
+  case {'reg', 1},    r = 1;
+  case {'lamreg', 2}, r = 2;
+  otherwise
+    error('Wrong parameter R.');
+end
+
+
+% TRAIN THE CLASSIFIER
+if ~isa(C,'mapping')
+  islabtype(K,'crisp');
+  isvaldset(K,1,2);      % Expect at least 1 object per class and 2 classes
+  [m,k,c] = getsize(K);
+  if m ~=k,
+    error('The kernel is not a square matrix.');
+  end
+  nlab  = getnlab(K);
+
+  % The SVM is basically a two-class classifier.
+  % Multi-class problems are trained one-versus-all.
+
+  if c == 2   % Two-class classifier
+    % Compute the parameters for the optimization:
+    y = 3 - 2*nlab;
+
+    prec = 1e-12;
+    if ~issym(K,prec),
+      prwarning(1, 'The kernel is not symmetric. The values are averaged out.')
+    end
+
+    if kc,   % Center the data
+      me = mean(+K,2)';                % Store the mean value
+
+      B = -repmat(1/m,m,m);
+      B(1:m+1:end) = B(1:m+1:end)+1;   % B = eye(m) - ones(m,m)/m
+      K = B*K*B;                       % K is now centered
+    else
+      me = [];
+    end
+    K = (K+K')/2;                      % K is averaged as QP solver is sensitive to small asymmetry
+
+
+    % Check feasibility of the kernel:
+    if r == 0 & dmeans(K,y) < 0,
+      if no > 0,
+        ss = [num2str(no) '-vs-all '];
+      else,
+        ss = '';
+      end
+      prwarning(1,['The kernel is badly indefinite. The ' ss ' SVM cannot be defined. Pseudo-Fisher is computed instead.']);
+      err = 1;
+      v   = prpinv([K ones(m,1)])*y;
+      J   = [1:m]';
+      T   = [];
+      reg = [];
+    else
+      % Perform the optimization
+      [v,J,T,reg,err] = ksvo(+K,y,C,r);
+    end
+
+    % Store the results
+    W = mapping(mfilename,'trained',{me,J,T,v,reg},getlablist(K),k,2);
+    % W = cnormc(W,K);
+    W = setname(W,'Kernel Support Vector Classifier (KSVC)');
+    W = setcost(W,K);
+    % J = K.ident(J);
+
+  else   % MULTI-CLASS CLASSIFIER: C > 2
+
+    % MCLASSC cannot be used here as we have a kernel K
+    W = [];
+    J = zeros(m,1);
+    lablist = getlablist(K);
+
+    for i=1:c
+      lab = 2 - (nlab == i);   % lab = 1/2
+      KK  = setlabels(K,lab);
+      KK  = remclass(KK,0);
+      KK  = setfeatlab(K,lab);
+      if ~isempty(K.prior)
+        KK = setprior(KK,[K.prior(i),1-K.prior(i)]');
+      end
+      [V,j,reg(i),err(i)]= ksvc(KK,C,kc,r,i);
+      W = [W,setlabels(V(:,1),lablist(i,:))];
+      J(j) = 1;
+    end
+    J = find(J);
+  end
+
+else
+
+% EXECUTE THE CLASSIFIER
+  % C is a SVM classifier now
+  n = size(K,1);
+  w = +C;
+
+  % Get the parameters from the classifier
+  me = w{1};
+  J  = w{2};
+
+  % The first parameter w{1} stores the mean of the kernel.
+  % When it is non-empty, kernel centering should also be applied
+  % to the test kernel.
+
+  if ~isempty(me),
+    m = length(me);
+    % Center the kernel
+    B = -repmat(1/m,m,m);
+    B(1:m+1:end) = B(1:m+1:end) + 1;    % B = eye(m) - ones(m,m)/m
+    K = (K - me(ones(n,1),:)) * B;
+  end
+
+  if ~isempty(w{3}),   % this is the transformation that reverses the negative eigenvalues
+    K = K*w{3};
+  end
+
+  % The classifier is stored in w{4}
+  % Data is mapped by the kernel, now we just have a linear classifier  w*x+b:
+  d = [K(:,J) ones(n,1)] * w{4};
+  d = sigm([d -d]);
+  W = setdat(K,d,C);
+end
+return
+
+
+
+
+function dm = dmeans(K,y)
+% Coputes the square pseudo Euclidean distance between the
+% means of the two classes. This can be done by using the kernel only.
+% Negative value means that the contribution of the negative
+% subspace in the pseudo-Euclidean sense is too large.
+
+yy = y;
+Z  = find (y == 1);
+T  = find (y == -1);
+yy(Z) = 1/length(Z);
+yy(T) = -1/length(T);
+dm    = yy'*(+K)*yy;
+return;
Index: distools/ksvc_nu.m
===================================================================
--- distools/ksvc_nu.m	(revision 10)
+++ distools/ksvc_nu.m	(revision 10)
@@ -0,0 +1,268 @@
+%KSVC_NU Kernel Support Vector Classifier: NU algorithm
+%
+%   [W,J,C,REG] = KSVC_NU(K,NU,KC,R)
+%
+% INPUT
+%   K   NxN Kernel dataset
+%   NU  Regularization parameter (0 < NU < 1);
+%       expected fraction of support vectors (optional; default: 0.25)
+%   KC  Kernel centering, 1/0, (optional; default: 1)
+%   R   Parameter: -1,0,1,2.
+%       -1 or 'flip',   Changes the kernel by flipping negative eigenvalues to
+%          positive
+%        0 or '',       Uses the kernel as it is
+%        1 or 'reg',    Checks positive definiteness and regularizes the kernel by
+%          adding the minimal constant in the form of 10^i to the diagonal
+%        2 or 'lamreg', Checks positive definiteness and regularizes the kernel by
+%          adding the minimal constant to the diagonal (equal to the magnitude of
+%          the smallest negative eigenvalue)
+%          (optional; default: 0, do not change the kernel)
+%
+% OUTPUT
+%   W   Mapping: Support Vector Classifier
+%   J   Object identifiers of support objects
+%   C   Equivalent C regularization parameter of the KSVC algorithm
+%   REG Regularization parameter added to the diagonal, if used (R=1,2); a vector
+%       of eigenvalues of K (R=-1), or -1 if not checked (R=0)
+%
+% DEFAULT
+%   NU  = 1
+%   KC  = 1
+%   R   = 0 (use the kernel as it is)
+%
+% DESCRIPTION
+% Determines a support vector machine (SVM) for the kernel K. Quadratic programming
+% formulation is used to solve the problem. K can be positive definite or indefinite.
+% indefinite. J is a list of the indices of the support objects from K. NU belongs
+% to the interval (0,1). The larger NU, the larger class overlap. Default NU = 0.25.
+%
+% For positive semidefinite kernels, NU is bounded from above by NU_MAX, where
+% NU_MAX = (1 - ABS(Lp-Lm)/(Lp+Lm)), where Lp (Lm) is the number of positive
+% (negative) samples. If NU > NU_MAX is supplied to the routine it will be changed to
+% the NU_MAX.
+% If NU is less than some NU_MIN which depends on the overlap between the classes,
+% the algorithm will typically take long time to converge (if at all). So, it is
+% advisable to set NU larger than the expected overlap.
+% The output is rescaled in such a way as if returned by KSVC with the parameter C.
+%
+% If R = 2, then K is regularized by adding the smallest constant possible to the
+% diagonal to make it positive definite. If R = 1, then K is regularized by adding
+% the smallest constant in the form of 10^i to the diagonal. If R = -1, then the
+% eigendecomposition of K is found as K = Q*L*Q' and the negative eigenvalues are
+% flipped, so the SVM is built on K = Q*abs(L)*Q'.
+%
+% IMPORTANT
+% The classifier cannot always be constructed for an indefinite kernel. If the norm
+% of the determined weight vector V in the Krein (pseudo-Euclidean) space induced
+% by K is negative, i.e. if V'*K*V < 0, then the proper SVM cannot be built. This
+% happens when the hyperplane in the Krein space lies 'more' in the negative subspace
+% than in the positive one. This means that the kernel is strongly indefinite.
+% Currently, a warning is given and a pseudo-Fisher classifier is trained, instead.
+% The pseudo-Fisher classifier is also trained in any situation when the quadratic
+% optimization fails to find a solution.
+%
+% REMARKS
+% Note that if D is a symmetric distance/dissimilarity matrix, then K = -D is an
+% (indefinite) kernel. If D.^2 is a square Euclidean distance matrix, then K = -D.^2
+% is a proper (conditionally negative definite) kernel. So, a linear SVM on some
+% data X, based on the kernel K = X*X' is the same classifier as the kernel-based
+% SVM on K = -D(X,X).^2.
+
+% DESCRIPTION
+% Determines a support vector machine (SVM) for the kernel K. Quadratic programming
+% formulation is used
+% The smaller C, e.g.
+% C < 1, the larger class overlap imposed. Optimal C will be different for a regularized
+% kernel and for an indefinite one.
+%
+% SEE ALSO
+% KSVO_NU, KSVO, KSVC, MAPPINGS
+%
+% LITERATURE
+% 1. B.Scholkopf, A. Smola, Learning with kernels, MIT press, 2001,
+%    http://www.learning-with-kernels.org/.
+% 2. B. Haasdonk, Feature Space Interpretation of SVMs with Indefinite Kernels.
+%    IEEE Trans. on PAMI, 27(4):482-492, 2005.
+% 3. E. Pekalska, P. Paclik, R.P.W. Duin,  A Generalized Kernel Approach to
+%    Dissimilarity-based Classification, JMLR, vol.2, no.2, 175-211, 2002.
+
+
+% Copyright: Elzbieta Pekalska, Robert P.W. Duin, ela.pekalska@googlemail.com
+% Based on SVC.M by D.M.J. Tax, D. de Ridder and R.P.W. Duin and SVC_NU.M by S.Verzakov
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [W,J,reg,err,K] = ksvc(K,nu,kc,r,no)
+prtrace(mfilename);
+
+if nargin < 5,
+  % Multi-class problems are solved by one-vs-all by calling KSVC.
+  % no is the class number in such a situation; 0 is the standard 2-class case
+  no = 0;
+end
+if nargin < 4,
+  r = 0;
+end
+if nargin < 3,
+  kc = 1;
+end
+if nargin < 2 | isempty(nu),
+  nu = 0.25;
+  prwarning(3,'Regularization parameter NU set to 0.25\n');
+end
+if nargin < 1 | isempty(K),
+  W = mapping(mfilename,{nu,kc,r});
+  W = setname(W,'Kernel Support Vector Classifier (KSVC-NU)');
+  return;
+end
+
+
+if all(kc ~= [0 1]),
+  error('Wrong KC parameter.');
+end
+
+switch lower(r)
+  case {'flip', -1},  r = -1;
+  case {'', 0},       r = 0;
+  case {'reg', 1},    r = 1;
+  case {'lamreg', 2}, r = 2;
+  otherwise
+    error('Wrong parameter R.');
+end
+
+
+% TRAIN THE CLASSIFIER
+if ~isa(nu,'mapping')
+  islabtype(K,'crisp');
+  isvaldset(K,1,2);      % Expect at least 1 object per class and 2 classes
+  [m,k,c] = getsize(K);
+  if m ~=k,
+    error('The kernel is not a square matrix.');
+  end
+  nlab = getnlab(K);
+
+  % The SVC is basically a two-class classifier.
+  % Multi-class problems are trained one-versus-all.
+
+  if c == 2   % Two-class classifier
+  % Compute the parameters for the optimization:
+    y = 3 - 2*nlab;    % y = +1/-1
+
+    prec = 1e-12;
+    if ~issym(K,prec),
+      prwarning(1, 'The kernel is not symmetric. The values are averaged out.')
+      K = (K+K')/2;
+    end
+
+    if kc,   % Center the data
+      me = mean(+K,2)';                % Store the mean value
+
+      B = -repmat(1/m,m,m);
+      B(1:m+1:end) = B(1:m+1:end)+1;   % B = eye(m) - ones(m,m)/m
+      K = B*K*B;                       % K is now centered
+    else
+      me = [];
+    end
+    K = (K+K')/2;                      % K is averaged out as QP solver is sensitive to small asymmetry
+
+
+    % Check feasibility of the kernel:
+    if r == 0 & dmeans(K,y) < 0,
+      if no > 0,
+        ss = [num2str(no) '-vs-all '];
+      else,
+        ss = '';
+      end
+      prwarning(1,['The kernel is badly indefinite. The ' ss ' SVM cannot be defined. Pseudo-Fisher is computed instead.']);
+      err = 1;
+      v   = prpinv([K ones(m,1)])*y;
+      J   = [1:m]';
+      T   = [];
+      reg = [];
+    else
+      % Perform the optimization
+      [v,J,T,reg,err] = ksvo_nu(+K,y,nu,r);
+    end
+
+    % Store the results
+    W = mapping(mfilename,'trained',{me,J,T,v},getlablist(K),k,2);
+    %W = cnormc(W,a);
+    W = setname(W,'Kernel Support Vector Classifier (KSVC-NU)');
+    W = setcost(W,K);
+    % J = K.ident(J);
+
+  else   % MULTI-CLASS CLASSIFIER: C > 2
+
+    % MCLASSC cannot be used here as we have a kernel K
+    W = [];
+    J = zeros(m,1);
+    lablist = getlablist(K);
+
+    for i=1:c
+      lab = 2 - (nlab == i);   % lab = 1/2
+      KK  = setlabels(K,lab);
+      KK  = remclass(KK,0);
+      KK  = setfeatlab(K,lab);
+      if ~isempty(K.prior)
+        KK = setprior(KK,[K.prior(i),1-K.prior(i)]');
+      end
+      [V,j,reg(i),err(i)]= ksvc_nu(KK,nu,kc,r,i);
+      W = [W,setlabels(V(:,1),lablist(i,:))];
+      J(j) = 1;
+    end
+    J = find(J);
+  end
+
+else
+
+% EXECUTE THE CLASSIFIER
+  % nu is an SVM classifier now
+  n = size(K,1);
+  w = +nu;
+
+  % Get the parameters from the classifier
+  me = w{1};
+  J  = w{2};
+
+  % The first   % The first parameter w{1} stores the mean of the kernel.
+  % When it is non-empty, data centering should also be applied
+  % to the test kernel.
+
+  if ~isempty(me),
+    % Center the kernel
+    m = length(me);
+    B = -repmat(1/m,m,m);
+    B(1:m+1:end) = B(1:m+1:end) + 1;    % B = eye(m) - ones(m,m)/m
+    K = (K - me(ones(n,1),:)) * B;
+  end
+
+  if ~isempty(w{3}),   % this is the transformation that reverses the negative eigenvalues
+    K = K*w{3};
+  end
+
+  % The classifier is stored in w{4}
+  % Data is mapped by the kernel, now we just have a linear classifier  w*x+b:
+  d = [+K(:,J) ones(n,1)] * w{4};
+  d = sigm([d -d]);
+  W = setdat(K,d,nu);
+end
+
+return
+
+
+
+
+function dm = dmeans(K,y)
+% Computes the square pseudo-Euclidean distance between the
+% means of the two classes. This can be done by using the kernel only.
+% Negative value means that the contribution of the negative
+% subspace in the pseudo-Euclidean sense is too large.
+
+yy = y;
+Z  = find (y == 1);
+T  = find (y == -1);
+yy(Z) = 1/length(Z);
+yy(T) = -1/length(T);
+dm    = yy'*(+K)*yy;
+return;
Index: distools/ksvo.m
===================================================================
--- distools/ksvo.m	(revision 10)
+++ distools/ksvo.m	(revision 10)
@@ -0,0 +1,200 @@
+%KSVO Kernel Support Vector Optimizer
+%
+%   [V,J,T,REG] = KSVO(K,Y,C,R)
+%
+% INPUT
+%   K   Kernel or a square similarity matrix
+%   Y   Label list consisting of -1/+1
+%   C   Scalar for weighting the errors (optional; default: 1)
+%   R   Parameter: -1,0,1,2
+%       -1 or 'flip',   Changes the kernel by flipping negative eigenvalues to
+%          positive
+%        0 or '',       Uses the kernel as it is
+%        1 or 'reg',    Checks positive definiteness and regularizes the kernel by
+%          adding the minimal constant in the form of 10^i to the diagonal
+%        2 or 'lamreg', Checks positive definiteness and regularizes the kernel by
+%          adding the minimal constant to the diagonal (equal to the magnitude of
+%          the smallest negative eigenvalue)
+%       (optional; default: 0, do not change the kernel)
+%
+% OUTPUT
+%   V   Vector of weights for the support vectors
+%   J   Index vector pointing to the support vectors
+%   T   Transformation matrix for the test kernel; to be used in testing
+%   REG Regularization parameter added to the diagonal, if used (R=1,2); a vector
+%       of eigenvalues of K (R=-1), or -1 if not checked (R=0)
+%
+% DESCRIPTION
+% A low level routine that optimizes the set of support vectors for a two-class
+% classification problem based on the kernel or similarity matrix K. KSVO is called
+% directly from KSVC. The labels Y should indicate the two classes by +1 and -1.
+% Optimization is done by a quadratic programming. If available, the QLD function
+% is used for a positive definite kernel, otherwise an appropriate Matlab routine.
+%
+% SEE ALSO
+% KSVC, SVC, SVO
+
+% Copyright: Elzbieta Pekalska, Robert P.W. Duin, ela.pekalska@googlemail.com
+% Based on SVC.M by D.M.J. Tax, D. de Ridder and R.P.W. Duin
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [v,J,T,reg,err] = ksvo(K,y,C,r)
+prtrace(mfilename);
+
+if (nargin < 4),
+  r = 0;      % Default: the kernel is used as provided
+end
+if (nargin < 3)
+  prwarning(3,'Third parameter not specified, assuming 1.');
+  C = 1;
+end
+
+if all(r ~= [-1,0,1,2]),
+  error('Wrong parameter R.');
+end
+
+err  = 0;
+v    = [];     % Weights of the SVM
+J    = [];     % Index of support vectors
+reg = -1;      % Regularization on the diagonal or a list of eigenvalues, if used; -1, if not checked
+vmin = 1e-9;   % Accuracy to determine when an object becomes the support object
+iacc = -14;    % Accuracy of 10^i to determine whether the kernel is pd or not
+T    = [];     % Matrix to transform the test kernel if r = -1
+
+% Set up variables for the optimization.
+n  = size(K,1);
+Ky = (y*y').*K;
+f  = -ones(1,n);
+A  = y';
+b  = 0;
+lb = zeros(n,1);
+ub = repmat(C,n,1);
+p  = rand(n,1);
+
+
+if r ~= 0,
+  % Find whether the kernel is positive definite.
+  i = -20;
+  while (pd_check (Ky + (10.0^i) * eye(n)) == 0)
+    i = i + 1;
+  end
+
+  if r == 1,
+    if i > iacc,  % if i is smaller, then the regularization is within numerical accuracy
+      prwarning(1,'K is not positive definite. The diagonal is regularized by 10.0^(%d)',i);
+    end
+
+    % Make the kernel positive definite by adding a constant to the diagonal.
+    reg = 10.0^i;
+    Ky  = Ky + (10.0^(i)) * eye(n);
+
+  elseif r == 2,
+    L = preig(Ky);
+    L = diag(real(L));
+    I = find(L < 0);
+    if ~isempty(I),
+      % Make the kernel positive definite by adding a constant to the diagonal.
+      reg = -1.001*min(L(I));
+      Ky  = Ky + reg * eye(n);
+      pow = round(log10(reg));
+      if pow >= 0
+        prwarning(1,['K is not positive definite. The diagonal is regularized by %' num2str(pow) '.2f'],reg);
+      elseif pow > iacc,
+        prwarning(1,['K is not positive definite. The diagonal is regularized by %0.3g'], reg);
+      else
+        ;
+      end
+    else
+      reg = 0;
+    end
+
+  else   % r = -1,
+    % reverse the negative eigenvalues of the kernel K
+    if i >= iacc,
+      [Q,L] = preig(K);
+      Q     = real(Q);
+      L     = diag(real(L));
+      reg   = L;
+      if all(L >= 0),
+        T = [];
+      else
+        K   = Q*diag(abs(L))*Q';
+        Ky  = (y*y').*K;
+        T   = Q* diag(sign(L)) *Q';   % transformation matrix for the test kernel
+      end
+    else
+      % if i < iacc, then the regularization is within numerical accuracy, so apply it
+      Ky    = Ky + (10.0^(i)) * eye(n);
+    end
+  end
+end
+
+
+% Minimization procedure
+% QP  minimizes:   0.5 x'*Ky*x + f'x
+% subject to:      Ax <= b
+%
+
+done = 0;
+if r ~= 0 & (exist('qld') == 3)
+  prwarning(5,'QLD routine is used.')
+  v = qld (Ky, f, -A, b, lb, ub, p, 2);
+  done = 1;
+end
+
+if r == 0 | ~done,
+  if (exist('quadprog') == 2)
+    prwarning(5,'Matlab QUADPROG is used.')
+    opt = optimset;
+    opt.Diagnostics = 'off';
+    opt.LargeScale  = 'off';
+    opt.Display     = 'off';
+    opt.MaxIter     = 500;
+    v = quadprog(Ky, f, [], [], A, b, lb, ub,[],opt);
+  else
+    error(5,'KSVC requires Matlab 6.x')
+  end
+end
+
+
+
+% Compute the square pseudo-norm of the weights in the corresponding
+% Hilbert/Krein space. If it is negative (which may happen for a highly
+% indefinite kernel), then the SVM is not proper.
+
+vnorm = v'*Ky*v;
+if vnorm < 0 | abs(vnorm) < 10^iacc,
+  prwarning(1,'SVM: ||w||^2_PE < 0. The SVM is not properly defined. Pseudo-Fisher is computed instead.');
+  err = 1;
+  v   = prpinv([K ones(n,1)])*y;
+  J   = [1:n]';
+  return;
+end
+
+
+% Find all support vectors SVs.
+J = find(v > vmin);
+
+% First find the SVs on the boundary
+I  = find((v > vmin) & (v < C-vmin));
+Ip = find(y(I) ==  1);
+Im = find(y(I) == -1);
+
+if (isempty(v) | isempty(Ip) | isempty(Im))
+  prwarning(1,'Quadratic Optimization failed. Pseudo-Fisher is computed instead.');
+  err = 1;
+  v   = prpinv([K ones(n,1)])*y;
+  J   = [1:n]';
+  return;
+end
+
+
+v = y.*v;
+
+% Find the output for the SVs:
+out = y(I)-(K(I,J)*v(J));
+b   = mean(out);
+v   = [v(J); b];
+return;
Index: distools/ksvo_nu.m
===================================================================
--- distools/ksvo_nu.m	(revision 10)
+++ distools/ksvo_nu.m	(revision 10)
@@ -0,0 +1,227 @@
+%KSVO_NU Kernel Support Vector Optimizer: NU algorithm
+%
+%   [V,J,C,REG] = KSVO_NU(K,Y,NU,PD)
+%
+% INPUT
+%   K   Kernel matrix
+%   Y   Label list consisting of -1/+1
+%   NU  Regularization parameter (0 < NU < 1):
+%       expected fraction of support vectors (optional; default: 0.25)
+%   R   Parameter: -1,0,1,2
+%       -1 or 'flip',   Changes the kernel by flipping negative eigenvalues to
+%          positive
+%        0 or '',       Uses the kernel as it is
+%        1 or 'reg',    Checks positive definiteness and regularizes the kernel by
+%          adding the minimal constant in the form of 10^i to the diagonal
+%        2 or 'lamreg', Checks positive definiteness and regularizes the kernel by
+%          adding the minimal constant to the diagonal (equal to the magnitude of
+%          the smallest negative eigenvalue)
+%       (optional; default: 0, do not change the kernel)
+%
+% OUTPUT
+%   V   Vector of weights for the support vectors
+%   J   Index vector pointing to the support vectors
+%   T   Transformation matrix for the test kernel; to be used in testing
+%   REG Regularization parameter added to the diagonal, if used (R=1,2); a vector
+%       of eigenvalues of K (R=-1), or -1 if not checked (R=0)
+%
+% DESCRIPTION
+% A low level routine that optimizes the set of support vectors for a two-class
+% classification problem based on the kernel or similarity matrix K.
+% KSVO_NU is called directly from KSVC_NU. The labels Y should indicate the
+% two classes by +1 and -1. Optimization is done by a quadratic programming.
+% If available, the QLD function is used for a positive definite kernel,
+% otherwise an appropriate Matlab routine.
+%
+% NU is bounded from above by NU_MAX = (1 - ABS(Lp-Lm)/(Lp+Lm)), where Lp (Lm)
+% is the number of positive (negative) samples. If NU > NU_MAX is supplied,
+% it will be changed to the NU_MAX.
+%
+% If NU is less than some NU_MIN which depends on the overlap between the
+% classes, the algorithm will typically take long time to converge (if at all).
+% So, it is advisable to set NU larger than the expected overlap.
+% Weights V are rescaled in such a way as if returned by KSVO with the
+% parameter C.
+%
+% SEE ALSO
+% KSCV_NU, KSVC, KSVO, SVO
+
+% Copyright: Elzbieta Pekalska, Robert P.W. Duin, ela.pekalska@googlemail.com
+% Based on SVC.M by D.M.J. Tax, D. de Ridder and R.P.W. Duin and SVC_NU.M by S.Verzakov
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [v,J,T,reg,err] = ksvo_nu(K,y,nu,r)
+
+prtrace(mfilename);
+
+if (nargin < 4),
+  r = 0;      % Default: the kernel is used as provided
+end
+if (nargin < 3)
+  prwarning(3,'Third parameter (nu) not specified, assuming 0.25.');
+  nu = 0.25;
+end
+
+if all(r ~= [-1,0,1,2]),
+  error('Wrong parameter R.');
+end
+
+nu_max = 1 - abs(nnz(y == 1) - nnz(y == -1))/length(y);
+if nu > nu_max
+  prwarning(3,['nu==' num2str(nu)  ' is not feasible; set to ' num2str(nu_max)]);
+  nu = nu_max;
+end
+
+err  = 0;
+v    = [];     % Weights of the SVM
+J    = [];     % Index of support vectors
+reg = -1;      % Regularization on the diagonal or a list of eigenvalues, if used; -1, if not checked
+vmin = 1e-9;   % Accuracy to determine when an object becomes the support object
+iacc = -14;    % Accuracy of 10^i to determine whether the kernel is pd or not
+T    = [];     % Matrix to transform the test kernel if r = -1
+
+
+% Set up the variables for the optimization.
+n  = size(K,1);
+Ky = (y*y').*K;
+f  = zeros(1,n);
+A  = [ones(1,n); y'];
+b  = [nu*n; 0];
+lb = zeros(n,1);
+ub = ones(n,1);
+p  = rand(n,1);
+
+
+if r ~= 0,
+  % Find whether the kernel is positive definite.
+  i = -20;
+  while (pd_check (Ky + (10.0^i) * eye(n)) == 0)
+    i = i + 1;
+  end
+
+  if r == 1,
+    if i > iacc,  % if i is smaller, then the regularization is within numerical accuracy
+      prwarning(1,'K is not positive definite. The diagonal is regularized by 10.0^(%d)',i);
+    end
+
+    % Make the kernel positive definite by adding a constant to the diagonal.
+    reg = 10.0^i;
+    Ky  = Ky + (10.0^(i)) * eye(n);
+
+  elseif r == 2,
+    L = preig(Ky);
+    L = diag(real(L));
+    I = find(L < 0);
+    if ~isempty(I),
+      % Make the kernel positive definite by adding a constant to the diagonal.
+      reg = -1.001*min(L(I));
+      Ky  = Ky + reg * eye(n);
+      pow = round(log10(reg));
+      if pow >= 0
+        prwarning(1,['K is not positive definite. The diagonal is regularized by %' num2str(pow) '.2f'],reg);
+      elseif pow > iacc,
+        prwarning(1,['K is not positive definite. The diagonal is regularized by %0.3g'], reg);
+      else
+        ;
+      end
+    else
+      reg = 0;
+    end
+
+  else   % r = -1,
+    % reverse the negative eigenvalues of the kernel K
+    if i > iacc,
+      [Q,L] = preig(K);
+      Q     = real(Q);
+      L     = diag(real(L));
+      if all(L >= 0),
+        T = [];
+      else
+        K   = Q*diag(abs(L))*Q';
+        Ky  = (y*y').*K;
+        T   = Q* diag(sign(L)) *Q';   % transformation matrix for the test kernel
+      end
+    else
+      % if i < iacc, then the regularization is within numerical accuracy, so apply it
+      Ky    = Ky + (10.0^(i)) * eye(n);
+    end
+  end
+end
+
+
+
+% Minimization procedure
+% QP  minimizes:   0.5 x'*Ky*x + f'x
+% subject to:      Ax <= b
+%
+
+
+done = 0;
+if r ~= 0 & (exist('qld') == 3)
+  prwarning(5,'QLD routine is used.')
+  v = qld (Ky, f, -A, b, lb, ub, p, 2);
+  done = 1;
+end
+
+if r == 0 | ~done,
+  if (exist('quadprog') == 2)
+    prwarning(5,'Matlab QUADPROG is used.')
+    opt = optimset;
+    opt.Diagnostics = 'off';
+    opt.LargeScale  = 'off';
+    opt.Display     = 'off';
+    opt.MaxIter     = 500;
+    v = quadprog(Ky, f, [], [], A, b, lb, ub,[],opt);
+  else
+    error(5,'KSVC requires Matlab 6.x')
+  end
+end
+
+
+% Compute the square pseudo-norm of the weights in the corresponding
+% Hilbert/Krein space. If it is negative (which may happen for a highly
+% indefinite kernel), then the SVM is not proper.
+
+vnorm = v'*Ky*v;
+if vnorm < 0 | abs(vnorm) < 10^iacc,
+  prwarning(1,'SVM: ||w||^2_PE < 0. The SVM is not properly defined. Pseudo-Fisher is computed instead.');
+  err = 1;
+  v   = prpinv([K ones(n,1)])*y;
+  J   = [1:n]';
+  return;
+end
+
+
+% Find all the support vectors.
+J = find(v > vmin);
+
+% First find the SV on the boundary
+I  = J(v(J) < 1-vmin);
+Ip = find(y(I) ==  1);
+Im = find(y(I) == -1);
+if (isempty(v) | isempty(Ip) | isempty(Im))
+  prwarning(1,'Quadratic Optimization failed. Pseudo-Fisher is computed instead.');
+  v = prpinv([K ones(n,1)])*y;
+  J = [1:n]';
+  C = nan;
+  err = 1;
+  return;
+end
+
+
+
+v    = y.*v;
+wxI  = K(I,J)*v(J);
+wxIp = mean(wxI(Ip),1);
+wxIm = mean(wxI(Im),1);
+
+rho  = 0.5*(wxIp-wxIm);
+b    = - (0.5/rho)*(wxIp+wxIm);
+%b = mean(y(I) - wxI/rho);
+
+v = [v(J)/rho; b];
+C = 1/rho;
+
+return;
Index: distools/lpdistm.m
===================================================================
--- distools/lpdistm.m	(revision 10)
+++ distools/lpdistm.m	(revision 10)
@@ -0,0 +1,124 @@
+%LPDISTM  l_p (p > 0) (Non)-Metric Distance Matrix
+%
+%     D = LPDISTM (A,B,P)
+%       OR
+%     D = LPDISTM (A,B)
+%       OR
+%     D = LPDISTM (A,P)
+%       OR
+%     D = LPDISTM (A)
+%
+% INPUT
+%   A   NxK Matrix or dataset
+%   B   MxK Matrix or dataset
+%   P   Parameter, P > 0
+%
+% OUTPUT
+%   D   NxM Dissimilarity matrix or dataset
+%
+% DESCRIPTION
+% Computation of the distance matrix D between two sets of vectors, A and B.
+% Distances between vectors X and Y are computed using the lp distance:
+%     d(X,Y) = (sum (|X_i - Y_i|.^P))^(1/P)
+%                i
+% If P = Inf, then the max-norm distance is computed:
+%     d(X,Y) = max (|X_i - Y_i|)
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% DEFAULT
+%   P = 1
+%   B = A
+%
+% REMARKS
+%   P >= 1      => D is metric
+%   P in (0,1)  => D is non-metric; D.^P is metric and l1-embeddable
+%   P = 1/2     => D is city block / Euclidean distance
+%
+% SEE ALSO
+%   FLPDISTM, EUDISTM
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function D = lpdistm (A,B,p)
+
+bisa = 0;
+if nargin < 2,
+  p = 1;
+  B = A;
+  bisa = 1;
+else
+  if nargin < 3,
+    if max (size(B)) == 1,
+      p = B;
+      B = A;
+      bisa = 1;
+    else
+      p = 1;
+    end
+  end
+end
+
+if p <= 0,
+  error ('The parameter p must be positive.');
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a    = +A;
+b    = +B;
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+
+if ca ~= cb,
+  error ('The matrices should have the same number of columns.');
+end
+
+
+D = zeros(ra,rb);
+if p < Inf,
+  for i=1:rb
+    %if ~rem(i,50), fprintf('.'); end
+    D(:,i) = sum(abs(repmat(b(i,:),ra,1) - a).^p,2);
+  end
+else
+  for i=1:rb
+    %if ~rem(i,50), fprintf('.'); end
+    D(:,i) = max(abs(repmat(b(i,:),ra,1) - a),[],2);
+  end
+end
+
+
+%fprintf('\n');
+if p < Inf,
+  D = D.^(1/p);
+end
+
+% Check numerical inaccuracy
+D (find (D < eps)) = 0;   % Make sure that distances are nonnegative
+if bisa,
+  D = 0.5*(D+D');         % Make sure that distances are symmetric for D(A,A)
+end
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/makesym.m
===================================================================
--- distools/makesym.m	(revision 10)
+++ distools/makesym.m	(revision 10)
@@ -0,0 +1,30 @@
+%MAKESYM Make a matrix symmetric
+%
+%   [B,C] = MAKESYM(A)
+%
+% INPUT
+%   A   Dataset or matrix
+%
+% OUTPUT
+%   B   Symmetric dataset or matrix computed as (A+A')/2
+%   C   Asymmetric remaining part, dataset or matrix computed as (A-A')/2
+%
+% DESCRIPTION
+% B is a symmetric matrix obtained by averiging values of A.
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% EWI Faculty, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [d1,d2] = makesym(d)
+[m,k] = size(d);
+if m ~= k,
+  error ('Matrix should be square.')
+end
+d1 = 0.5 * (d + d');
+if nargout == 2,
+  d2 = 0.5 * (d - d');
+end
+return
Index: distools/marksize.m
===================================================================
--- distools/marksize.m	(revision 10)
+++ distools/marksize.m	(revision 10)
@@ -0,0 +1,17 @@
+%MARKSIZE Change markersize in lineplot or scatterplot
+%
+%	marksize(size,marker)
+%
+% The marker fontsize (default set by matlab to 6) is reset
+% to size for the given marker, default: all markers.
+% 
+function marksize(siz,marker)
+if nargin == 1, marker = ' '; end
+h = get(gca,'Children')';
+for i = h
+	if strcmp(get(i,'Type'),'line')
+		if nargin == 1 | get(i,'Marker') == marker
+			set(i,'MarkerSize',siz);
+		end
+	end
+end
Index: distools/mclassdc.m
===================================================================
--- distools/mclassdc.m	(revision 10)
+++ distools/mclassdc.m	(revision 10)
@@ -0,0 +1,147 @@
+%MCLASSDC Multi-Class Dissimilarity-based Classifier from Two-Class Discriminants
+%
+% 	W = MCLASSDC(D,CLASSF,MODE)
+%
+% INPUT
+%   D       Dissimilarity dataset
+%   CLASSF  Untrained dissimilarity-based classifier
+%   MODE	Way of handling multi-class problems: 'SINGLE' or 'MULTI' 
+% 			(optional; default: 'SINGLE')
+%
+% OUTPUT
+%   W       Combined classifier
+%
+% DEFAULT
+%   MODE = 'SINGLE'
+% 
+% DESCRIPTION
+% For the default MODE = 'SINGLE', the untrained classifier CLASSF is called to
+% compute C classifiers between each of the C classes in the dataset D and
+% the remaining C-1 classes. The result is stored into the combined
+% classifier W. There is no combining rule added. The default rule, MAXC
+% might be replaced by adding one, e.g. W = W*MEANC.
+%
+% For the MODE = 'MULTI', the untrained classifier CLASSF is trained between 
+% all pairs of classes as well as between each class and all other classes.
+% This total set of C^2 classifiers is combined by MINC.	The use of soft labels
+% is supported.
+% The pairwise classifiers are trained by using a representation set based
+% on the traing objects of the corresponding classes only (just in case of
+% crisp labels). This is the only difference with the use of MCLASSC. 
+%
+% EXAMPLE
+% W = MCLASSDC(DISTM(GENDATM(100)),QDC([],0.01),'MULTI')
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, MAXC, MINC
+
+% Copyright: R.P.W. Duin, r.duin@ieee.org
+% Faculty EWI, Delft University of Technology 
+
+
+function varargout = mclassdc(D,classf,mode)
+
+prtrace(mfilename);
+if nargin < 3, 
+	mode = 'single'; 
+end
+if nargin < 2, 
+	classf = []; 
+end
+if nargin < 1 | isempty(D)
+	w = mapping(mfilename,{classf,mode});
+	return
+end
+	
+if ~ismapping(classf) | ~isuntrained(classf)
+	error('Second parameter should be an untrained mapping.')
+end
+
+islabtype(D,'crisp','soft');
+isvaldset(D,1,2); 	% At least 1 object per class and two classes
+
+[m,k,c] = getsize(D);
+	
+varout = {};
+if c == 2
+	varargout = map(D,classf);
+	return
+end
+lablist = getlablist(D);
+
+
+switch lower(mode)
+	case 'single'
+		w = [];
+	  %	lablist = getlablist(D);
+	  for i=1:c
+			if islabtype(D,'crisp')
+			  mlab = 2 - (getnlab(D) == i);
+			  DD = setlabels(D,mlab);
+		  elseif islabtype(D,'soft')
+			  Dtargets = gettargets(D);
+			  targets  = [Dtargets(:,i) 1-Dtargets(:,i)]; 
+			  DD			 = dataset(+D,mlab,targets,'lablist',[1 2]');
+		  end
+			if nargout(classf.mapping_file) > 1
+		 	 	[v,varo] = map(DD,classf);
+				varout   = [varout {varo}];
+			else
+				v = map(DD,classf);
+			end
+			w = [w,setlabels(v(:,1),lablist(i,:))];
+	  end
+
+
+	case 'multi'
+		w = [];
+	  nlab = getnlab(D);
+		[nl,clab,list] = renumlab(getlablist(D),getfeatlab(D));
+	  for z=1:c
+		  lab = lablist(z,:);
+		  
+		  J1 = find(nlab==z);
+		  L1 = find(clab==z);
+		  if islabtype(D,'crisp')
+			  mlab     = ones(m,1);
+			  mlab(J1) = zeros(length(J1),1);
+			  DD       = setlabels(D,mlab);
+		  else
+			  problab  = gettargets(D);
+			  mlab     = [problab(:,i1) sum(problab,2)-problab(:,z)];
+			  DD       = settargets(D,mlab,[1 2]');
+		  end		
+		  I1 = setdiff([1:c],z);
+			if nargout(classf.mapping_file) > 1
+		 	 	[v,varo] = map(DD,classf);
+				varout   = [varout {varo}];
+			else
+				v = map(DD,classf);
+			end
+			w = [w,setlabels(v(:,1),lab)];
+
+		  for t = I1 
+			  if islabtype(D,'crisp')
+				  J2 = find(nlab==t);
+				  L2 = find(clab==t);
+				  v  = featsel(k,[L1;L2])*(DD([J1;J2],[L1;L2])*classf);
+					%disp([z,t]);
+					%parsc(v);
+			  else
+				  mlab2 = problab(:,[z t]);
+				  v     = setlabels(DD,mlab2)*classf;
+			  end
+			  w = [w,setlabels(v(:,1),lab)];
+		  end
+	  end
+	  w = minc(w);
+		
+	otherwise
+	  error('Unknown mode')
+end
+
+w = setname(w,getname(classf));
+w = setsize(w,[k,c]);
+w = setcost(w,D);
+varargout = {w varout};
+return
Index: distools/mstplot.m
===================================================================
--- distools/mstplot.m	(revision 10)
+++ distools/mstplot.m	(revision 10)
@@ -0,0 +1,59 @@
+%MSTPLOT Plot minimum spanning trees
+%
+%   MSTPLOT (A,L)
+%
+% INPUT
+%   A   Nx2 or Nx3 Data matrix
+%   L   List of edges belonging to one or more minimum spanning trees
+%
+% DESCRIPTION
+% Plots data and edges in the minimum spanning trees. Applicable only
+% for 2D or 3D data. L can be found by KMST. If A is unknown, but
+% dissimilarity data are given, then a 2D or 3D approximation can be
+% found by PSEM.
+%
+% SEE ALSO
+% KMST, PSEM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function mstplot (A,L)
+A = +A;
+[n,m] = size(A);
+
+len = length(L);
+K   = round (len/(n-1));
+
+if m == 2,
+  plot(A(:,1),A(:,2),'.r')
+  text(A(:,1),A(:,2),num2str([1:n]'));
+  grid on;
+  hold on;
+  for i=1:len
+    plot([A(L(i,1),1) A(L(i,2),1)],[A(L(i,1),2) A(L(i,2),2)],'k');
+  end
+
+elseif m == 3,
+
+  plot3(A(:,1),A(:,2),A(:,3),'.r')
+  text(A(:,1),A(:,2),A(:,3),num2str([1:n]'));
+  grid on;
+  hold on;
+  for i=1:len
+    plot3([A(L(i,1),1) A(L(i,2),1)],[A(L(i,1),2) A(L(i,2),2)],[A(L(i,1),3) A(L(i,2),3)],'k');
+  end
+else
+  error('Plotting is only possible for two or three variables.');
+  return;
+end
+
+hold off
+if K == 1,
+  title('Minimum Spanning Tree');
+else
+  title([num2str(K) ' Minimum Spanning Trees']);
+end
+return;
Index: distools/nef.m
===================================================================
--- distools/nef.m	(revision 10)
+++ distools/nef.m	(revision 10)
@@ -0,0 +1,36 @@
+%NEF Compute Negative Eigen Fraction from dataset or mapping
+%
+%   F = NEF(D)
+%   F = NEF(W)
+%
+% INPUT
+%   D   - Dissimilarity matrix
+%   W   - Pseudo-Euclidean mapping
+%
+% OUTPUT
+%   F   - Negative eigenfraction
+%
+% DESCRIPTION
+% The  Negative eigenfraction is a ratio expressing the sum of 
+% magnitudes of all negative eigenvalues divided by the sum of 
+% magnitudes of all eigenvalues. The necessary numbers are 
+% stored in W = PE_EM(D). W is computed from D is needed.
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, PE_EM, CHECKEUCL 
+
+function f = nef(input)
+
+if isdataset(input)
+	w = pe_em(input);
+elseif ~ismapping(input)
+	error('Input should be dataset or mapping')
+else
+	w = input;
+end
+
+eval = abs(getdata(w,'eval'));
+sig  = getdata(w,'sig');
+f = 1-sum(eval(1:sig(1)))/sum(eval);
+
+
Index: distools/nhgraph.m
===================================================================
--- distools/nhgraph.m	(revision 10)
+++ distools/nhgraph.m	(revision 10)
@@ -0,0 +1,124 @@
+%NHGRAPH Find a neighborhood graph and its shortest paths
+%
+%   [NG,L,DL,D] = NHGRAPH(A,OPT,PAR)
+%
+% INPUT
+%   A   NxN Weight (dissimilarity) matrix/dataset representing a weighted graph
+%   OPT Option method (optional; default: 'MST')
+%       'NN'     - based on nearest neighbor neighborhoods
+%       'MST'    - based on minimum spanning trees (MSTs)
+%       'EPS'    - based on eps-neighborhoods
+%       'MST-NN' - based on a single MST followed by nearest neighbor neighborhoods
+%       'MST-EPS'- based on a single MST followed by eps-neighborhoods
+%   PAR Parameter (optional; default: 3 for 'NN' and 'MST-NN'; 1 for 'MST';
+%       0.1*avr(W) for 'EPS' and 'MST-EPS')
+%       Integer K, 1<=K<N, for 'NN', 'MST-NN'
+%       Integer K, 1<=K<N, for 'MST'
+%       Real positive value for 'EPS', 'MST-EPS'
+%
+% OUTPUT
+%   NG  NxN Weight matrix (dataset) representing the neighborhood graph
+%   L   List of edges in the neighborhood graph
+%   DL  List of edge weights of the neighborhood graph
+%   D   NxN matrix of shortest paths
+%
+% DESCRIPTION
+% Finds a neighborhood graph for the graph described by the weight matrix A.
+% A is NxN matrix representing a graph G(V,E). V is a set of vertices, |V| = N,
+% and E is a set of edges. If there is no edge between i and j then A(i,j) = INF.
+%
+% DEFAULT
+%   M   = 'MST'
+%   PAR = 3 ('NN','MST-NN'), 1 ('MST') or 0.1*avr(W) ('EPS','MST-EPS')
+%
+% SEE ALSO
+% KMST, DSPATH, DSPATHS
+
+% Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty of EWI, Delft University of Technology, The Netherlands and
+% School of Computer Science, University of Manchester 
+
+
+function [V,L,DL,D] = nhgraph(A,opt,par)
+
+if nargin < 2 | isempty(opt),
+  opt = 'MST';
+end
+
+opt = upper(opt);
+if nargin < 3 | isempty(par),
+  switch opt
+    case 'MST', par = 1;
+    case {'MST','NN','MST-NN'}, par = 3;
+    case {'EPS','MST-EPS'}, par = 0.1*mean(A(:));
+    otherwise
+			error(['Wrong method', opt]);
+  end
+end
+
+
+V = +A;
+[n,m] = size(V);
+if n~= m,
+  error('Weight matrix A should be square.');
+end
+
+
+L  = [];
+DL = [];
+switch opt
+  case 'MST'
+    [L,DL,V] = kmst(V,par);
+
+  case {'NN', 'MST-NN'}
+    K = par;
+    if K ~= round(K) | K < 2 | K >= n,
+      error ('K should be the number of nearest neighbors.');
+    end
+    if strcmp(opt,'MST-NN'),
+      [L,DL,V] = kmst(V,1);
+    end
+    [VV,I] = sort(V);
+    for i=1:n
+      V(i,I((2+K):end,i)) = inf;
+    end
+    if nargout > 1,
+      for i=1:n
+        L  = [L; i*ones(K,1) I(2:1+K,i)];
+        DL = [DL; VV(i,I(2:1+K,i))'];
+      end
+    end
+
+  case {'EPS','MST-EPS'}
+    if strcmp(opt,'MST-EPS')
+      [L,DL,V] = kmst(V,1);
+    end
+    deps = par;
+    if deps <= 0,
+      error ('EPS should be positive.');
+    end
+    warning off;
+    V = V./(V <= deps);
+    V = min(V,inf);
+    if nargout > 1,
+      [I J] = find(V < inf);
+      L  = [L; I J];
+      DL = [DL; V(J*(n-1)+I)];
+    end
+    warning on;
+  otherwise
+    error('Unknown method.')
+end
+
+LL = [L; L(:,[2 1])];
+V  = inf*ones(n,m);
+V((LL(:,2)-1)*n+LL(:,1)) = +A((LL(:,2)-1)*n+LL(:,1));
+
+if isdataset(A),
+  V = setdata(A,V);
+end
+
+if nargout > 3,
+  D = dspaths(V);
+end
+return;
Index: distools/nne.m
===================================================================
--- distools/nne.m	(revision 10)
+++ distools/nne.m	(revision 10)
@@ -0,0 +1,36 @@
+%NNE Leave-one-out Nearest Neighbor Error on a Dissimilarity Matrix
+%
+%   [E,LAB] = NNE(D)
+%
+% INPUT
+%   D   NxN symmetric dissimilarity dataset
+%
+% OUTPUT
+%   E   Leave-one-out error
+%   LAB Nearest neighbor labels
+%
+% DESCRIPTION
+% Estimates the leave-one-out error of the 1-nearest neighbor rule
+% on the givven symmetric dissimilairy data.
+%
+
+% Copyright: Robert P.W. Duin, r.p.w.duin@prtools.org and
+% Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [e,NNlab] = nne(D)
+
+[m,n] = size(D);
+if m ~= n,
+  error('Distance matrix should be square.');
+end
+
+lab = getlab(D);
+[nlab,lablist] = renumlab(lab);
+D(1:m+1:end)   = inf;
+[d,M] = min(D');
+e     = mean(nlab(M) ~= nlab);
+NNlab = lablist(nlab(M),:);
+return;
Index: distools/nnerr.m
===================================================================
--- distools/nnerr.m	(revision 10)
+++ distools/nnerr.m	(revision 10)
@@ -0,0 +1,94 @@
+%NNERR Exact expected NN error from a dissimilarity matrix (1)
+%
+%   E = NNERR(D,M)
+%
+% INPUT
+%   D 	NxN dissimilarity dataset
+%   M 	Vector with desired umber of objects to be selected
+%
+% OUTPUT
+%   E 	Expected NN errror
+%
+%   E = NNERR(D)
+%
+% In this case a set of training set sizes is used to produce
+% a full learning curve. E can be plotted by PLOTE.
+%
+% DESCRIPTION
+% An exact computation is made of the expected NN error for a random 
+% selection of M objects for training. D should be a dataset containing 
+% a labeled square dissimilarity matrix.
+%
+
+% Copyright: R.P.W. Duin, r.duin@ieee.org
+% and Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+function e = nnerr(d,n)
+
+  if nargin < 2, n = []; end
+	m = size(d,2);
+	if nargin == 2 & any(n >= m)
+		error('Training set sizes should be smaller than sample size')
+	end
+	
+	if isempty(n)
+		% find full curve, but gain some speed
+		L = [1:20 22:2:40 45:5:60 70:10:100 120:20:300 350:50:1000 1100:100:10000];
+		L = [L(find(L<m-1)) m-1];
+		f = zeros(1,m-1);
+		prwaitbar(max(L),'Compute Learning Curve')
+		for i=1:length(L)
+			prwaitbar(max(L),L(i));
+			f(L(i)) = feval(mfilename,d,L(i));
+			if (i > 1) & (L(i)-L(i-1) > 1)
+				for n=L(i-1):L(i)
+					f(n) = f(L(i-1)) + (f(L(i))-f(L(i-1)))*(n-L(i-1))/(L(i)-L(i-1));
+				end
+			end
+		end
+		prwaitbar(0)
+    
+    e.error = f;
+    e.xvalues = [1:length(e.error)];
+    e.title = 'Learning curve 1-NN rule';
+    e.xlabel = 'Size training set';
+    e.ylabel = 'Expected classification error';
+    e.plot = 'semilogx';
+	
+  elseif length(n) > 1
+        
+		for i=1:length(n)
+			e(i) = feval(mfilename,d,n(i));
+    end
+
+  else
+	
+    q = zeros(1,m);
+    for k = 1:m-n
+      %p(k) = (prod(m-k+1-n+1:m-k+1) - prod(m-k-n+1:m-k)) / prod(m-n+1:m);
+      q(k) = (exp(gamln(m-k+2)-gamln(m-k+1-n+1)-gamln(m+1)+gamln(m-n+1)) ...
+		     - exp(gamln(m-k+1)-gamln(m-k-n+1)-gamln(m+1)+gamln(m-n+1)));
+    end
+    k = m-n+1;
+    %p(k) = (prod(m-k+1-n+1:m-k+1) - prod(m-k-n+1:m-k)) / prod(m-n+1:m);
+    q(k) = (exp(gamln(m-k+2)-gamln(m-k+1-n+1)-gamln(m+1)+gamln(m-n+1)));
+	
+    isdataset(d);
+    nlab     = getnlab(d);
+    d = d + diag(repmat(inf,1,m));
+    [DD,L] = sort(+d,2);			% sort distances
+    L = nlab(L);
+    R = mean(L ~= repmat(nlab,1,m));
+    e = q*R';
+
+  end
+    
+return
+
+function x = gamln(y)
+	if y == 0, x = 1; 
+	elseif y < 0, x = 1;
+	else, x = gammaln(y); end
+return
Index: distools/nnerror.m
===================================================================
--- distools/nnerror.m	(revision 10)
+++ distools/nnerror.m	(revision 10)
@@ -0,0 +1,105 @@
+%NNERROR Exact expected NN error from a dissimilarity matrix (2)
+%
+%   E = NNERROR(D,M)
+%
+% INPUT
+%   D 	NxN dissimilarity dataset
+%   M 	Number of objects to be selected per class (optional)
+%
+% OUTPUT
+%   E 	Expected NN errror 
+%
+% DEFAULT
+%   M = minimum class size minus 1
+%
+% DESCRIPTION
+% An exact computation is made of the expected NN error for a random 
+% selection of M for training. D should be a dataset containing a labeled 
+% square dissimilarity matrix.
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+
+function e = nnerror(D,n)
+isdataset(D);
+discheck(D);
+nlab     = getnlab(D);
+[m,mm,c] = getsize(D);
+
+% Number of objects per class
+nc = classsizes(D);
+
+% Compute for all training set sizes
+if nargin < 2
+	n = min(nc)-1;
+end
+
+if length(n) > 1
+	e = zeros(1,length(n));
+	for j=1:length(n)
+		e(j) = nnerror(D,n(j));
+	end
+else
+	if n >= min(nc)
+		error('Requested size of the training set is too large.')
+	end
+	% Call for the given sample size	
+	[D,I] = sort(D);
+	I     = reshape(nlab(I),m,m);   % Order objects according to their distances
+	ee    = zeros(1,m);
+	
+	% Loop over all classes
+	for j = 1:c
+		% Find probabilities Q that objects of other classes are not selected
+		Q = ones(m,m);
+		for i = 1:c
+			if i~=j
+				[p,q] = nnprob(nc(i),n); 
+				q = [1,q];
+				C = cumsum(I==i)+1;
+				Q = Q.*reshape(q(C),m,m);
+			end
+		end
+		
+		% Find probabilitues P for objects of this class to be the first
+		[p,q] = nnprob(nc(j),n); 
+		p = [0,p];
+		C = cumsum(I==j)+1;
+		P = reshape(p(C),m,m);
+
+		% Now estimate the prob EC it is really the NN
+		J     = find(I==j);
+		EC    = zeros(m,m);
+		EC(J) = P(J).*Q(J);
+		
+		% Determine its error contribution
+		L     = find(nlab==j);
+		ee(L) = 1-sum(EC(2:m,L))./(1-EC(1,L));	% Correct for the training size
+	end
+
+	% Average for the final result
+	e = abs(mean(ee));
+end
+
+
+
+%NNPROB Probability of selection as the nearest neighbor
+%
+% [P,Q] = NNPROB(M,K)
+%
+% If K objects are selected out of M, then P(i) is the probability
+% that the i-th object is the nearest neigbor and Q(i) is the probability
+% that this object is not selected.
+
+function [p,q] = nnprob(m,k)
+p = zeros(1,m);
+q = zeros(1,m);
+q(1) = (m-k)/m;
+p(1) = k/m;
+for i=2:(m-k+1)
+	q(i) = q(i-1)*(m-k-i+1)/(m-i+1);
+	p(i) = q(i-1)*k/(m-i+1);
+end
+
Index: distools/pe_affine.m
===================================================================
--- distools/pe_affine.m	(revision 10)
+++ distools/pe_affine.m	(revision 10)
@@ -0,0 +1,41 @@
+%PE_AFFINE Define and execute Pseudo Eclidean Affine mappings
+%
+%   W = PE_AFFINE(W,SIG)
+%   F = PE_AFFINE(A,W)
+%   F = A*W
+
+function argout = pe_affine(arg1,arg2)
+
+if ismapping(arg1)  % definition of PE mapping
+	isaffine(arg1);
+	if length(arg2) ~= 2
+		error('Signature should have two components')
+	end
+	[n1,n2] = size(arg1);
+	if sum(arg2) ~= n1
+		error('Sum of signature numbers should equal input dimension of mapping')
+	end
+	par.map = arg1;
+	par.sig = arg2;
+	argout = mapping(mfilename,'trained',par,getlabels(arg1),n1,n2);
+else
+	isdataset(arg1);
+	ismapping(arg2);
+	w = getdata(arg2,'map');
+	sig = getdata(arg2,'sig');
+	if sig(2) ~= 0;
+		data = getdata(w);
+		data.rot = -data.rot;
+		data.offset = zeros(1,size(arg2,2));
+		v = setdata(w,data);
+		[m,k] = size(arg1);
+		if sig(1) ~= 0
+			argout = [arg1(:,1:sig(1)) zeros(m,sig(2))]*w;
+		else
+			argout = setdata(arg1,zeros(m,k))*w;
+		end
+		argout = argout + [setdata(arg1,zeros(m,sig(1))) arg1(:,sig(1)+1:end)]*v;
+	else % no negative directions: back in Euclidean case
+		argout = arg1*w;
+	end
+end
Index: distools/pe_distm.m
===================================================================
--- distools/pe_distm.m	(revision 10)
+++ distools/pe_distm.m	(revision 10)
@@ -0,0 +1,80 @@
+%PE_DISTM Square Pseudo-Euclidean (PE) Distance Between Two Datasets
+%
+%   D = PE_DISTM(A)
+%     OR
+%   D = PE_DISTM(A,B)
+%
+% INPUT
+%   A    PE dataset of size NxK
+%   B    PE dataset of size MxK (default A = B)
+%
+% OUTPUT
+%   D   NxM dissimilarity matrix or dataset
+%
+% DESCRIPTION
+% Computation of the square pseudo-Euclidean distance matrix D between two sets
+% of vectors, A and B. The pseudo-Euclidean distance with the signature SIG
+% (e.g. SIG = [10 5]) between vectors X and Y is computed as an indefinite
+% 'Euclidean' distance:
+%     D(X,Y) = (X-Y)'*J*(X-Y),
+% where J is a diagonal matrix with 1's, followed by -1's.
+% J = diag ([ONES(SIG(1),1);  -ONES(SIG(2),1)]);
+%
+% In a PE dataset the signature is stored in the user field, see
+% SETSIG. This signature is derived from A. It is not stored in D as D
+% does not contain vectors in a PE space.
+%
+% D is a dataset with the labels defined by the labels of A and feature labels 
+% defined by the labels of B. 
+%
+% REMARKS
+% Note that square pseudo-Euclidean distances can be negative.
+%
+% SEE ALSO
+% DATASET, SETSIG, DISTM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function D = pe_distm(A,B)
+
+  isdataset(A);
+  bisa = 0;
+  if nargin < 2, B = A; bisa = 1; end
+  sig = getsig(A);
+
+  if ~isdataset(B), B = dataset(B,1); end
+
+  a    = +A;
+  b    = +B;
+  [ra,ca] = size(a);
+  [rb,cb] = size(b);
+
+  if ca ~= cb,
+    error ('The datasets should have the same number of features.');
+  end
+
+  if any(sig) < 0 | sum(sig) ~= ca,
+    error('Signature vector SIG is invalid: its sum should equal feature size');
+  end
+
+  J = [ones(1,sig(1))  -ones(1,sig(2))];
+  D = - 2 .* a * diag(J) * b';
+  D = D + ones(ra,1) * (J*(b'.*b'));
+  D = D + (J * (a'.*a'))' * ones(1,rb);
+
+  if bisa
+    D = 0.5*(D+D');         % Make sure that distances are symmetric for D(A,A)
+  end
+
+  % Set object labels and feature labels
+  D = setdata(A,D,getlab(B));
+  D.name = 'Square Pseudo-Euclidean distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+
+return
Index: distools/pe_em.m
===================================================================
--- distools/pe_em.m	(revision 10)
+++ distools/pe_em.m	(revision 10)
@@ -0,0 +1,212 @@
+%PE_EM Pseudo-Euclidean Linear Embedding
+%
+%     W = PE_EM(D,ALF,P)
+%                 OR
+%     W = PE_EM(W,ALF)
+%
+% INPUT
+%   D   NxN symmetric dissimilarity matrix (dataset)
+%   W   Trained linear embedding into a pseudo-Euclidean space
+%   ALF Parameter determining the dimensionality and the mapping (optional, default: Inf)
+%       (0,1)   - Fraction of the total (absolute value) preserved variance
+%        Inf    - No dimensionality reduction, keeping all dimensions (it's VERY noisy)
+%       'p'     - Projection into a Euclidean space based on positive eigenvalues only
+%       'PARp'  - Projection into a Euclidean space based on the PAR fraction of
+%                 positive eigenvalues; e.g. ALF = '0.9p'
+%       'n'     - Projection into a Euclidean space based on negative eigenvalues only
+%       'PARn'  - Projection into a (negative) Euclidean space based on the PAR fraction
+%                 of negative eigenvalues; e.g. ALF = '0.7n'
+%       'P1pP2n'- Projection into a Euclidean space based on the P1 positive eigenvalues
+%                 and P2 negative eigenvalues; e.g. ALF = '0.7p0.1n', ALF = '7p2n'
+%       1 .. N  - Number of dimensions in total
+%       [P1 P2] - P1 dimensions or preserved fraction of variance in the positive subspace
+%                 and P2 dimensions or preserved fraction of variance in the negative
+%                 subspace; e.g. ALF = [5 10], ALF = [0.9 0.1]
+%   P   Integer between 0 and N specifying which object is mapped at the origin;
+%       0 stands for the mean; (optional, default: 0)
+%
+% OUTPUT
+%   W   Linear embedding into a pseudo-Euclidean space
+%
+% DEFAULT
+%   P   = 0
+%   ALF = INF
+%
+% DESCRIPTION
+% Linear mapping W onto an M-dimensional Pseudo-Euclidean _PE) subspace from a 
+% symmetric, square dissimilarity matrix D such that the dissimilarities are preserved.
+% M is determined by ALF. E.g., the subspace is found such that at least a fraction
+% ALF of the total variance is preserved for ALF in (0,1). The resulting X is found
+% by D*W. The signature of the obtained PE space (numbers of positive and negative
+% directions) can be found by PE_SIG(W). The spectrum of the obtained space
+% can be found by PE_SPEC(W). 
+%
+% A trained mapping can be reduced further by:   W = PE_EM(W,ALF)
+% The signature of the obtained PE space can be found by PE_SIG(W)
+% The spectrum of 
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, AUGPSEM, PCA, PE_PCA, PE_SPEC, GETSIG, SETSIG
+%
+% LITERATURE
+% 1. L. Goldfarb, A unified approach to pattern recognition, Pattern Recognition, vol.17,
+% 575-582, 1984.
+% 2. E. Pekalska, P. Paclik, and R.P.W. Duin, A Generalized Kernel Approach to
+% Dissimilarity-based Classification, Journal of Machine Learning Research,
+% vol.2, no.2, 175-211, 2002.
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+% This routine is adapted from PSEM. 
+% Old PSEM mappings W may be converted by W = PE_EM(W)
+
+function [W,sig,L,Q] = pe_em(d,alf,pzero,prec)
+
+% PREC is the precision parameter used for the automatic
+% selection (heuristic) of the number of dominant eigenvalues.
+% This happens when SELEIGS is called with the parameter 'CUT'.
+
+if nargin < 4, prec = [];  end
+if nargin < 3, pzero = []; end
+if nargin < 2  alf = [];   end
+
+if nargin < 1 | isempty(d),
+  W = mapping(mfilename,{alf,pzero,prec});
+  W = setname(W,'PE embedding');
+  return
+end
+
+if isempty(prec),  prec = 1e-4; end
+if isempty(pzero), pzero = 0;   end
+if isempty(alf),   alf = inf;   end
+
+if (isdataset(d) | isa(d,'double'))
+  if ismapping(alf)
+    % APPLY THE MAPPING
+    [m,n] = size(d);
+    d     = d.^2;
+
+    Q   = getdata(alf,'evec');  % Eigenvectors
+    me  = getdata(alf,'mdis');  % Vector of the average squared original dissimilarities
+    p   = getdata(alf,'mean');  % p=0 -> the mean of the embedded configuration lies at 0, 
+                                % otherwise, it lies at pzero
+    L   = getdata(alf,'eval');  % Eigenvalues
+
+    % Project new data depending on p
+    % (whether the mean or other object lies at the origin)
+    if p == 0,
+      H = -repmat(1,n,n)/n;
+      H(1:n+1:end) = H(1:n+1:end) + 1;     % H = eye(n) - ones(n,n)/n
+      W = -0.5 * (d - me(ones(m,1),:)) * H * Q * diag(sqrt(abs(L))./L);
+    else
+      W =  0.5 * (d(:,p) * ones(1,n) + me(ones(m,1),:) - d) * Q * diag(sqrt(abs(L))./L);
+    end
+
+    % Store signature in the USER field
+    if isdataset(W),
+      W = setname(W,['Projected ' updname(W.name)]);
+      W = setsig(W,getdata(alf,'sig'));
+    end
+    return
+  end
+end
+
+
+
+% REDUCE A TRAINED MAPPING
+if ismapping(d)
+  data = getdata(d);
+  if iscell(data) % check for old type of mapping
+    ispsem(d);
+    dat.evec = data{1};
+    dat.mdis = data{2};
+    dat.mean = data{3};
+    dat.eval = data{4};
+    dat.sig  = data{5};
+    dat.prec = data{6};
+    d = setmapping_file(d,mfilename);
+    d = setdata(d,dat);
+    if nargin < 2
+      W = d;
+      return % conversion only
+    else 
+      data = dat;
+    end
+  end
+  Q   = data.evec;  % Eigenvectors
+  L   = data.eval;  % Eigenvalues
+  m    = size(Q,1);
+
+  [ll,K] = sort(-abs(L));
+  L = L(K);
+  Q = Q(:,K);
+  [J,sig] = seleigs(L,alf,getdata(d,'prec'));
+  data.evec = Q(:,J);        % Eigenvectors
+  data.eval = L(J);          % Eigenvalues
+ 
+  W = mapping(mfilename,'trained',data,[],m,length(J));
+  W = setname(W,'PE embedding');
+  return
+end
+
+
+
+% TRAIN THE MAPPING
+% Tolerance value used in comparisons
+if mean(+d(:)) < 1,
+  tol = 1e-12;
+else
+  tol = 1e-10;
+end
+
+[n,m] = size(d);
+if ~issym(d,tol),
+  prwarning(1,'Matrix should be symmetric. It is made symmetric by averaging.')
+  d = 0.5*(d+d');
+end
+
+if pzero > n,
+  error('Wrong third parameter.');
+end
+
+d = (+d).^2;
+
+if pzero == 0,
+  % Project the data such that the mean lies at the origin
+  H = -repmat(1/n,n,n);
+  H(1:n+1:end) = H(1:n+1:end) + 1; % H = eye(n) - ones(n,n)/n
+  H = -0.5 * H * d * H;            % H is now the matrix of inner products
+else
+  % Project the data such that pzero's object lies at the origin
+  H = 0.5 * (d(:,pzero) * ones(1,n) + ones(n,1) * d(:,pzero)' - d);
+end
+H = 0.5*(H+H');                    % Make sure H is symmetric
+
+[Q,L]  = preig(H);
+Q      = real(Q);
+l      = diag(real(L));
+[lm,Z] = sort(-abs(l));
+Q      = Q(:,Z);
+l      = l(Z);                     % Eigenvalues are sorted by decreasing absolute value
+
+[J,sig] = seleigs(l,alf,prec);     % J is the index of the selected eigenvalues
+data.eval = l(J);                          % Eigenvalues
+data.evec = Q(:,J);                        % Eigenvectors
+data.mdis = mean(+d,2)';
+data.mean = pzero;
+data.sig  = sig;
+data.prec = prec;
+
+%A  = Q * diag(sqrt(abs(L)));      % Data in a pseudo-Euclidean space
+
+% Determine the mapping depending on pzero
+if pzero == 0,
+  W = mapping(mfilename,'trained',data,[],m,sum(sig));
+else
+  data.mdis = +d(:,pzero)';
+  W = mapping(mfilename,'trained',data,[],m,sum(sig));
+end
+W = setname(W,'PE embedding');
+return
Index: distools/pe_kernelm.m
===================================================================
--- distools/pe_kernelm.m	(revision 10)
+++ distools/pe_kernelm.m	(revision 10)
@@ -0,0 +1,86 @@
+%PE_KERNELM Pseudo-Euclidean kernel mapping
+% 
+%    K = PE_KERNELM(A,B)
+%    W = B*PE_KERNELM
+%    W = PE_KERNELM([],B)
+%    K = A*W
+%
+% INPUT
+%   A     Pseudo-Euclidean dataset of size NxK
+%   B     Pseudo-Euclidean dataset of size MxK
+%
+% OUTPUT
+%   W     PE mapping
+%   K     Kernel matrix, size [N M]
+%
+% DESCRIPTION
+% Computation of a kernel matrix in a pseudo-Euclidean space. The signature
+% of this space should be stored in the datasets A and B, see SETSIG.
+% K = A*J*B', where J is a diagonal matrix with 1's, followed by -1's.
+% J = diag ([ONES(SIG(1),1);  -ONES(SIG(2),1)]);
+% The two-element vector SIG stores the signature of the space. This is the
+% number of 'positive' dimensions, followed by the number of 'negative'
+% dimensions. It is computed by a pseudo-Eucledean embedding, e.g. PSEM,
+% and stored in the related mapping and datasets that are projected in this
+% space.
+%
+% The resulting kernel matrix K is indefinite in case A == B. This routine
+% may be used in support vector routines and other kernelized procedures.
+% Note that most of such routines are not optimal for indefinite kernels.
+%
+% EXAMPLE
+% a = gendatb;                  % generate dataset
+% d = a*proxm(a,'m',1);         % compute L1 distance matrix
+% w = psem(d);                  % embed in PE space
+% b = d*w;                      % project data in this space
+% [trainset testset] = gendat(b,0.5);     % split in trainset and testset
+% ktrain = pe_kernelm(trainset,trainset); % compute train kernel
+% w = svc(ktrain,0);            % compute SV classifier
+% ktest = pe_kernelm(testset,trainset);   % compute test kernel
+% ktest*w*testc                 % inspect error of testset   
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, PE_EM, PE_DISTM
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function w = pe_kernelm(a,b);
+
+  if nargin < 2, b = []; end
+  mapname = 'PE kernel mapping';
+	if (nargin < 1) | (isempty(a) & nargin == 1)  
+		% Definition: pe kernel mapping.
+		w = mapping(mfilename,{b});
+		w = setname(w,mapname);
+  elseif isempty(a)
+    w = mapping(mfilename,'trained',b,getlab(b),size(b,2),size(b,1));
+		w = setname(w,mapname);
+  elseif isdataset(a) & ~isempty(a)
+    if isempty(b)   % store a as rep set, 'training'
+      w = mapping(mfilename,'trained',a,getlab(a),size(a,2),size(a,1));
+		  w = setname(w,mapname);
+    elseif isdataset(b); % compute kernel between a and b
+      w = pe_mtimes(a,b');
+    elseif ismapping(b)
+      if isuntrained(b) % nothing stored yet, do it now, a is rep set
+        w = mapping(mfilename,'trained',a,getlab(a),size(a,2),size(a,1));
+		    w = setname(w,mapname);
+      else % we have already a rep set: compute kernel matrix
+        b = getdata(b);
+        w = pe_mtimes(a,b');
+      end
+    else
+      error('Second parameter should be dataset')
+    end
+    
+  else  % may be double ???
+    a = dataset(a);
+    w = feval(mfilename,a,b);
+    
+  end
+  
+return
+      
+      
Index: distools/pe_knnc.m
===================================================================
--- distools/pe_knnc.m	(revision 10)
+++ distools/pe_knnc.m	(revision 10)
@@ -0,0 +1,60 @@
+%PE_KNNC K-Nearest Neighbor Classifier for PE spaces
+%
+%   [W,K,E] = PE_KNNC(A,K)
+%   [W,K,E] = PE_KNNC(A)
+%
+% INPUT
+%   A  PE dataset
+%   K  Number of the nearest neighbors (optional; default: K is 
+%      optimized with respect to the leave-one-out error on A)
+%
+% OUTPUT
+%   W  k-NN classifier 
+%   K  Number of the nearest neighbors used
+%   E  The leave-one-out error of the KNNC
+%
+% DESCRIPTION  
+% Computation of the K-nearest neighbor classifier for the PE dataset A. 
+%
+% Warning: class prior probabilities in A are neglected.
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, KNNC, PE_EM
+
+% R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function [w,k,e] = pe_knnc(a,k)
+
+  if nargin < 2, k = []; end
+
+	if nargin == 0 | isempty(a)
+		w = mapping(mfilename,'untrained',{k});
+		w = setname(w,'PE K-NN Classifier');
+		
+	elseif ~ismapping(k) % training
+		
+		if ~ispe_dataset(a)
+			[w,k] = knnc(a,k);
+		else
+			if isempty(k)             % optimize k in PE space
+				d = pe_distm(a);        % find PE distances
+				[v,k,e] = knndc(d,k);   % use dis mat routine for optimisation k
+      elseif nargout > 2
+        e = testkd(pe_distm(a),k,'loo');
+			end
+			w = mapping(mfilename,'trained',{a,k},getlablist(a),size(a,2),getsize(a,3));
+		end
+		
+	else % execution, testset is in a, trained mapping is in k
+		
+		%retrieve data
+		trainset = getdata(k,1);
+		k = getdata(k,2);
+		d = pe_distm(a,trainset);
+    [e,w] = testkd(d,k);         % confidences in w
+    
+  end
+		
+return
Index: distools/pe_libsvc.m
===================================================================
--- distools/pe_libsvc.m	(revision 10)
+++ distools/pe_libsvc.m	(revision 10)
@@ -0,0 +1,67 @@
+%PE_LIBSVC LIBSVC for PE spaces
+%
+%    W = PE_LIBSVC(A,C)
+%  
+% INPUT
+%   A	      Pseudo-Euclidean Dataset
+%   C       Trade_off parameter in the support vector classifier.
+%           Default C = 1;
+%  
+% OUTPUT
+%   W       Mapping: Support Vector Classifier
+%   J       Object idences of support objects. Can be also obtained as W{4}
+%
+% DESCRIPTION  
+% Computation of the linear LIBSVC classifier for the Pseudo-Euclidean 
+% dataset A.  Note that testsets should be defined in the same PE space 
+% as A.
+%
+% Warning: class prior probabilities in A are neglected.
+%
+% EXAMPLE
+% trainset = gendatm;
+% testset = gendatm;
+% Dtrain = trainset*proxm(trainset,'m',1);
+% Dtest  = testset*proxm(testset,'m',1);
+% w = pe_em(Dtrain);
+% Xtrain = Dtrain*w;
+% Xtest = Dtest*w;
+% v = pe_libsvc(Xtrain);
+% Xtest*v*testc
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, KNNC, PE_EM
+
+% R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function w = pe_libsvc(a,c)
+
+  if nargin < 2, c = 1; end
+
+	if nargin == 0 | isempty(a)
+		w = mapping(mfilename,'untrained',{c});
+		w = setname(w,'PE LIBSVC');
+		
+	elseif ~ismapping(c) % training
+		
+		if ~ispe_dataset(a)
+			prwarning(1,'Dataset is Euclidean')
+			w = libsvc(a,[],c);
+		else
+			ktrain = pe_kernelm(a,a)
+			v = libsvc(ktrain,0);
+			w = mapping(mfilename,'trained',{v,a},getlablist(a),size(a,2),getsize(a,3));
+		end
+		
+	else % execution, testset is in a, trained mapping is in c
+		
+		w = getdata(c,1);
+		trainset = getdata(c,2);
+		ktest = pe_kernelm(a,trainset);
+		w = ktest*w;
+    
+  end
+		
+return
Index: distools/pe_mtimes.m
===================================================================
--- distools/pe_mtimes.m	(revision 10)
+++ distools/pe_mtimes.m	(revision 10)
@@ -0,0 +1,30 @@
+%PE_MTIMES Pseudo-Euclidean matrix product
+%
+%  C = PE_MTIMES(A,B)
+%
+% A and/or B should be datasets. Their PE signature SIG is retrieved,
+% C = A*J*B, where J is a diagonal matrix with 1's, followed by -1's.
+% J = diag ([ONES(SIG(1),1);  -ONES(SIG(2),1)])
+
+function c = pe_mtimes(a,b)
+
+siga = getsig(a);
+sigb = getsig(b); 
+
+if isdataset(a) & isdataset(b)
+  if any(siga~=sigb)
+    error('PE signatures should be equal')
+  end
+  J = diag([ones(1,siga(1))  -ones(1,siga(2))]);
+  c = a*J*b;
+elseif isdataset(a)
+  J = diag([ones(1,siga(1))  -ones(1,siga(2))]);
+  c = a*J*b;
+elseif isdataset(b) % problem! make doubles
+  J = diag([ones(1,sigb(1))  -ones(1,sigb(2))]);
+  c = a*J*(+b);
+else % just doubles, no PE space
+  c = a*b;
+end
+  
+  
Index: distools/pe_nmc.m
===================================================================
--- distools/pe_nmc.m	(revision 10)
+++ distools/pe_nmc.m	(revision 10)
@@ -0,0 +1,42 @@
+%PE_NMC Nearest Mean Classifier for PE spaces
+%
+%   W = PE_NMC(A)
+%
+% INPUT
+%   A  PE dataset
+%
+% OUTPUT
+%   W  Nearest mean classifier 
+%
+% DESCRIPTION  
+% Computation of the nearest mran classifier for the PE dataset A. 
+%
+% Warning: class prior probabilities in A are neglected.
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, NMC
+
+% R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function w = pe_nmc(a,w)
+
+  if nargin == 0 | isempty(a)
+    w = mapping(mfilename,'untrained');
+    w = setname(w,'PE Nearest Mean');
+    
+  else
+    
+    if ~ispe_dataset(a)
+      w = nmc(a);
+    else
+      u = meancov(a);
+      sig = getsig(a);
+      u = setsig(u,sig);
+      w = pe_knnc(u,1);
+    end
+    
+  end
+    
+return
Index: distools/pe_parzenc.m
===================================================================
--- distools/pe_parzenc.m	(revision 10)
+++ distools/pe_parzenc.m	(revision 10)
@@ -0,0 +1,62 @@
+%PE_PARZENC Parzen Classifier for PE spaces
+%
+%   [W,H,E] = PE_PARZENC(A,H)
+%   [W,H,E] = PE_PARZENC(A)
+%
+% INPUT
+%   A  PE dataset
+%   H  Smoothing parameter (optional; default: H is optimized
+%      with respect to the leave-one-out error on A)
+%
+% OUTPUT
+%   W  Parzen classifier 
+%   H  Number of the nearest neighbors used
+%   E  The leave-one-out error
+%
+% DESCRIPTION  
+% Computation of the Parzen classifier for the PE dataset A. 
+%
+% Warning: class prior probabilities in A are neglected.
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, PARZENC, PARZENDDC
+
+% R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function [w,h,e] = pe_parzenc(a,h)
+
+  if nargin < 2, h = []; end
+
+  if nargin == 0 | isempty(a)
+    w = mapping(mfilename,'untrained',{h});
+    w = setname(w,'PE Parzen Classifier');
+    
+  elseif ~ismapping(h) % training
+    
+    if ~ispe_dataset(a)
+      [w,h] = parzenc(a,h);
+    else
+      if isempty(h)             % optimize h for PE space
+        d = sqrt(pe_distm(a));  % find PE distances
+        [v,h] = parzenddc(d,h); % use dis mat routine for optimisation h
+      end
+      if nargout > 2
+        e = testpd(sqrt(pe_distm(a)),h,'loo');
+      end
+      w = mapping(mfilename,'trained',{a,h},getlablist(a),size(a,2),getsize(a,3));
+    end
+    
+  else % execution, testset is in a, trained mapping is in h
+    
+    %retrieve data
+    trainset = getdata(h,1);
+    h = getdata(h,2);
+    
+    d = sqrt(pe_distm(a,trainset));
+    [e,w] = testpd(d,h);         % confidences in w
+    
+  end
+    
+return
Index: distools/plotgraph.m
===================================================================
--- distools/plotgraph.m	(revision 10)
+++ distools/plotgraph.m	(revision 10)
@@ -0,0 +1,61 @@
+%PLOTGRAPH Plot a 2D graph
+%
+%   PLOTGRAPH (A,L,S)
+%
+% INPUT
+%   A   Nx2 or Nx3 Data matrix
+%   L   List of edges belonging to the graph
+%   S   Plotstring, default 'k'
+%
+% DESCRIPTION
+% Plots data and edges of a graph. Applicable only for 2D or 3D data.
+% If A is unknown, but dissimilarity data are given, then a 2D or 3D 
+% approximation can be found by PSEM.
+%
+% SEE ALSO
+% KMST, PSEM, DISTGRAPH, GRAPHPATH
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function plotgraph (A,L,S)
+
+if narg < 3, S = 'k'; end
+A = +A;
+[n,m] = size(A);
+
+len = length(L);
+K   = round (len/(n-1));
+
+if m == 2,
+  plot(A(:,1),A(:,2),'.r')
+  text(A(:,1),A(:,2),num2str([1:n]'));
+  grid on;
+  hold on;
+  for i=1:len
+    plot([A(L(i,1),1) A(L(i,2),1)],[A(L(i,1),2) A(L(i,2),2)],S);
+  end
+
+elseif m == 3,
+
+  plot3(A(:,1),A(:,2),A(:,3),'.r')
+  text(A(:,1),A(:,2),A(:,3),num2str([1:n]'));
+  grid on;
+  hold on;
+  for i=1:len
+    plot3([A(L(i,1),1) A(L(i,2),1)],[A(L(i,1),2) A(L(i,2),2)],[A(L(i,1),3) A(L(i,2),3)],S);
+  end
+else
+  error('Plotting is only possible for two or three variables.');
+  return;
+end
+
+hold off
+if K == 1,
+  title('Minimum Spanning Tree');
+else
+  title([num2str(K) ' Minimum Spanning Trees']);
+end
+return;
Index: distools/plotspectrum.m
===================================================================
--- distools/plotspectrum.m	(revision 10)
+++ distools/plotspectrum.m	(revision 10)
@@ -0,0 +1,52 @@
+%PLOTSPECTRUM
+%
+%     h = PLOTSPECTRUM(L)
+%     h = PLOTSPECTRUM(W)
+%
+% Plot spectrum as stored in vector L or in mapping W.
+
+function [h1,h2] = plotspectrum(L)
+
+if ismapping(L)
+  if strcmp(getmapping_file(L),'psem')
+    L = getdata(L,4);
+    tit = 'Embedding Spectrum';
+  elseif strcmp(getmapping_file(L),'affine')
+    try 
+      L = getdata(L,'eigenvalues');
+      tit = 'Eigenvalues';
+    catch
+      error('No spectrum found');
+    end
+  else
+    error('No spectrum found')
+  end
+else
+  tit = 'Eigenspectrum';
+end
+
+L = flipud(sort(L(:)));
+sig1 = max(find(L>=0));
+sig2 = length(L) - sig1;
+
+if sig2 == 0
+    hh1 = plot([1:sig1],[L(1:sig1)]); 
+else
+    hh1 = plot([1:sig1 sig1+0.5],[L(1:sig1);0]); 
+    hold on; 
+    hh2 = plot([sig1+0.5 sig1+1:sig1+sig2],[0;L(sig1+1:end)],'r');
+    hold off
+end
+V = axis;
+V(1) = -1;
+V(2) = length(L)+2;
+axis(V);
+fontsize(16);
+linewidth(2);
+xlabel('Eigenvector')
+ylabel('Eigenvalue')
+title(tit)
+if nargout > 1
+    h1 = hh1;
+    h2 = hh2;
+end
Index: distools/protselfd.m
===================================================================
--- distools/protselfd.m	(revision 10)
+++ distools/protselfd.m	(revision 10)
@@ -0,0 +1,155 @@
+%PROTSELFD Forward Prototype Selection for Dissimilarity Matrices
+%
+%   [W,E,KOPT] = PROTSELFD(D,K,PAR)
+%    W  = D*PROTSELFD([],K,PAR)
+%
+% INPUT
+%   D     Dataset, square dissimilarity matrix
+%   K     Integer, desired number of prototypes
+%   PAR  'LOO' - leave-one-out option. This should be used if
+%          the objects are related to themselves. If D is not square,
+%          it is assumed that the first sets of objects in columns and
+%          rows match.
+%        'ALL' - use all objects (default).
+%
+% OUTPUT
+%   W     Selection mapping ('feature selection')
+%   E     Error stimate as a function of number of selected prototypes
+%         (only reliable for prototype sizes >= class size)
+%   KOPT  Estimate for best size in avoiding peaking
+%
+% DESCRIPTION
+% This procedure for optimizing the representation set of a 
+% dissimilarity matrix is based on a greedy, forward selection of
+% prototypes using the leave-one-out error estimate of the 1NN rule
+% as a criterion. As this is computed on the given distances in
+% D, the procedure is based on sorting and counting only and is
+% thereby fast. In case K=1 just a single prototype has to be returned,
+% but computing the 1NN error is not possible as all objects are assigned
+% to the same class. In that case the centre object of the largest class
+% will be returned.
+%
+% Note that the search continues untill K prototypes are found.
+% This might be larger than desired due to peaking (curse of
+% dimensionality, overtraining). Therefor an estimate for the
+% optimal number of prototype is returned in KOPT. 
+%
+% The prototype selection may be applied by C = B*W(:,1:KSEL),
+% in which B is a dissimilarity matrix based on the same 
+% representation set as A (e.g. A itself) and C is a resulting 
+% dissimilarity matrix in which the KSEL (e.g. KOPT) best prototypes
+% are selected.
+%
+% REFERENCE
+% E. Pekalska, R.P.W. Duin, and P. Paclik, Prototype selection for
+% dissimilarity-based classification, Pattern Recognition, 
+% vol. 39, no. 2, 2006, 189-208.
+%
+% SEE ALSO
+% KNNDC, DISEX_PROTSELFD
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% 
+
+function [R,e,D,J,nlab,clab] = protselfd(D,ksel,par,J,e,nlab,clab)
+
+if nargin < 2, ksel = []; end
+if nargin < 3 | isempty(par), par = 'all'; end
+
+if nargin < 4 % user call
+  
+  if nargin < 1 | isempty(D)  % allow for D*protselfd([],pars)
+    R = mapping(mfilename,'untrained',{ksel,par});
+    R = setname(R,'Forward Prototype Sel');
+    return
+  end
+  
+  [m,k,c] = getsize(D);
+  if isempty(ksel), ksel = k; end
+  if strcmp(par,'loo') | strcmp(par,'LOO')
+    if k > m
+      error('More rows than columns expected for dissimilarity matrix')
+    end
+    discheck(D(1:k,:));
+    D(1:k,:) = D(1:k,:) + 1e100*eye(k); % get rid of diagonal for LOO
+  end
+  
+  %Initialise by the centre of the largest class
+  cc = classsizes(D);
+  [cmax,n] = max(cc); % n is the largest class
+  lablist = getlablist(D);
+  nlab = getnlab(D);
+  clab = renumlab(getfeatlab(D),lablist);
+  R = find(nlab == n);
+  C = find(clab == n);
+  dd = +D(R,C);
+  [dmin,rmin] = sort(dd,1); % find one but most remote object
+  [dmin,cmin] = min(dmin(end-1,:)); % find prototype for which this is minimum
+  R = C(cmin);
+  
+  e = zeros(1,ksel);
+  [nlab,clab] = renumlab(getlabels(D),getfeatlab(D));
+  [dd,J] = min(+D(:,R),[],2);
+  e(1) = sum(clab(R(J)) ~= nlab);
+  
+	if ksel > 1
+		% this will be a deep recursive call !!!
+		prwaitbar(ksel,'Forward prototype selection')
+		[R,e,D,J,nlab,clab] = protselfd(D,ksel,R,J,e,nlab,clab);
+		prwaitbar(0);
+	end
+  e = e(1:length(+R))/m;
+  R = featsel(k,R);
+  
+  % Find optimal number of prototypes in avoiding peaking
+  
+  Jopt = find(e==min(e));
+  D = floor((Jopt(end)+Jopt(1))/2);
+  
+  % done!
+  
+else  % internal call, parameters may have another meaning!
+  
+  R = par;  % prototypes sofar
+  [m,k,c] = getsize(D);
+  d = +D;
+  S = [1:k];   % all candidates
+  S(R) = [];   % exclude ones we have
+  emin = inf;
+  dmin = inf;
+  r = length(R);
+  prwaitbar(ksel,r);
+  for j=S      % run over all candidates left
+		% the following tricky statements finds the nearest neighobor indices n
+		% for all objects to their nearest prototype (n=1) or the candidate 
+		% prototype (n=2). In ds the minimum distances are stored and used for
+		% solving ties later.
+    [ds,n] = min([d(m*(R(J')'-1)+[1:m]'),d(:,j)],[],2);
+		% the labels of the nearest prototypes and the candidates
+    cclab = [clab(R(J)') repmat(clab(j),m,1)];
+		% compute the nearest neighbor error using the computed n
+    ee = sum(cclab(m*(n-1)+[1:m]') ~= nlab);
+    de = sum(ds);
+		% if better, use it
+    if ee < emin | ((ee == emin) & (de < dmin))
+      emin = ee;
+      jmin = j;
+      JJ = [J repmat(r+1,m,1)];
+      Jmin = JJ(m*(n-1)+[1:m]');
+      Rmin = [R jmin];
+      dmin = de;
+    end
+  end
+
+  if emin <= e(r) | 1 % we even continue if emin increases due to peaking
+    e(r+1) = emin;
+    R = Rmin;
+    if (r+1) < ksel
+			[R,e,D,J,nlab,clab] = protselfd(D,ksel,R,Jmin,e,nlab,clab);
+    end
+  end
+  
+end
Index: distools/proxxm.m
===================================================================
--- distools/proxxm.m	(revision 10)
+++ distools/proxxm.m	(revision 10)
@@ -0,0 +1,344 @@
+%PROXXM Proximity Mapping
+%
+%   W = PROXXM(A,TYPE,P,WEIGHTS)
+%   W = A*PROXXM([],TYPE,P,WEIGHTS)
+%
+% INPUT
+%   A       MxK Dataset
+%   TYPE    Type of the proximity (optional; default: 'distance')
+%   P       Parameter of the proximity (optional; default: 1)
+%   WEIGHTS Weights (optional; default: all 1)
+%
+%   OUTPUT
+%   W       Proximity mapping
+%
+% DESCRIPTION
+% Computation of the KxM proximity mapping (or kernel) defined by the
+% MxK dataset A. Unlabeled objects in A are neglected. If B is an NxK
+% dataset, then D=B*W is the NxM proximity matrix between B and A. The
+% proximities can be defined by the following types:
+%
+%   'POLYNOMIAL'   | 'P':  SIGN(A*B').*(A*B').^P
+%   'HOMOGENEOUS'  | 'H':  SIGN(A*B').*(A*B').^P
+%   'EXP'          | 'E':  EXP(-(||A-B||)/P)
+%   'EXP-SUM'      | 'ES': SUM_Z SIGN(P(Z)) * EXP(-(||A-B||)/P(Z))
+%   'RBF'          | 'R':  EXP(-(||A-B||.^2)/(P*P))
+%   'RBF-SUM'      | 'RS': SUM_Z SIGN(P(Z)) * EXP(-(||A-B||.^2)/(P(Z)^2))
+%   'SIGMOID'      | 'S':  SIGM(A*B'/P)
+%   'DSIGMOID'     | 'DS': SIGM(||A-B||^(2P(1))/P(2))
+%   'DISTANCE'     | 'D':  ||A-B||.^P
+%   'MULTIQUADRIC' | 'MQ': SQRT(||A-B||.^2/P(1) + P(2))
+%   'THIN-PLATE'   | 'TP': ||A-B||.^(2*P(1))/P(2) * LOG(1+||A-B||.^(2*P(1))/P(2))
+%   'N-THIN-PLATE' | 'NTP': -||A-B||.^(2*P(1))/P(2) * LOG(1+||A-B||.^(2*P(1))/P(2))
+%   'MINKOWSKI'    | 'M':  SUM(|A-B|^P).^(1/P)
+%   'CITY-BLOCK'   | 'C':  SUM(|A-B|)
+%   'COSINE'       | 'O':  1 - (A*B')/||A||*||B||
+%   'FOURIER'      | 'F'
+%   'TANH'         | 'T':  TANH(P*(A*B')/LENGTH(A) + P);
+%   'ANOVA'        | 'A':  ANOVA MODEL
+%   'BSPLINE'      | 'B':  BSPLINE MODEL, ORDER P
+%   'ANOVABSPLINE' | 'AB': ANOVA-BSPLINE MODEL, ORDER P
+%   'ANOVASPLINE1' | 'AS1':ANOVA-SPLINE MODEL, ORDER 1
+%   'ANOVASPLINE2' | 'AS2':ANOVA-SPLINE MODEL, ORDER 2
+%   'ANOVASPLINE3' | 'AS3':ANOVA-SPLINE MODEL, ORDER 3
+%
+% In the polynomial case for a non-integer P, the proximity is computed
+% as D = SIGN(S+1).*ABS(S+1).^P, in order to avoid problems with negative
+% inner products S = A*B'. The features of the objects in A and B may be
+% weighted by the weights in the vector WEIGHTS.
+%
+% SEE ALSO
+% PROXM, MAPPINGS, DATASETS
+
+% Copyright: Robert P.W. Duin, r.p.w.duin@prtools.org, Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function W = proxxm(A,type,s,weights)
+
+prtrace(mfilename);
+
+if (nargin < 4)
+  weights = [];
+  prwarning(4,'Weights are not supplied, assuming all 1.');
+end
+
+if (nargin < 3) | (isempty(s))
+  s = [1 1];
+  prwarning(4,'The proximity parameter is not supplied, assuming 1.');
+end
+if length(s) < 2, s(2) = 1; end
+
+if (nargin < 2) | (isempty(type))
+  type = 'd';
+  prwarning(4,'Type of the proximity is not supplied, assuming ''DISTANCE''.');
+end
+
+
+% No data, return an UNTRAINED mapping
+if (nargin < 1) | (isempty(A))
+  W = mapping(mfilename,{type,s,weights});
+  W = setname(W,'Proximity mapping');
+  return;
+end
+
+
+[m,k] = size(A);
+
+if (isstr(type))
+  % Definition of the mapping, just store parameters.
+  all = char('polynomial','p','homogeneous','h','exp','e','exp-sum','es','rbf','r',...
+             'rbf-sum','rs','sigmoid','s','distance','d','thin-plate','tp',...
+             'multiquadric','mq','dsigmoid','ds','minkowski','m','city-block','c',...
+             'cosine','o','uniform','u','anova','a','anovaspline1','as1',...
+             'anovaspline2','as2','anovaspline3','as3','anovabspline',...
+             'ab','bspline','b','spline','fourier','f','tanh','t',...
+             'n-thin-plate','ntp','shiftdist');
+  if (~any(strcmp(cellstr(all),type)))
+    error(['Unknown proximity type: ' type])
+  end
+
+  A     = cdats(A,1);
+  [m,k] = size(A);
+  if isdataset(A)
+    W = mapping(mfilename,'trained',{A,type,s,weights},getlab(A),getfeatsize(A),getobjsize(A));
+  else
+    W = mapping(mfilename,'trained',{A,type,s,weights},[],k,m);
+  end
+  W = setname(W,'Proximity mapping');
+
+
+elseif ismapping(type)
+
+  % Execution of the mapping: compute a proximity matrix
+  % between the input data A and B; output stored in W.
+
+  w = type;
+  [B,type,s,weights] = deal(w.data{1},w.data{2},w.data{3},w.data{4});
+  [kk,n] = size(w);
+  if (k ~= kk)
+    error('Mismatch in sizes between the mapping and its data stored internally.');
+  end
+  if (~isempty(weights))
+    if (length(weights) ~= k),
+      error('Weight vector has a wrong length.');
+    end
+    A = A.*(ones(m,1)*weights(:)');
+    B = B.*(ones(n,1)*weights(:)');
+  end
+  AA = A;
+  A  = +A;
+  B  = +B;
+
+  switch type
+    case {'polynomial','p'}
+      D = A*B' + ones(m,n);
+      if (s ~= round(s(1)))
+        D = sign(D).*abs(D).^s(1);
+      elseif (s(1) ~= 1)
+        D = D.^s(1);
+      end
+
+    case {'homogeneous','h'}
+      D = (A*B');
+      if (s ~= round(s(1)))
+        D = sign(D).*abs(D).^s(1);
+      elseif (s(1) ~= 1)
+        D = D.^s(1);
+      end
+
+    case {'sigmoid','s'}
+      D = (A*B');
+      D = sigm(D/s(1));
+
+    case {'dsigmoid','ds'}
+      D = dist2(B,A).^s(1);
+      D = sigm(D/s(2));
+
+    case {'city-block','c'}
+      D = zeros(m,n);
+      for j=1:n
+        D(:,j) = sum(abs(A - repmat(+B(j,:),m,1)),2);
+      end
+
+    case {'minkowski','m'}
+      D = zeros(m,n);
+      for j=1:n
+        D(:,j) = sum(abs(A - repmat(+B(j,:),m,1)).^s(1),2).^(1/s(1));
+      end
+
+    case {'exp','e'}
+      D = dist2(B,A);
+      D = exp(-sqrt(D)/s(1));
+
+    case {'exp-sum','es'}
+      d = sqrt(dist2(B,A));
+      D = sign(s(1))*exp(-d/s(1));
+      for z=2:length(s)
+        D = D + sign(s(z))*exp(-d/s(z));
+      end
+
+      case {'rbf','r'}
+        D = dist2(B,A);
+        D = exp(-D/(s(1)*s(1)));
+
+      case {'rbf-sum','rs'}
+        d = dist2(B,A);
+        D = sign(s(1))*exp(-d/(s(1)^2));;
+        for z=2:length(s)
+          D = D + sign(s(z))*exp(-d/(s(z)^2));
+        end
+
+      case {'distance','d'}
+        D = dist2(B,A);
+        if s(1) ~= 2
+          D = sqrt(D).^s(1);
+				end
+
+     case {'shiftdist'} % not properly implemented for test objects
+        D = dist2(B,A);
+        if s(1) ~= 2
+          D = sqrt(D).^s(1);
+        end
+        D = -D;
+				n = size(D,1);
+        % shift data such that mean lies in the origin
+        H = -repmat(1/n,n,n); 
+        H(1:n+1:end) = H(1:n+1:end) + 1;  % H = eye(n) - ones(n,n)/n
+				size(D)
+				size(H)
+        D = -0.5 * H * D * H;             % D is now the matrix of inner products
+				
+      case {'multiquadric','mq'}
+        D = sqrt(dist2(B,A)/s(1) +s(2).^2);
+
+      case {'thin-plate','tp'}
+        d = dist2(B,A).^s(1)/s(2);
+        D = d.*log(1+d);
+
+      case {'n-thin-plate','ntp'}
+        d = dist2(B,A).^s(1)/s(2);
+        D = -d.*log(1+d);
+
+      case {'cosine','o'}
+        D  = (A*B');
+        lA = sqrt(sum(A.*A,2));
+        lB = sqrt(sum(B.*B,2));
+        D  = 1 - D./(lA*lB');
+
+      case {'tanh','t'}
+        D = tanh(s(1)*(A*B')/k + s(1));
+
+      case {'fourier','f'}
+        zz = sin(s(1) + 1/2)*2*ones(k,1);
+        D  = zeros(m,n);
+        for oo=1:m
+          for o=1:n
+            z = zz;
+            I = find(A(oo,:)-B(o,:));
+            z(I) = sin(s(1) + 1/2)*(A(oo,I)-B(o,I))./sin((A(oo,I)-B(o,I))/2);
+            D(oo,o) = prod(z);
+          end
+        end
+
+      case {'spline','anovaspline1','as1'}
+        D = zeros(m,n);
+        for oo=1:m
+          for o=1:n
+            mAB = min(A(oo,:),B(o,:));
+            z   = 1 + A(oo,:).*B(o,:).*(1 + mAB) - ((A(oo,:)+B(o,:))/2).*mAB.^2 + mAB.^3/3;
+            D(oo,o) = prod(z);
+          end
+        end
+
+      case {'anova','a'}
+        D = zeros(m,n);
+        for oo=1:m
+          for o=1:n
+            mAB = min(A(oo,:),B(o,:));
+            z   = 1 + A(oo,:).*B(o,:).*(1 + 0.5*mAB) - mAB.^3/6;
+            D(oo,o) = prod(z);
+          end
+        end
+
+      case {'bspline','b'}
+        D = zeros(m,n);
+        for oo=1:m
+          for o=1:n
+            z = 0;
+            AmB = A(oo,:)- B(o,:);
+            for r = 0:2*(s(1)+1)
+              z = z + (-1)^r*binomial(2*(s(1)+1),r)*(max(0,AmB + s(1)+1 - r)).^(2*s(1) + 1);
+            end
+            D(oo,o) = prod(z);
+          end
+        end
+
+      case {'anovaspline2','as2'}
+        D = zeros(m,n);
+        for oo=1:m
+          for o=1:n
+            mAB = min(A(oo,:),B(o,:));
+            AmB = A(oo,:) - B(o,:);
+            AB  = A(oo,:) .* B(o,:);
+            ApB = A(oo,:) + B(o,:);
+            z   = 1 + AB + AB.^2.*(1 + mAB) - AB.*(ApB).*mAB.^2 + ...
+                  (ApB.^2+2*AB).*mAB.^3/3 - 0.5*ApB.*mAB.^4 + 0.2*mAB.^5;
+            D(oo,o) = prod(z);
+          end
+        end
+
+      case {'anovaspline3','as3'}
+        D = zeros(m,n);
+        for oo=1:m
+          for o=1:n
+            mAB = min(A(oo,:),B(o,:));
+            AmB = A(oo,:)- B(o,:);
+            AB  = A(oo,:).*B(o,:);
+            ApB = A(oo,:)+B(o,:);
+            z   = 1 + AB + AB.^2 + AB.^3.*(1 + mAB) - 1.5 * AB.^2 .*(ApB).*mAB.^2 + ...
+                  AB.*(ApB.^2+AB).*mAB.^3 - 0.25 * (3*ApB.^3- 2*B(oo,:).^2 - ...
+                  2*A(o,:).^2).*mAB.^4 + 0.6 * (ApB.^2+AB).*mAB.^5 - 0.5 * ApB .*mAB.^6+mAB.^7/7;
+            D(oo,o) = prod(z);
+          end
+        end
+
+      case {'anovabspline','ab'}
+        D = zeros(m,n);
+        for oo=1:m
+          for o=1:n
+            z = 0;
+            AmB = A(oo,:)- B(o,:);
+            for r = 0:2*(s(1)+1)
+              z = z + (-1)^r*binomial(2*(s(1)+1),r)*(max(0,BmA + s(1)+1 - r)).^(2*s(1) + 1);
+            end
+          D(oo,o) = prod(1+z);
+        end
+      end
+
+      otherwise
+        error('Unknown proximity type')
+    end
+    W = setdat(AA,D,w);
+
+  else
+      error('Illegal TYPE argument.')
+  end
+return;
+
+
+
+function D = dist2(B,A)
+% Computes square Euclidean distance, avoiding large matrices for a high
+% dimensionality data
+    m = size(A,1);
+    n = size(B,1);
+    D = ones(m,1)*sum(B'.*B',1);
+    D = D + sum(A'.*A',1)'*ones(1,n);
+    D = D - 2 .* (+A)*(+B)';
+    % Clean result.
+    J = find(D<0);
+    D(J) = zeros(size(J));
+return
Index: distools/prtbunke.m
===================================================================
--- distools/prtbunke.m	(revision 10)
+++ distools/prtbunke.m	(revision 10)
@@ -0,0 +1,69 @@
+% Read Bunke's data to PRTOOLS
+
+function D = prtbunke(fname)
+
+fid = fopen(fname,'r');
+if fid == -1,
+  error(['File not found: ' fname])
+end
+
+ok   = 0;
+info = [];
+lab  = [];
+
+while ~ok,
+  str = fgetl(fid);
+  switch str
+    case '.CHARACTERBAND TYPE'
+      info.datatype = fgets(fid);
+
+    case '.COST FUNCTION'
+      str = fgets(fid);
+      [info.costfun,info.cost] = strread(str,'%s%f','delimiter',' ');
+
+    case '.CLASS MEMBERSHIP'    % here come labels
+      str = fgets(fid);
+      lab = strread(str,'%s','delimiter',' ');
+
+    case '.DISTANCE MATRIX'
+      D = fscanf(fid,'%f');
+      N = sqrt(length(D));
+      D = reshape(D,N,N);
+      if issym(D,1e-10),
+        D = 0.5*(D+D');
+      end
+      if ~isempty(lab),
+        D = dataset(D,lab,'featlab',lab);
+        C = classsizes(D);
+        % Should it be class frequencies or equal priors?
+        if length(C) > 1,
+          D = setprior(D,C/sum(C));
+        end
+        if ~isempty(info),
+          D = setuser(D,info);
+        end
+        p   = findstr(lower(fname),'_norm');
+        if ~isempty(p),
+          pos = findstr(lower(fname),'/');  % Linux
+          if isempty(pos)
+            pos = findstr(lower(fname),'\');  % Windows
+          end
+          if isempty(pos),
+            z = 1;
+          else
+            I = find(pos < p(1));
+            z = pos(I(end))+1;
+          end
+          D = setname(D,['Distance matrix for ' fname(z:p(1)-1)]);
+        else
+          D = setname(D,'Distance matrix');
+        end
+      end
+      ok = 1;
+    otherwise
+        ;
+  end
+  ok = feof(fid);
+end
+fclose(fid);
+return
Index: distools/psdistm.m
===================================================================
--- distools/psdistm.m	(revision 10)
+++ distools/psdistm.m	(revision 10)
@@ -0,0 +1,98 @@
+%PSDISTM Square Pseudo-Euclidean Distance Between Two Datasets
+%
+%   D = PSDISTM(A,SIG)
+%     OR
+%   D = PSDISTM(A,B,SIG)
+%
+% INPUT
+%   A    NxK Matrix or dataset
+%   B    MxK Matrix or dataset
+%   SIG  2x1 vector being the signature of the pseudo-Euclidean space;
+%        SIG(1)+SIG(2)=K
+%
+% OUTPUT
+%   D   NxM dissimilarity matrix or dataset
+%
+% DESCRIPTION
+% Computation of the square pseudo-Euclidean distance matrix D between two sets
+% of vectors, A and B. The pseudo-Euclidean distance with the signature SIG
+% (e.g. SIG = [10 5]) between vectors X and Y is comuted as an indefinite
+% 'Euclidean' distance:
+%     D(X,Y) = (X-Y)'*J*(X-Y),
+% where J is a diagonal matrix with 1, followed by -1.
+% J = diag ([ONES(SIG(1),1);  -ONES(sig(2),1)]);
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% REMARKS
+% Note that square pseudo-Euclidean distances can be negative.
+%
+% SEE ALSO
+% DISTM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function D = psdistm(A,B,sig)
+
+bisa = 0;
+if nargin < 2,
+  error ('Inputs not specified');
+elseif nargin < 3
+  if max (size(B)) == 2 & min(size(B)) == 1,
+    sig = B;
+    B = A;
+    bisa = 1;
+  else
+    error('Signature vector SIG expected.');
+  end
+else
+  ;
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a    = +A;
+b    = +B;
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+
+if ca ~= cb,
+  error ('The matrices should have the same number of columns.');
+end
+
+if any(sig) < 0 | sum(sig) ~= ca,
+  error('Signature vector SIG is invalid.');
+end
+
+J = [ones(1,sig(1))  -ones(1,sig(2))];
+D = - 2 .* a * diag(J) * b';
+D = D + ones(ra,1) * (J*(b'.*b'));
+D = D + (J * (a'.*a'))' * ones(1,rb);
+
+% Check numerical inaccuracy
+if bisa,
+  D = 0.5*(D+D');         % Make sure that distances are symmetric for D(A,A)
+end
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Square Pseudo-Euclidean distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/psem.m
===================================================================
--- distools/psem.m	(revision 10)
+++ distools/psem.m	(revision 10)
@@ -0,0 +1,193 @@
+%PSEM Pseudo-Euclidean Linear Embedding
+%
+%     [W,SIG,L] = PSEM(D,ALF,P)
+%                 OR
+%     [W,SIG,L] = PSEM(W,ALF)
+%
+% INPUT
+%   D   NxN symmetric dissimilarity matrix (dataset)
+%   W   Trained linear embedding into a pseudo-Euclidean space
+%   ALF Parameter determining the dimensionality and the mapping (optional, default: Inf)
+%       (0,1)   - Fraction of the total (absolute value) preserved variance
+%        Inf    - No dimensionality reduction, keeping all dimensions (it's VERY noisy)
+%       'p'     - Projection into a Euclidean space based on positive eigenvalues only
+%       'PARp'  - Projection into a Euclidean space based on the PAR fraction of
+%                 positive eigenvalues; e.g. ALF = '0.9p'
+%       'n'     - Projection into a Euclidean space based on negative eigenvalues only
+%       'PARn'  - Projection into a (negative) Euclidean space based on the PAR fraction
+%                 of negative eigenvalues; e.g. ALF = '0.7n'
+%       'P1pP2n'- Projection into a Euclidean space based on the P1 positive eigenvalues
+%                 and P2 negative eigenvalues; e.g. ALF = '0.7p0.1n', ALF = '7p2n'
+%       1 .. N  - Number of dimensions in total
+%       [P1 P2] - P1 dimensions or preserved fraction of variance in the positive subspace
+%                 and P2 dimensions or preserved fraction of variance in the negative
+%                 subspace; e.g. ALF = [5 10], ALF = [0.9 0.1]
+%   P   Integer between 0 and N specifying which object is mapped at the origin;
+%       0 stands for the mean; (optional, default: 0)
+%
+% OUTPUT
+%   W   Linear embedding into a pseudo-Euclidean space
+%   SIG Signature of the space
+%   L   List of eigenvalues
+%
+% DEFAULT
+%   P   = 0
+%   ALF = INF
+%
+% DESCRIPTION
+% Linear mapping W onto an M-dimensional pseudo-Euclidean subspace from a symmetric,
+% square dissimilarity matrix D such that the dissimilarities are preserved. M
+% M is determined by ALF. E.g., the subspace is found such that at least a fraction
+% ALF of the total variance is preserved for ALF in (0,1). The resulting X is found
+% by D*W. The parameter SIG describes the signature of the subspace. L is a sorted
+% list of eigenvalues describing the variances in the (pseudo-)Euclidean space.
+%
+% A trained mapping can be reduced further by:
+%   [W,SIG,L] = PSEM(D,ALF)
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, AUGPSEM, PCA
+%
+% LITERATURE
+% 1. L. Goldfarb, A unified approach to pattern recognition, Pattern Recognition, vol.17,
+% 575-582, 1984.
+% 2. E. Pekalska, P. Paclik, and R.P.W. Duin, A Generalized Kernel Approach to
+% Dissimilarity-based Classification, Journal of Machine Learning Research,
+% vol.2, no.2, 175-211, 2002.
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function [W,sig,L,Q] = psem(d,alf,pzero,prec)
+
+% PREC is the precision parameter used for the automatic
+% selection (heuristic) of the number of dominant eigenvalues.
+% This happens when SELEIGS is called with the parameter 'CUT'.
+
+if nargin < 4 | isempty(prec),
+  prec = 1e-4;
+end
+if nargin < 3 | isempty(pzero),
+  pzero = 0;
+end
+if nargin < 2 | isempty(alf),
+  alf = inf;
+end
+if nargin < 1 | isempty(d),
+  W = mapping(mfilename,{alf,pzero,prec});
+  W = setname(W,'PE embedding');
+  return
+end
+
+
+
+if (isdataset(d) | isa(d,'double'))
+  if ismapping(alf)
+    % APPLY THE MAPPING
+    pars  = getdata(alf);
+    [m,n] = size(d);
+    d     = d.^2;
+
+    Q   = pars{1};  % Eigenvectors
+    me  = pars{2};  % Vector of the average squared original dissimilarities
+    p   = pars{3};  % p=0 -> the mean of the embedded configuration lies at 0, otherwise, it lies at pzero
+    L   = pars{4};  % Eigenvalues
+
+    % Project new data depending on p
+    % (whether the mean or other object lies at the origin)
+    if p == 0,
+      H = -repmat(1,n,n)/n;
+      H(1:n+1:end) = H(1:n+1:end) + 1;     % H = eye(n) - ones(n,n)/n
+      W = -0.5 * (d - me(ones(m,1),:)) * H * Q * diag(sqrt(abs(L))./L);
+    else
+      W =  0.5 * (d(:,p) * ones(1,n) + me(ones(m,1),:) - d) * Q * diag(sqrt(abs(L))./L);
+    end
+
+    % Store signature in the USER field
+    if isdataset(W),
+      W = setname(W,['Projected ' updname(W.name)]);
+      W = setsig(W,pars{5});
+    end
+    return
+  end
+end
+
+
+
+% REDUCE A TRAINED MAPPING
+if ismapping(d)
+  pars = getdata(d);
+  Q    = pars{1};
+  L    = pars{4};
+  m    = size(Q,1);
+
+  [ll,K] = sort(-abs(L));
+  L = L(K);
+  Q = Q(:,K);
+  [J,sig] = seleigs(L,alf,pars{6});
+  Q = Q(:,J);        % Eigenvectors
+  L = L(J);          % Eigenvalues
+
+  W = mapping(mfilename,'trained',{Q, pars{2},pars{3},L,pars{5},pars{6}},[],m,length(J));
+  W = setname(W,'PE embedding');
+  return
+end
+
+
+
+% TRAIN THE MAPPING
+% Tolerance value used in comparisons
+if mean(+d(:)) < 1,
+  tol = 1e-12;
+else
+  tol = 1e-10;
+end
+
+[n,m] = size(d);
+if ~issym(d,tol),
+  prwarning(1,'Matrix should be symmetric. It is made symmetric by averaging.')
+  d = 0.5*(d+d');
+end
+
+if pzero > n,
+  error('Wrong third parameter.');
+end
+
+d = (+d).^2;
+
+if pzero == 0,
+  % Project the data such that the mean lies at the origin
+  H = -repmat(1/n,n,n);
+  H(1:n+1:end) = H(1:n+1:end) + 1; % H = eye(n) - ones(n,n)/n
+  H = -0.5 * H * d * H;            % H is now the matrix of inner products
+else
+  % Project the data such that pzero's object lies at the origin
+  H = 0.5 * (d(:,pzero) * ones(1,n) + ones(n,1) * d(:,pzero)' - d);
+end
+H = 0.5*(H+H');                    % Make sure H is symmetric
+
+[Q,L]  = preig(H);
+Q      = real(Q);
+l      = diag(real(L));
+[lm,Z] = sort(-abs(l));
+Q      = Q(:,Z);
+l      = l(Z);                     % Eigenvalues are sorted by decreasing absolute value
+
+[J,sig] = seleigs(l,alf,prec);     % J is the index of the selected eigenvalues
+L = l(J);                          % Eigenvalues
+Q = Q(:,J);                        % Eigenvectors
+
+%A  = Q * diag(sqrt(abs(L)));      % Data in a pseudo-Euclidean space
+
+% Determine the mapping depending on pzero
+if pzero == 0,
+  W = mapping(mfilename,'trained',{Q,mean(+d,2)',pzero,L,sig,prec},[],m,sum(sig));
+else
+  W = mapping(mfilename,'trained',{Q,+d(:,pzero)',pzero,L,sig,prec},[],m,sum(sig));
+end
+W = setname(W,'PE embedding');
+return
Index: distools/pspca.m
===================================================================
--- distools/pspca.m	(revision 10)
+++ distools/pspca.m	(revision 10)
@@ -0,0 +1,157 @@
+%PSPCA Pseudo-Euclidean Principal Component Analysis
+%
+%     [W,SIG,L] = PSPCA(X,XSIG,ALF)
+%
+% INPUT
+%   X     NxK data
+%   XSIG  Signature of the input pseudo-Euclidean space; (default: [K 0])
+%   ALF   Parameter determining the dimensionality and the mapping (optional, default: Inf)
+%         (0,1)   - fraction of the total (absolute value) preserved variance
+%         Inf     - no dimensionality reduction, keeping all dimensions (it's noisy)
+%         'p'     - projection into a Euclidean space based on positive eigenvalues only
+%         'PARp'  - projection into a Euclidean space based on the PAR fraction of
+%                   positive eigenvalues; e.g. ALF = '0.9p'
+%         'n'     - projection into a Euclidean space based on negative eigenvalues only
+%         'PARn'  - projection into a (negative) Euclidean space based on the PAR fraction
+%                   of negative eigenvalues; e.g. ALF = '0.7n'
+%         'P1pP2n'- projection into a Euclidean space based on the P1 positive eigenvalues
+%                   and P2 negative eigenvalues; e.g. ALF = '0.7p0.1n', ALF = '7p2n'
+%         1 .. N  - number of dimensions in total
+%         [P1 P2] - P1 dimensions or preserved fraction of variance in the positive subspace
+%                   and P2 dimensions or preserved fraction of variance in the negative
+%                   subspace; e.g. ALF = [5 10], ALF = [0.9 0.1]
+%
+% OUTPUT
+%   W     PCA mapping in a pseudo-Euclidean space
+%   SIG   Signature of the output pseudo-Euclidean space
+%   L     List of eigenvalues
+%
+% DEFAULT
+%   XSIG = [K 0]
+%   ALF  = INF
+%
+% DESCRIPTION
+% PCA mapping W from a K-dimensional pseudo-Euclidean space to an M-dimensional
+% pseudo-Euclidean subspace. M is determined by ALF. The subspace is found, e.g.
+% such that at least a fraction ALF of the total variance is preserved for ALF
+% in (0,1). The resulting Y is found by X*W. The parameter SIG describes the
+% signature of the subspace. L is a sorted list of eigenvalues describing the
+% variances in the (pseudo-)Euclidean space.
+%
+% If X is a labeled dataset, then the averaged covariance matrix is weighted
+% by class priors.
+%
+% Note that a PCA decomposition in a pseudo-Euclidean space is different than in
+% a Euclidean space. Namely, CJ = Q*L*inv(Q), where CJ is a pseudo-Euclidean
+% covariance matrix computed such that CJ= C*J, where C is a Euclidean covariance
+% matrix, J is the fundamental symmetry (taking part in inner products). Q is
+% J-orthogonal, i.e. Q'*J*Q = J, hence inv(Q) = J*Q'*J.
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, PCA, KPSEM, PSEM
+%
+% LITERATURE
+% 1. E. Pekalska, R.P.W. Duin, The Dissimilarity representation in Pattern Recognition.
+%    Foundations and Applications. World Scientific, Singapore, 2005.
+% 2. L. Goldfarb, A unified approach to pattern recognition, Pattern Recognition, vol.17, 575-582, 1984.
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function [W,outsig,L,Q] = pspca(a,sig,alf,prec)
+
+if nargin < 4 | isempty(prec), prec = 1e-4; end
+if nargin < 3 | isempty(alf), alf = inf; end
+if nargin < 2 | isempty(sig), sig = [size(a,1) 0]; end
+if nargin < 1 | isempty(a),
+  W = mapping(mfilename,sig,alf,prec);
+  W = setname(W,'Pseudo-Euclidean PCA');
+  return
+end
+
+
+if (isdataset(a) | isa(a,'double')),
+
+  if ismapping(sig),
+    % APPLY MAPPING: project new data using the trained mapping.
+    [m,n] = size(a);
+    pars  = getdata(sig);
+
+    % Parameters
+    v   = pars{1};  % Mapping that shifts data to the origin
+    JQ  = pars{2};  % J*Q
+    sig = pars{3};  % Signature in the output space
+    W = (a*v) * JQ;
+    if isdataset(W),
+      W.user = sig;
+      W.name = updname(W.name);
+    end
+    return;
+  end
+end
+
+
+% TRAIN THE MAPPING
+[m,k] = size(a);
+if m < 2,
+  error('At least two objects are expected.');
+end
+if sum(sig) ~= k,
+  error('Signature does not fit the data dimensionality.')
+end
+isdset = isdataset(a);
+
+
+% Shift mean of data to the origin
+v  = scalem(+a);
+aa = a*v;
+
+if ~isdset,    % Unlabeled data
+  A = +aa;
+else
+  c = max(getnlab(aa));
+  if c == 0,
+    A = +aa;
+  else
+    p = getprior(a);
+    A = [];
+    for j = 1:c
+      A = [A; +seldat(aa,j)*p(j)];
+    end
+  end
+end
+G = prcov(A);
+G = 0.5*(G+G');     % Make sure G is symmetric
+if sig(2) > 0,
+  J = diag([ones(sig(1),1); -ones(sig(2),1)]);
+  G = G*J;
+end
+
+[Q,L]  = eig(G);
+Q      = real(Q);
+l      = diag(real(L));
+[lm,Z] = sort(-abs(l));
+Q      = Q(:,Z);
+l      = l(Z);
+
+[I,outsig] = seleigs(l,alf,prec); % I is the index of selected eigenvalues
+L = l(I);                         % Eigenvalues
+Q = Q(:,I);                       % Eigenvectors
+
+
+if sig(2) > 0,
+  % Q is NOT orthogonal, but should be J-orthogonal, i.e. Q'*J*Q = J
+  % Normalize Q to be J-orthogonal
+  Q = Q*diag(1./sqrt(abs(diag(Q'*J*Q))));
+  Q = J*Q;
+end
+
+
+% Determine the mapping
+W = mapping(mfilename,'trained',{v,Q,outsig,sig},[],k,sum(outsig));
+W = setname(W,'Pseudo-Euclidean PCA');
+return
Index: distools/qdistm.m
===================================================================
--- distools/qdistm.m	(revision 10)
+++ distools/qdistm.m	(revision 10)
@@ -0,0 +1,188 @@
+%QDISTM  Distance Matrix for Quantitative Variables
+%
+%     D = QDISTM (A,B,TYPE,P)
+%       OR
+%     D = QDISTM (A,B)
+%       OR
+%     D = QDISTM (A,TYPE,P)
+%       OR
+%     D = QDISTM (A,TYPE)
+%
+% INPUT
+%   A   NxK Matrix or dataset
+%   B   MxK Matrix or dataset
+%   TYPE  Type of the dissimilarity D (optional; default: 'E'):
+%           'E',  'Euclidean'
+%           'SQE','Square-Euclidean'
+%           'LP', 'LP-distance'
+%           'BC', 'Bray-Curtis'
+%           'CAN','Canberra'
+%           'COR','Correlation'
+%           'COS','Cosine'
+%           'DIV','Divergence'
+%           'EXP','Exponent'
+%           'S',  'Soergel'
+%           'SAM','Spectral-Angular-Mapper'
+%           'TAX','Taxonomic'
+%           'WS', 'Ware-Hedges'
+%   P   Parameter, P > 0 (optional, default: 1)
+%
+% OUTPUT
+%   D   NxM Dissimilarity matrix or dataset
+%
+% DESCRIPTION
+% Computation of the distance matrix D between two sets of vectors, A and B.
+% Distances between vectors X and Y are computed as:
+%   'E':   d(X,Y) = (sum_i (|X_i - Y_i|^2))^(1/2)
+%   'SQE': d(X,Y) =  sum_i (|X_i - Y_i|^2)
+%   'LP':  d(X,Y) = (sum_i (|X_i - Y_i|^P))^(1/P)
+%   'BC':  d(X,Y) =  sum_i (|X_i - Y_i|)/sum_i (X_i + Y_i)
+%   'CAN': d(X,Y) =  sum_i (|X_i - Y_i|)/sum_i (|X_i| + |Y_i|)
+%   'COR': d(X,Y) =  (1 - COV(X,Y) / sqrt(Var(X) * VAR(Y)))/2
+%   'COS': d(X,Y) =  (1 - X'*Y/(||X||*||Y||))
+%   'DIV': d(X,Y) =  sum_i {|X_i - Y_i|^2/(X_i + Y_i)^2}
+%   'EXP': d(X,Y) =  1 - exp (-(X-Y)'(X-Y)/P^2)%
+%   'S':   d(X,Y) =  sum_i (|X_i - Y_i|)/max_i {X_i,Y_i}
+%   'SAM': d(X,Y) =  P arcos (X'Y/P^2)
+%   'TAX': d(X,Y) = (sum_i |X_i - Y_i|^P/r_i^P)^(1/P)
+%   'WS':  d(X,Y) =  sum_i {1 - min_i{X_i,Y_i}/max_i{X_i,Y_i}}
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% DEFAULT
+%   B    = A
+%   TYPE = 'E'
+%   P    = 1
+%
+% SEE ALSO
+%   CORRDISTM, COSDISTM, DISTM, EXPDISTM, EUDISTM, LPDISTM, SAMDISTM,
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function D = qdistm (A,B,type,p)
+
+bisa = 0;
+if nargin < 2,
+  p    = 1;
+  B    = A;
+  type = 'E';
+  bisa = 1;
+elseif nargin < 3,
+  if isstr(B),
+    p    = 1;
+    type = B;
+    B    = A;
+    bisa = 1;
+  else
+    p    = 1;
+    type = 'E';
+  end
+elseif nargin < 4,
+  if ~isstr(type),
+    p    = type;
+    type = B;
+    B    = A;
+    bisa = 1;
+  else
+    p    = 1;
+  end
+else
+  ;
+end
+
+if ~isstr(type)
+  error ('TYPE is a string.');
+end
+
+if p <= 0,
+  error ('The parameter P must be positive.');
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a    = +A;
+b    = +B;
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+
+if ca ~= cb,
+  error ('The matrices should have the same number of columns.');
+end
+
+
+D = zeros(ra,rb);
+switch lower(type)
+  case {'e','euclidean'}
+    D = sqrt(distm(a,b));
+  case {'sqe','square-euclidean'}
+    D = distm(a,b);
+  case {'lp','lp-distance'}
+    D = lpdistm(a,b,p);
+  case {'bc','bray-curtis'}
+    for i=1:rb
+      D(:,i) = sum(abs(repmat(b(i,:),ra,1) - a),2);
+      D(:,i) = D(:,i) ./ sum((repmat(b(i,:),ra,1) + a),2);
+    end
+  case {'can','canberra'}
+    for i=1:rb
+      D(:,i) = sum( abs(repmat(b(i,:),ra,1) - a) ./ (repmat(abs(b(i,:)),ra,1) + abs(a)), 2);
+    end
+  case {'cor','correlation'}
+    D = corrdistm(a,b);
+  case {'cos','cosine'}
+    D = cosdistm(a,b);
+  case {'div','divergence'}
+    for i=1:rb
+      Z = (abs(repmat(b(i,:),ra,1) - a)).^p;
+      D(:,i) = sum (Z ./(repmat(b(i,:),ra,1) + a).^p, 2);
+      D(:,i) = D(:,i).^(1/p);
+      clear Z;
+    end
+  case {'exp','exponent'}
+    D = expdistm(a,b,p);
+  case {'sam','spectral-angular-mapper'}
+    D = samdistm(a,b,p);
+  case {'s','soergel'}
+    for i=1:rb
+      D(:,i) = sum(abs(repmat(b(i,:),ra,1) - a),2) ./ sum(max(repmat(b(i,:),ra,1),a),2);
+    end
+  case {'tax','taxonomic'}
+    rr = max(b) - min(b);
+    for i=1:rb
+      D(:,i) = sum( (abs(repmat(b(i,:),ra,1) - a)./repmat(rr,ra,1)).^p,2);
+      D(:,i) = D(:,i).^(1/p);
+    end
+  case {'ws','ware-hedges'}
+    for i=1:rb
+      D(:,i) = sum(1 -  min(repmat(b(i,:),ra,1),a) ./ max(repmat(b(i,:),ra,1),a),2);
+    end
+  otherwise
+    error('Wrong dissimilarity type.');
+end
+
+if bisa,
+  D = 0.5*(D+D');         % Make sure that distances are symmetric for D(A,A)
+end
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other is not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/rankdistm.m
===================================================================
--- distools/rankdistm.m	(revision 10)
+++ distools/rankdistm.m	(revision 10)
@@ -0,0 +1,147 @@
+%RANKDISTM  Distance matrix between two data sets based on ranking
+%
+%     D = RANKDISTM (A,B,P)
+%       or
+%     D = RANKDISTM (A,B)
+%       or
+%     D = RANKDISTM (A,P)
+%       or
+%     D = RANKDISTM (A)
+%
+% INPUT
+%   A   NxK Matrix or dataset
+%   B   MxK Matrix or dataset
+%   P   Parameter:
+%       Integer - 1 .. K or 'MIN', 'MAX', 'MEDIAN' (optional; default: 'MEDIAN')
+%
+% OUTPUT
+%   D   NxM dissimilarity matrix or dataset
+%
+% DESCRIPTION
+% Computes the distance matrix D between two sets of vectors, A and B.
+% Given the vectors X and Y, distances are computed using the ranked
+% distance as:
+%   D(X,Y) = P-th value of (sort {|X_1 - Y_1|, |X_2 - Y_2|,..,|X_K - Y_K|})
+%
+% For instance, for P = 1, the ranked distance becomes the minimum value of
+% the differences |X_i - Y_i|, or for P = K, the infinty norm.
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% DEFAULT
+% P = 'MEDIAN'
+%
+% SEE ALSO
+% LPDISTM, EUDISTM, SIMDISTM, JACSIMDISTM, CORRDISTM, COSDISTM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function D = rankdistm (A,B,kk)
+bisa = 0;
+if nargin == 3,
+  k = whichk(kk,ca);
+elseif nargin < 2,
+  k = 0;                  % median
+  B = A;
+  bisa = 1;
+else
+  k = whichk(B,ca);
+  B = A;
+  bisa = 1;
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a    = +A;
+b    = +B;
+
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+
+if ca ~= cb,
+  error ('The matrices should have the same number of columns.');
+end
+
+
+D = zeros(ra,rb);
+switch k,
+  case 0,
+    for i=1:rb
+      D(:,i) = median (abs(repmat(b(i,:),ra,1) - a),2);
+    end
+    % D = median((abs (repmat (permute(a,[1 3 2]), [1 rb 1]) - ...
+    %                  repmat (permute(b,[3 1 2]), [ra 1 1]))),3);
+  case 1,
+    for i=1:rb
+      D(:,i) = min (abs(repmat(b(i,:),ra,1) - a),[],2);
+    end
+%    D = min((abs (repmat (permute(a,[1 3 2]), [1 rb 1]) - ...
+%                  repmat (permute(b,[3 1 2]), [ra 1 1]))),[],3);
+  case ra,
+    for i=1:rb
+      D(:,i) = max (abs(repmat(b(i,:),ra,1) - a),[],2);
+    end
+%    D = max((abs (repmat (permute(a,[1 3 2]), [1 rb 1]) - ...
+%                  repmat (permute(b,[3 1 2]), [ra 1 1]))),[],3);
+  otherwise
+    for i=1:rb
+      aa = sort (abs(repmat(b(i,:),ra,1) - a),2);
+      D(:,i) = aa(:,k);
+    end
+%    aa = sort (abs (repmat (permute(a,[1 3 2]), [1 rb 1]) - ...
+%               repmat (permute(b,[3 1 2]), [ra 1 1])), 3);
+%    D  = aa(:,:,k);
+end
+
+% Check numerical inaccuracy
+D (find (D < eps)) = 0;   % Make sure that distances are nonnegative
+if bisa,
+  D = 0.5*(D+D');         % Make sure that distances are symmetric for D(A,A)
+end
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
+
+
+
+
+function k = whichk(kk,ca)
+if isstr(kk),
+  switch lower(kk),
+    case 'min'
+      k = 1;
+    case 'max'
+      k = ca;
+    case 'median',
+      k = 0;
+    otherwise
+      error ('Wrong parameter k.');
+  end
+elseif max(size(kk)) == 1,
+  k = kk;
+else
+  error ('Wrong parameter k.');
+end
+
+if k < 0 | k > ca,
+  error ('The parameter k, if an integer, must be positive and not larger then the number of features.');
+end
Index: distools/readchicken.m
===================================================================
--- distools/readchicken.m	(revision 10)
+++ distools/readchicken.m	(revision 10)
@@ -0,0 +1,20 @@
+function a = readchicken(norm,cost,dirname)
+if nargin < 3
+    dirname = ['/data/pr/projects/dissim/data/chickenpieces/chickenpieces_norm' num2str(norm) '.0'];
+		if ispc
+			dirname = ['s:\root' dirname];
+		end
+end
+if nargin < 2
+    dir(dirname)
+    a = [];
+    return
+end
+name = ['chickenpieces_norm' num2str(norm) '.0_AngleCostFunction' num2str(cost) '.0.dm'];
+a = prtbunke(fullfile(dirname,name));
+if length(a)==1 & a==-1
+    return
+end
+a = setprior(a,getprior(a,0));
+%a = min(a,a');      % starting from exp4
+a = (a + a')/2; 
Index: distools/samdistm.m
===================================================================
--- distools/samdistm.m	(revision 10)
+++ distools/samdistm.m	(revision 10)
@@ -0,0 +1,109 @@
+%SAMDISTM  Distance matrix based on Spectral Angular Mapper (SAM)
+%          distance, which is also the spherical geodesic distance
+%
+%   D = SAMDISTM (A,B,R)
+%     OR
+%   D = SAMDISTM (A,B)
+%     OR
+%   D = SAMDISTM (A,R)
+%     OR
+%   D = SAMDISTM (A)
+%
+% INPUT
+%   A   NxK matrix (dataset)
+%   B   MxK matrix (dataset)
+%   R   Radius (optional, default: 1)
+%
+% OUTPUT
+%   D   NxM dissimilarity matrix (dataset)
+%
+% DESCRIPTION
+% Computes the distance matrix D between two sets of vectors, A and B.
+% Distances between vectors X and Y are computed based on the spherical
+% geodesic formula:
+%     D(X,Y) = R arcos (X'Y/R^2)
+% X and Y are normalized to a unit length.
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% DEFAULT
+%   R = 1
+%
+% REMARKS
+% A square SAM-distance D(A,A) for a finite set A can be proved to be
+% the l_1-distance (LPDISTM). D(A,A).^{1/2} has a Euclidean behavior, so
+% it can be embedded by PSEM in a Euclidean space.
+%
+
+% SEE ALSO
+% JACSIMDISTM, CORRDISTM, LPDISTM, DISTM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function D = samdistm (A,B,r)
+
+bisa = 0;
+if nargin < 2,
+  r = 1;
+  B = A;
+  bisa = 1;
+else
+  if nargin < 3,
+    if max (size(B)) == 1,
+      r = B;
+      B = A;
+      bisa = 1;
+    else
+      r = 1;
+    end
+  end
+end
+
+if r <= 0,
+  error ('The parameter R must be positive.');
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a    = +A;
+b    = +B;
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+
+if ca ~= cb,
+  error ('The matrices should have the same number of columns.');
+end
+
+aa = sum(a.*a,2);
+bb = sum(b.*b,2)';
+D  = (a*b') ./sqrt(aa(:,ones(rb,1)) .* bb(ones(ra,1),:));
+D  = r * acos(D/r^2);
+
+% Check numerical inaccuracy
+D (find (D < eps)) = 0;   % Make sure that distances are nonnegative
+if bisa,
+  D = 0.5*(D+D');         % Make sure that distances are symmetric for D(A,A)
+end
+
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/selcdat.m
===================================================================
--- distools/selcdat.m	(revision 10)
+++ distools/selcdat.m	(revision 10)
@@ -0,0 +1,38 @@
+%SELCDAT Select Class Subset from a Square Dissimilarity Dataset
+%
+%   [DN,J] = SELCDAT(D,C)
+%
+% INPUT
+%   A   NxN Dissimilarity Dataset
+%   C   Indices of classes
+%
+% OUTPUT
+%   DN  Subset of the dataset D
+%   J   Indices of the selected objects
+%
+% DESCRIPTION
+% The classes listed in C (numerically) are extracted for the square
+% dissimilarity matrix D by both, their rows (objects) as well as their
+% columns (features).
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org, and
+% Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [D,J] = selcdat(D,n)
+issquare(D);
+if nargin < 2, return, end
+
+J = [];
+c = getsize(D,3);
+if (any(n > c))
+  error('Not that many classes')
+end
+
+for j=1:length(n)
+  J = [J; findnlab(D,n(j))];
+end
+D = remclass(D(J,J));
+return;
Index: distools/setsig.m
===================================================================
--- distools/setsig.m	(revision 10)
+++ distools/setsig.m	(revision 10)
@@ -0,0 +1,67 @@
+%SETSIG Set signature for pseudo-Euclidean dataset or mapping
+%
+%   B = SETSIG(A,SIG)
+%   B = A*SETSIG([],SIG);
+%   V = SETSIG(W,SIG);
+%
+% INPUT
+%   A    Dataset or data matrix (doubles)
+%   SIG  Signature, 2-element vector with numbers of positive
+%        and negative dimensions, default: all positive
+%   W    Pseudo-Euclidean mapping created by PE_EM
+%
+% OUTPUT
+%   B   PE dataset
+%   V   PE mapping
+%
+% DESCRIPTION
+% Distances in a PE dataset are computed in a special way, see PE_DISTM
+% using the signature of the PE space. This routine stores the signature
+% in the user-field of the dataset, so it can be used by any routine that
+% needs it. The signature is determined during a pseudo-Euclidean mapping,
+% e.g. by PSEM. Datasets applied to such a mapping obtain the signature
+% automatically. The signature is a vector of two elements equal to the
+% numbers of positive and negative eigenvalues found during the process of
+% PE mapping. Their sum should thereby be equal to the dimensionality of
+% the space, i.e. the number of features in A.
+%
+% Note that V = W*SETSIG converts a pseudo-Euclidean mapping W into a
+% mapping V to the associated space.
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, PE_EM, PE_DISTM, GETSIG
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function b = setsig(a,sig)
+
+  if nargin < 2, sig = []; end
+  if nargin < 1 | isempty(a)
+    b = mapping(mfilename,'fixed',{sig});
+    b = setname(b,'Set signature');
+    return
+  end
+  
+  if isempty(sig), sig = [size(a,2) 0]; end
+  if length(sig) ~= 2
+    error('The PE signature should consist of a vector of two elements');
+	end
+	
+	if sum(sig) ~= size(a,2)
+		error('The signature does not match the feature size')
+	end
+	if ispe_em(a)
+		data = getdata(a);
+		data.sig = sig;
+		b = setdata(a,data);
+	else
+		a = dataset(a);
+        	b = setuser(a,sig,'pe_signature');
+	end
+  
+return
+  
+  
+  
Index: distools/sigmoid.m
===================================================================
--- distools/sigmoid.m	(revision 10)
+++ distools/sigmoid.m	(revision 10)
@@ -0,0 +1,33 @@
+%SIGMOID Element-wise Sigmoid Tranformation of a Matrix
+%
+%   F = SIGMOID(A,S)
+%
+% INPUT
+%   A   NxM matrix (dataset)
+%   S   Scale parameter (optional, default: 1)
+%
+% OUTPUT
+%   F   NxM matrix (dataset)
+%
+% DESCRIPTION
+% Applies sigmoid transformation to the elements of A.
+% The values of F are in (0,1] for positive values of A and
+% in [-1,0) for negative values.
+%
+% DEFAULT
+%   S = 1
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function F = sigmoid(A,s)
+
+if nargin < 2,
+  s = 1;
+end
+
+F = 2./(1+exp(-A/s)) - 1;
+return;
Index: distools/simdistm.m
===================================================================
--- distools/simdistm.m	(revision 10)
+++ distools/simdistm.m	(revision 10)
@@ -0,0 +1,81 @@
+%SIMDISTM  Distance matrix between two data sets found from similarities
+%
+%   D = SIMDISTM (A,B)
+%
+% INPUT
+%   A   NxK matrix or dataset
+%   B   MxK matrix or dataset (optional; default: B=A)
+%
+% OUTPUT
+%   D   NxM dissimilarity matrix or dataset; D in [0,1]
+%
+% DESCRIPTION
+% Computes the distance matrix D between two sets of vectors: A and B.
+% Distances between vectors X and Y are computed based on the similarity
+% formula:
+%     SIM(X,Y) = 2 * (X'Y) / (||X||^2 + ||Y||^2)
+%     D(X,Y)   = (1 - SIM(X,Y))
+%
+% If A and B are datasets, then D is a dataset as well with the labels defined
+% by the labels of A and the feature labels defined by the labels of B. If A is
+% not a dataset, but a matrix of doubles, then D is also a matrix of doubles.
+%
+% DEFAULT
+%   B = A
+%
+% SEE ALSO
+% JACSIMDISTM, CORRDISTM, COSDISTM, LPDISTM, EUDISTM
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function D = simdistm(A,B)
+
+bisa = nargin < 2;
+if bisa,
+  B = A;
+end
+
+isda = isdataset(A);
+isdb = isdataset(B);
+a = +A;
+b = +B;
+
+[ra,ca] = size(a);
+[rb,cb] = size(b);
+
+if ca ~= cb,
+  error ('Matrices should have equal numbers of columns');
+end
+
+
+aa = sum(a.*a,2);
+bb = sum(b.*b,2)';
+D  = (2 * (a * b')) ./ (aa(:,ones(rb,1)) + bb(ones(ra,1),:));
+D  = 1 - D;
+
+% Check numerical inaccuracy
+D (find (D < eps)) = 0;   % Make sure that distances are nonnegative
+if bisa,
+  D = 0.5*(D+D');         % Make sure that distances are symmetric for D(A,A)
+end
+
+
+% Set object labels and feature labels
+if xor(isda, isdb),
+  prwarning(1,'One matrix is a dataset and the other not. ')
+end
+if isda,
+  if isdb,
+    D = setdata(A,D,getlab(B));
+  else
+    D = setdata(A,D);
+  end
+  D.name = 'Distance matrix';
+  if ~isempty(A.name)
+    D.name = [D.name ' for ' A.name];
+  end
+end
+return
Index: distools/sphem.m
===================================================================
--- distools/sphem.m	(revision 10)
+++ distools/sphem.m	(revision 10)
@@ -0,0 +1,154 @@
+%SPHEM Spherical Embedding
+%
+%       [W,SIG,L] = SPHEM(D,R,ALF)
+%                 OR
+%       [W,SIG,L] = SPHEM(W,ALF)
+%
+% INPUT
+%   D   NxN symmetric dissimilarity matrix (dataset)
+%   W   Trained linear embedding into a pseudo-Euclidean space
+%   ALF Parameter determining the dimensionality and the mapping (optional, defaulf: Inf)
+%       (0,1)   - fraction of the total (absolute value) preserved variance
+%        Inf    - no dimensionality reduction, keeping all dimensions (it's noisy)
+%       'p'     - projection into a Euclidean space based on positive eigenvalues only
+%       'PARp'  - projection into a Euclidean space based on the PAR fraction of
+%                 positive eigenvalues; e.g. ALF = '0.9p'
+%       'n'     - projection into a Euclidean space based on negative eigenvalues only
+%       'PARn'  - projection into a (negative) Euclidean space based on the PAR fraction
+%                 of negative eigenvalues; e.g. ALF = '0.7n'
+%       'P1pP2n'- projection into a Euclidean space based on the P1 positive eigenvalues
+%                 and P2 negative eigenvalues; e.g. ALF = '0.7p0.1n', ALF = '7p2n'
+%       1 .. N  - number of dimensions in total
+%       [P1 P2] - P1 dimensions or preserved fraction of variance in the positive subspace
+%                 and P2 dimensions or preserved fraction of variance in the negative
+%                 subspace; e.g. ALF = [5 10], ALF = [0.9 0.1]
+%   P   Integer between 0 and N specifying which object is mapped at the origin;
+%       0 stands for the mean; (optional, default: 0)
+%
+% OUTPUT
+%   W   Linear embedding into a pseudo-Euclidean space
+%   SIG Signature of the space
+%   L   List of eigenvalues
+%
+% DESCRIPTION
+% Linear mapping W onto an M-dimensional pseudo-Euclidean subspace from a symmetric,
+% square dissimilarity matrix D such that the dissimilarities are preserved. M
+% M is determined by ALF. E.g., the subspace is found such that at least a fraction
+% ALF of the total variance is preserved for ALF in (0,1). The resulting X is found
+% by D*W. The parameter SIG describes the signature of the subspace. L is a sorted
+% list of eigenvalues describing the variances in the (pseudo-)Euclidean space.
+%
+% A trained mapping can be reduced further by:
+%   [W,SIG,L] = SPHEM(D,ALF)
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, PSEM, AUGPSEM, PCA
+%
+% LITERATURE
+% 1. L. Goldfarb, A unified approach to pattern recognition, Pattern Recognition, vol.17, 575-582, 1984.
+% 2. E. Pekalska, P. Paclik, and R.P.W. Duin, A Generalized Kernel Approach to Dissimilarity-based
+%    Classification, Journal of Machine Learning Research, vol.2, no.2, 175-211, 2002.
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+
+function [W,sig,L,Q] = sphem(d,R,alf,prec)
+if nargin < 4 | isempty(prec), prec = 1e-4; end
+if nargin < 3 | isempty(alf), alf = inf; end
+if nargin < 2 | isempty(R), R = 1; end
+if nargin < 1 | isempty(d),
+  W = mapping(mfilename,{R,alf,prec});
+  W = setname(W,'Spherical embedding');
+  return
+end
+
+
+
+if (isdataset(d) | isa(d,'double'))
+  if ismapping(R)
+
+    % APPLY THE MAPPING
+    pars  = getdata(R);
+    [m,n] = size(d);
+
+    R = pars{1};  % radius
+    Q = pars{2};  % Eigenvectors
+    L = pars{3};  % Eigenvalues
+
+    W = R^2*(cos(+d/R)) * Q * diag(sqrt(abs(L))./L);
+    if isdataset(d),
+      W = dataset(W,getlab(d),'prior',getprior(d));
+
+      % Store signature in the USER field
+      W.user = pars{4};    % Signature
+      W.name = ['Projected '  updname(d.name)];
+    end
+    return
+  end
+end
+
+
+
+% REDUCE ALREADY TRAINED MAPPING
+if ismapping(d)
+  pars = getdata(d);
+  R = pars{1};  % radius
+  Q = pars{2};  % Eigenvectors
+  L = pars{3};
+  m = size(Q,1);
+
+  [ll,K] = sort(-abs(L));
+  L = L(K);
+  Q = Q(:,K);
+  [J,sig] = seleigs(L,alf,pars{5});
+  Q = Q(:,J);        % Eigenvectors
+  L = L(J);          % Eigenvalues
+
+  W = mapping(mfilename,'trained',{R,Q,L,pars{4},pars{5}},[],m,length(J));
+  W = setname(W,'Spherical embedding');
+  return
+end
+
+
+
+% TRAIN THE MAPPING
+
+% Tolerance value used in comparisons
+if mean(+d(:)) < 1,
+  tol = 1e-12;
+else
+  tol = 1e-10;
+end
+
+if R <= 0,
+  error('R should be positive.');
+end
+
+
+[n,m] = size(d);
+if ~issym(d,tol),
+  prwarning(1,'Matrix should be symmetric. It is made symmetric by averaging.')
+  d = 0.5*(d+d');
+end
+
+B = R^2*cos(+d/R);
+B = 0.5*(B+B');                       % Make sure B is symmetric
+
+[Q, L] = preig(B);
+Q      = real(Q);
+l      = diag(real(L));
+[lm,Z] = sort(-abs(l));
+Q      = Q(:,Z);
+l      = l(Z);                % Eigenvalues are sorted by decreasing absolute value
+
+[J,sig] = seleigs(l,alf,prec);% J is the index of the selected eigenvalues
+L = l(J);                     % Eigenvalues
+Q = Q(:,J);                   % Eigenvectors
+
+W = mapping(mfilename,'trained',{R,Q,L,sig,prec},[],m,sum(sig));
+W = setname(W,'Spherical  embedding');
+return
Index: distools/strkerm.m
===================================================================
--- distools/strkerm.m	(revision 10)
+++ distools/strkerm.m	(revision 10)
@@ -0,0 +1,137 @@
+%STRKERM  String Kernel Matrix by Lodhi et al
+%
+% 	[K,KK] = STRKERM (A,B,W,LAM,KNORM)
+%
+% INPUT
+%   A     Cell structure of N strings or a single string
+%   B     Cell structure of M strings or a single string (optional; default: B = A)
+%   W     Vector of K weights (optional; default: [1 1])
+%   LAM   Decay factor Weight parameter in (0,1] used to scale the intermediate kernels
+%         (optional; default: 1)
+%   KNORM Parameter (0/1) indicating whether the kernel should be normalized
+%         to remove bias wrt to text length (optional; default: 1)
+%
+% OUTPUT
+%   K 		NxM kernel matrix
+%   KK		NxMxK matrix of intermediate kernels
+%
+% DESCRIPTION
+% Derives a string kernel matrix K following the idea of Lodhi et al [2002]. A and B are 
+% either individual strings or cell structures of strings. The basic idea is to compute 
+% the kernel as an inner product of the feature vectors for two strings and give a sum 
+% over all common subsequences weighted according to their frequency of occurrence and 
+% lengths. Dynamic programming is used to compute the kernel values between strings. 
+% If dataset is needed, it should be created afterwards.
+%
+% DEFAULT
+%   B     = A
+%   W     = [1 1]
+%   LAM   = 1
+%   KNORM = 1
+%
+% REFERENCE
+% H.Lodhi, C.Saunders, J. Shawe-Taylor, N.Cristianini, C.Watkins, "Text
+% Classification using String Kernels", J. of Machine Learning Research 2,
+% 419-444, 2002.
+%
+
+% Copyright: Elzbieta Pekalska, ela.pekalska@googlemail.com
+% EWI Faculty, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [K,KK] = strkerm (a,b,w,lam,Knorm)
+if nargin < 5,
+  Knorm = 1;
+end
+if nargin < 4 | isempty(lam),
+  lam = 1;
+end
+if nargin < 3 | isempty(w),
+  w = [1 1];
+end
+if nargin < 2 | isempty(b),
+  b = a;
+end
+
+if any(w) < 0,
+  error('Weights should be nonnegative.');
+end
+
+if ~iscell(a),
+  if isstr(a) | (~isstr(a) & min(size(a)) == 1)
+    a = {a};
+  else
+    error('A is improper.');
+  end
+end
+if ~iscell(b),
+  if isstr(b) | (~isstr(b) & min(size(b)) == 1)
+    b = {b};
+  else
+    error('B is improper.');
+  end
+end
+
+
+m = length(a);
+n = length(b);
+
+
+K = zeros(m,n);
+for i=1:m
+  for j=1:n
+    K(i,j) = strkernel(a{i},b{j},w,lam);
+  end
+end
+
+if Knorm,
+  for i=1:m
+    Kaa(i,1) = strkernel(a{i},a{i},w,lam);
+  end
+  for j=1:n
+    Kbb(1,j) = strkernel(b{j},b{j},w,lam);
+  end
+  K = K ./ sqrt(Kaa*Kbb);
+end
+return;
+
+
+
+
+
+
+function K = strkernel(s,t,w,lam)
+
+if isstr(s),
+  s = ['a',s];
+  t = ['a',t];
+else
+  if size(s,1) > size(s,2)
+    s = [s(1); s];
+    t = [s(1); t];
+  else
+    s = [s(1) s];
+    t = [s(1) t];
+  end
+end
+
+ns = length(s);
+nt = length(t);
+n  = length(w);
+
+K = 0;
+KK(:,:,1) = ones(ns+1,nt+1);
+for i=1:n
+  KK(:,:,i+11) = zeros(ns+1,nt+1);
+  for j=1:ns
+    ss = 0;
+    for k=1:nt
+      if t(k) == s(j),
+        ss = ss + KK(j,k,i);
+      end
+      KK(j+1,k+1,i+1) = KK(j,k+1,i+1) +ss;
+    end
+  end
+  K = K + w(i)*KK(ns+1,nt+1,i+1)*lam^(2*i);
+end
Index: distools/testkd.m
===================================================================
--- distools/testkd.m	(revision 10)
+++ distools/testkd.m	(revision 10)
@@ -0,0 +1,98 @@
+%TESTKD Test k-NN classifier for dissimilarity data
+%
+%   [E,C] = TESTKD(D,K,PAR)
+%
+% INPUT
+%   D    Dissimilarity dataset. Object labels are assumed to be the
+%        true labels. Feature labels are assumed to be the labels of
+%        the objects they are related to.
+%   K    Desired number of neighbors to take into account, default K = 1.
+%   PAR  'LOO' - leave-one-out option. This should be used if
+%          the objects are related to themselves. If D is not square,
+%          it is assumed that the first sets of objects in columns and
+%          rows match.
+%        'ALL' - use all objects (default).
+%
+% OUTPUT
+%   E    Estimated error
+%   C    Matrix with confidences, size M x N, if D has size M x L and
+%        the labels are given for N classes. Note that for K < 3 these
+%        confidences are derived from the nearest neigbor distances
+%        and that for K >= 3 they are the Bayes estimators of the 
+%        neighborhood class probabilities.
+%
+% DESCRIPTION
+% TESTKD is based on just counting errors and does not weight with 
+% testobject priors.
+%
+% SEE ALSO
+% DATASETS, KNNDC
+
+% Copyright: R.P.W. Duin, r.duin@ieee.org
+% Faculty EWI, Delft University of Technology
+
+
+function [e,F] = testkd(d,knn,par)
+
+if nargin < 3 | isempty(par), par = 'all'; end
+if nargin < 2 | isempty(knn), knn = 1; end
+
+isdataset(d);
+
+nlab     = getnlab(d);
+lablist  = getlablist(d);
+featlist = getfeat(d);
+[m,k]  = getsize(d);
+p        = getprior(d);
+
+[clab,classlist] = renumlab(featlist);
+%[cl,nc,labl] = renumlab(classlist,lablist);
+%if size(labl,1) > c
+%	error('Object labels do not match representation set.')
+%end
+                   % correct for different classlist - lablist orders
+J = matchlablist(classlist,lablist);
+classlist = lablist;
+clab = J(clab);
+c = max(clab);
+
+if strcmp(upper(par),'LOO')
+	% get rid of leave-one-out problems
+	km = min(k,m);
+	dmax=max(max(+d))*2;
+	d(1:km,1:km) = d(1:km,1:km) + dmax*eye(km);
+elseif ~strcmp(upper(par),'ALL')
+	error(['Unknown option ''' par ''''])
+end
+
+
+% find class frequencies in representation set			
+% r = zeros(1,c);
+% for j=1:c
+% 	r(j) = length(find(clab==j));
+% end
+
+%D = ones(m,c);
+[DD,L] = sort(+d',1);			% sort distances
+L = clab(L);
+for j = 1:c     				% find label frequencies
+	F(:,j) = sum(L(1:knn,:)==j,1)';
+end
+K = max(F');
+%for j = 1:c
+%	K = min(K,r(j));  
+%	J = reshape(find(L==j),r(j),m); % find the distances to the
+%	J = J(K+[0:m-1]*r(j));		% objects of that neighbor
+%	D(:,j) = DD(J)';			% number for all classes
+%end
+                                % estimate posterior probabilities
+%if knn > 2					    % use Bayes estimators on frequencies
+	F = (F+1)/(knn+c);
+	%else						% use distances
+%  F = sigm(log(sum(D,2)*ones(1,c)./(D+realmin) - 1 + realmin));
+%end
+F = F ./ (sum(F,2)*ones(1,c));
+F = setdata(d,F,classlist);
+%e = F*testc; % goes wrong in case of LOO testing (empty classes)
+labf = F*labeld;  
+e = nlabcmp(labf,getlabels(F))/m;
Index: distools/testpd.m
===================================================================
--- distools/testpd.m	(revision 10)
+++ distools/testpd.m	(revision 10)
@@ -0,0 +1,77 @@
+%TESTPD Test Parzen classifier for dissimilarity data
+%
+%   [E,C] = TESTPD(D,H,PAR)
+%
+% INPUT
+%   D    Dissimilarity dataset. Object labels are assumed to be the
+%        true labels. Feature labels are assumed to be the labels of
+%        the objects they are related to.
+%   H    Desired smoothing parameter.
+%   PAR  'loo' - leave-one-out option. This should be used if
+%        the objects are related to themselves. If D is not square,
+%        it is assumed that the first sets of objects in columns and
+%        rows match.
+%        'all' - use all objects (default).
+%
+% OUTPUT
+%   E    Estimated error
+%   C    Matrix with confidences, size M x N, if D has size M x L and
+%        the labels are given for N classes. 
+%
+% SEE ALSO
+% DATASETS, KNND, TESTKD
+
+% Copyright: R.P.W. Duin, r.p.w.duin@prtools.org
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+function [e,F] = testkd(d,h,par)
+
+if nargin < 3 | isempty(par), par = 'all'; end
+if nargin < 2 | isempty(h), [w,h] = parzenddc(d); end
+
+isdataset(d);
+
+nlab     = getnlab(d);
+lablist  = getlablist(d);
+featlist = getfeat(d);
+[m,k,c]  = getsize(d);
+p        = getprior(d);
+
+[clab,classlist] = renumlab(featlist);
+c = max(clab);
+%[cl,nc,labl] = renumlab(classlist,lablist);
+%if size(labl,1) > c
+%	error('Object labels do not match representation set')
+%end
+                   % correct for different classlist - lablist orders
+J = matchlablist(classlist,lablist);
+classlist = lablist;
+clab = J(clab);
+
+if strcmp(par,'loo')
+	% get rid of leave-one-out problems
+	km = min(k,m);
+	dmax=max(max(+d))*100;
+	d(1:km,1:km) = d(1:km,1:km) + dmax*eye(km);
+elseif ~strcmp(par,'all')
+	error(['Unknown option ''' par ''''])
+end
+
+s = exp(-(d.^2)/(2*h*h));
+
+F = zeros(m,c);
+for j=1:c
+  L = find(clab==j);
+  F(:,j) = mean(s(:,L),2)*p(j);
+  if strcmp(par,'loo')
+    if length(L) == 1
+      F(L,j) = 0;
+    else
+      F(L,j) = length(L)*F(L,j)/(length(L)-1); % correct for LOO
+    end
+  end
+end
+%F = F ./ (sum(F,2)*ones(1,c));
+F = setdata(d,F,classlist);
+e = F*testc;
Index: distools/tqdc.m
===================================================================
--- distools/tqdc.m	(revision 10)
+++ distools/tqdc.m	(revision 10)
@@ -0,0 +1,150 @@
+%TQDC Trade-off Quadratic Discriminant (Regularized Bayes Normal Classifier)
+%
+%   W = TQDC(A,ALF,R,S,DIM)
+%
+% INPUT
+%   A   NxK dataset (N points in a K-dimensional space)
+%   ALF Trade-off parameter, ALF in [0,1] (optional; default: ALF = 0.1)
+%   R,S Additional regularization parameters, 0 <= R,S <= 1
+%       (optional; default: no regularization, i.e. R,S = 0)
+%   DIM Dimension of subspace structure in covariance matrix (default: K)
+%
+% OUTPUT
+%   W   Quadratic Bayes Normal Classifier mapping
+%
+% DESCRIPTION
+% Computation of the quadratic classifier between the classes of the dataset
+% A assuming normal densities. Each class covariance matrix Gi (i=1..C) is
+% modeled as a convex combination between the original class covariance Gi and
+% the diagonal marix Gdiag retrieved from the overall weighted (by priors)
+% covariance matrix. So,
+%     Gi = (1-ALF)*Gi + ALF*Gdiag
+% If ALF=0, then you will get QDC.
+% If ALF=1, then you will get NMSC.
+%
+% R and S (0 <= R,S <= 1) are additional parameters used for regularizing the
+% resulting covariance matrices by
+%     Gi = (1-R-S)*Gi + R*diag(diag(Gi)) + S*mean(diag(Gi))*eye(size(Gi,1))
+% This covariance matrix is then decomposed as Gi = W*W' + sigma^2 * eye(K),
+% where W is a KxM matrix containing the M leading principal components.
+%
+% The use of soft labels is supported. The classification A*W is computed by
+% NORMAL_MAP.
+%
+% DEFAULT
+% ALF = 0.1
+% R   = 0
+% S   = 0
+% DIM = K (data dimension)
+%
+% EXAMPLES
+% PREX_MCPLOT, PREX_PLOTC.
+%
+% REFERENCES
+% 1. R.O. Duda, P.E. Hart, and D.G. Stork, Pattern classification, 2nd
+% edition, John Wiley and Sons, New York, 2001.
+% 2. A. Webb, Statistical Pattern Recognition, John Wiley & Sons,
+% New York, 2002.
+%
+% SEE ALSO
+% MAPPINGS, DATASETS, NMC, NMSC, LDC, UDC, QDC, QUADRC, NORMAL_MAP
+
+% Copyright: R.P.W. Duin, E. Pekalska, D.M.J. Tax and P. Paclik
+% ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function w = tqdc(a,alf,r,s,dim)
+
+if (nargin < 5)
+  prwarning(4,'Subspace dimensionality DIM not provided, assuming K.');
+  dim = [];
+end
+if (nargin < 4)
+  prwarning(4,'Regularisation parameter S not given, assuming 0.');
+  s = 0;
+end
+if (nargin < 3)
+  prwarning(4,'Regularisation parameter R not given, assuming 0.');
+  r = 0;
+end
+if (nargin < 2)
+  prwarning(4,'Trade-off parameter ALF not given, assuming 0.1.');
+  alf = 0.1;
+end
+
+% No input arguments: return an UNTRAINED mapping
+if (nargin < 1) | (isempty(a))
+  w = mapping(mfilename,{alf,r,s,dim});
+  w = setname(w,'Trade-off Bayes-Normal-2');
+  return
+end
+
+
+% TRAIN the classifier
+islabtype(a,'crisp','soft');
+isvaldset(a,2,2);        % at least 2 objects per class and 2 classes
+
+[m,k,c] = getsize(a);
+
+% If the subspace dimensionality is not given, set it to the data dimensionality.
+if (isempty(dim)),
+  dim = k;
+end
+
+if (dim < 1) | (dim > k)
+  error ('Number of dimensions DIM should lie in the range [1,K].');
+end
+
+% Assert whether A has the right labtype.
+islabtype(a,'crisp','soft');
+
+% Get mean vectors and class covariance matrices.
+[U,G] = meancov(a);
+
+% Calculate means and priors.
+pars.mean  = +U;
+pars.prior = getprior(a);
+
+% in the NMSC limit:
+Gtot = zeros(c,k);
+for j = 1:c
+  Gtot(j,:) = diag(G(:,:,j))';
+end
+Gtot = diag(pars.prior*Gtot);
+
+% Calculate class covariance matrices.
+
+pars.cov   = zeros(k,k,c);
+for j = 1:c
+  F = G(:,:,j);
+  F = (1-alf)*F + alf*Gtot;
+
+  % Regularize, if requested.
+  if (s > 0) | (r > 0)
+    F = (1-r-s) * F + r * diag(diag(F)) +s*mean(diag(F))*eye(size(F,1));
+  end
+
+  % If DIM < K, extract the first DIM principal components and estimate
+  % the noise outside the subspace.
+
+  if (dim < k)
+    [eigvec,eigval] = preig(F);
+    eigval = diag(eigval);
+    [dummy,ind] = sort(-eigval);
+
+    % Estimate sigma^2 as avg. eigenvalue outside subspace.
+    sigma2 = mean(eigval(ind(dim+1:end)));
+
+    % Subspace basis: first DIM eigenvectors * sqrt(eigenvalues).
+    F = eigvec(:,ind(1:dim)) * diag(eigval(ind(1:dim))) * eigvec(:,ind(1:dim))' + sigma2 * eye(k);
+  end
+  pars.cov(:,:,j) = F;
+end
+
+w = mapping('normal_map','trained',pars,getlab(U),k,c);
+w = setname(w,'Trade-off Bayes-Normal-2');
+w = setcost(w,a);
+
+return;
Index: distools/vat.m
===================================================================
--- distools/vat.m	(revision 10)
+++ distools/vat.m	(revision 10)
@@ -0,0 +1,72 @@
+% VAT  Visual Assessment of cluster Tendency for dissimilarity matrices
+%
+%   DN = VAT(D)
+%
+% INPUT
+%   D   NxN symmetric dissimilarity matrix (dataset)
+%
+% OUTPUT
+%   P   Order of elements
+%   DN  Reorded and scaled dissimilarity matrix
+%
+% DESCRIPTION
+% Visualization of the distance matrix to emphasize cluster tendencies
+% by reordering the rows and columns in the distance matrix.
+%
+% REFERENCE
+% R.J.Hathaway, J.C.Bezdek, J.M.Huband, "Scalable visual assessment of
+% cluster tendency for large data sets", Pattern Recognition, vol. 39,
+% no. 7, 2006.
+%
+
+% Copyright: Pavel Paclik, Elzbieta Pekalska, ela.pekalska@googlemail.com
+% Faculty EWI, Delft University of Technology and
+% School of Computer Science, University of Manchester
+
+
+function [P,DN] = vat(D)
+
+D = +D;
+n = size(D,1);
+K = (1:n)';
+I = [];
+J = [];
+P = [];
+
+[i,j] = mmind(D,'max');
+
+P(1) = i(1);
+I    = i(1);
+J    = setdiff(K,I);
+
+for r=2:n
+  [i,j] = mmind(D(I,J),'min');
+  i     = I(i(1));
+  j     = J(j(1));
+
+  P = [P; j];
+  I = [I; j];
+  J = setdiff(J,j);
+end
+if nargout >1
+  DN = D(P,P);
+
+  % make linear stretch
+  mi = min(min(D));
+  ma = max(max(D));
+  k  = 256/(ma-mi);
+  DN = floor(k*DN-mi*k);
+end
+return
+
+
+
+
+function [i,j] = mmind(A,FUNC)
+% Return all indices that are maximum (minimum) in the matrix.
+% Function is specified by the FUNC string.
+
+eval(['[m,ind]=' FUNC '(' FUNC '(A));']);
+ind   = find(A==m(1));
+[i,j] = ind2sub(size(A),ind);
+return
