Index: /hypertools/hypertools/Contents.m
===================================================================
--- /hypertools/hypertools/Contents.m	(revision 3)
+++ /hypertools/hypertools/Contents.m	(revision 3)
@@ -0,0 +1,84 @@
+% Hypertools toolbox, Version 2.2 [2 November 2005]
+% (C) P.Paclik, S.Verzakov, R.P.W.Duin, TU Delft
+% P.Paclik@ewi.tudelft.nl
+%
+% Data handling
+% data2dip             Convert image in a dataset into a dip image
+% dip2data             Convert a dip image into a dataset
+% getli                Return label image from a dataset or label vector
+% setli                Set labels in the dataset from the label image
+% isdipinstalled       Tests if DIPimage is installed
+% 
+% Visualization of spectral data
+% drawident            Draw overlay image highlighting identifiers of dataset subset
+% fig2dip              Retrieve DIP images from figures via handles or indices
+% get_spec_colormap    Generate colormap for label images
+% plots                Plot spectra
+% chemimage            Create an image rendering the area under the part of spectra
+% showsi               Show spectral image
+% si_attach_display    Attach an additional display to the spectral image
+% si_dettach_display   Dettach an additional display to the spectral image
+% si_get_spectra       Get spectra marked in spectral image
+% si_set_ylim          Set the ylim of the spectral figure
+% speccolormap         Set the spectral colormap
+% 
+% Preprocessing
+% basesubm             Baseline subtraction mapping
+% derfilter            Gaussian derivative filter
+% smoothm              Smoothing and derivatives mapping
+% specnormm            Spectral normalization mapping
+% subsamplem           Spectral subsampling mapping
+% 
+% Dissimilarity data representations
+% dissimm              General dissimilarity mapping
+% dasam                Spectral Angle Mapper (using acos)
+% dsam                 Spectral Angle Mapper (normalized inner product)
+% dcityblock           City-block (Manhattan) distance
+% dkl                  Kullback-Leibler divergence
+% dkolmogorov          Kolmogorov distance
+% dmatch               Match distance
+% dquadform            Quadratic-form distance
+% dshape               Spectral distance using shape (Savitsky-Golay smoothing)
+% dspec_shape          Spectral distance using shape (Gaussian smoothing)
+% protoselm            Prototype selection mapping
+% 
+% Unmixing
+% opam                 Orthogonal projection approach: selects "pure" features
+% opaps                Orthogonal projection approach: selects "pure" objects
+% varimaxfm            Extracts sparse (pure) features 
+% varimaxom            Extracts sparse (pure) objects
+% als                  Alterating least squares
+%
+% Feature extraction methods
+% ccam                 Canonical Correlation Analysis mapping
+% gldbm                Generalised Local Discriminant Bases GLDB (bottom-up, Fisher crit)
+% gldbm_cat            Concatenate GDLB mappings
+% gldbm_featsel        Select bases in GLDB mapping using a feat.sel. mapping
+% gldbm_mc_featsel     Apply the feature selection to a multi-class GLDB mapping
+% gldbm_multi          GLDB bottom-up, multi-class crit using Fisher separability
+% gldbm_td             GLDB using top-down criterion (Fisher separability)
+% gldbm_td_ae          GLDB using top-down criterion (apparent error)
+% gldbm_td_prob        GLDB using top-down criterion (Log-odds)
+% maf                  Maximum autocorrelation mapping
+% nlgldbm              Non-linear Fisher multi-class GLDB (bottom-up) mapping for spectra
+% pcashave             PCA shaving algorithm
+% plot_cca             Superimpose training and test data projected by CCA
+% plot_gldb_groups     Plot groups selected by GLDB
+% simcam               Supervised SIMCA mapping
+% 
+% featself_simple      Simple forward feature selection
+% randfeatselm         Random feature selection with validation
+% genfeatsel           Genetic feature selection algorithm
+% 
+% Image segmentation
+% pcaclust             PCA clustering
+% segment_comb         Segmentation combining spatial and spectral domains
+% 
+% Classification
+% corrc                Correlation classifier
+% samc                 Spectral Angle Mapper classifier
+% simcac               Supervised SIMCA classifier
+% liknonc              Liknon feature extractor and classifier
+% maxsimc              Maximum similarity classifier
+% mindistc             Minimum distance classifier
+%
Index: /hypertools/hypertools/als.m
===================================================================
--- /hypertools/hypertools/als.m	(revision 3)
+++ /hypertools/hypertools/als.m	(revision 3)
@@ -0,0 +1,225 @@
+%ALS Alterating least squares
+%
+%  [Z, Y] = als(X,Y,OPT) % pure samples mode
+%
+%  [Z, Y] = als(X,Z,OPT) % pure features mode
+%
+% INPUT 
+%   X             [M -by- K] training dataset
+%   Y             [N -by- K] set of candidate pure samples
+%   Z             [M -by- N] set of candidate pure features
+%
+%   OPT.          options
+%    MODE         'samples' (Y), 'features' (Z), or 'auto' mode; in automatic regime the selection of the real mode
+%                 will be made using the sizes of input datasets; if both input datasets have the same sizes then 
+%    CROP_MODE    'features', 'samples', 'all' (all by default)
+%                 automatic selection will fail; by default = 'auto'
+%    MAX_ITER     the max number of iterations; by default = 25
+%    CRIT         type of stopping criterion: small changes in the solution ('convergence') or
+%                 small reconstruction error ('reconstruction'); by default = 'convergence'
+%    EPS          value for stopping criterion; by default = 1e-2
+%    VERBOSE      force/disable messages: PRPROGRESS(VERBOSE,['%s\n'],MSG) will be run;
+%                 by default = []
+%
+%
+% OUTPUT 
+%   Y             [N -by- K] set of spectra of pure components
+%   Z             [M -by- N] set of concentrations of pure components
+%
+% DESRIPTION
+% An iterative approcach to the least square problem with positive constraints:
+% X = Z*Y at X,Y,Z >=0
+% 
+% Input are a (non-negative) dataset (X) and a set of candidate pure samples (Y) or
+% a set of candidate pure features (Z).
+%
+% SEE ALSO
+% SIMPLISMAM, VARIMAXFM, SIMLISMAPS, OPAPS, VARIMAXOM, ALS, OPA
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: als.m,v 1.16 2007/03/15 16:10:24 serguei Exp $
+
+function [Z, Y] = als(X,Y,Options)
+
+if nargin < 3
+  Options = [];
+end
+
+DefOptions.mode      = 'auto'; % 'samples' | 'features' | 'auto'
+DefOptions.crop_mode = 'all'; % 'samples' | 'features' | 'all'
+DefOptions.max_iter  = 25;
+DefOptions.crit      = 'convergence'; % 'convergence' | 'reconstruction'
+DefOptions.eps       = 1e-2;
+DefOptions.verbose   = [];
+
+Options = updstruct(DefOptions, Options);
+
+%----------------
+if isa(X,'dataset') 
+  featlab  = X.featlab;
+  featsize = X.featsize;
+  data_X = X;
+
+  data_X.data = zeros([size(X,1),1]);
+  X = +X;
+else  
+  data_X = [];
+end   
+
+if isa(Y,'dataset') 
+  data_Y = Y;
+  data_Y.data = zeros([size(Y,1),1]);
+  Y = +Y;
+else  
+  data_Y = [];
+end  
+
+prprog = exist('prprogress');
+if ~prprog & isempty(Options.verbose)
+  Options.verbose = 0;
+end
+%----------------
+
+%if strcmp(Options.mode,'features')
+%  X = X';
+%  Y = Y';
+%end
+
+if size(X,1) > size(Y,1) & size(X,2) == size(Y,2)
+  if strcmp(Options.mode ,'features')
+    error('Not proper size of pure features dataset');
+  end
+  Options.mode = 'samples';
+elseif size(X,1) == size(Y,1) & size(X,2) > size(Y,2)
+  if strcmp(Options.mode ,'samples')
+    error('Not proper size of pure samples dataset');
+  end
+  Options.mode = 'features';
+  X = X';
+  Y = Y';
+elseif size(X,1) == size(Y,1) & size(X,2) == size(Y,2)
+  if strcmp(Options.mode ,'auto')
+    error('Cannot automatically detect decomposition (sample/feature) mode');
+  elseif strcmp(Options.mode ,'features')
+    X = X';
+    Y = Y';
+  end
+else  
+  error('Not proper size of pure channels/samples dataset');
+end
+
+crop_y = 0;
+crop_z = 0;
+switch Options.crop_mode
+case 'all'
+  crop_y = 1;
+  crop_z = 1;
+case 'samples'
+  if strcmp(Options.mode,'samples')
+    crop_y = 1;
+  else % features
+    crop_z = 1;
+  end
+case 'features'
+  if strcmp(Options.mode,'samples')
+    crop_z = 1;
+  else % features
+    crop_y = 1;
+  end
+end
+
+[N, d] = size(X);
+[n, d] = size(Y);
+
+SSX = sum(X(:).^2);
+
+if crop_y
+  Y = Y.*repmat(1 - 2*(sum(Y,2)<0),[1 d]);
+  Y(Y < 0) = 0;
+end
+
+
+for i=1:Options.max_iter
+  Z = X / Y;
+  ZZ = Z;
+  %Z = Z.*repmat(1 - 2*(sum(Z,1)<0),[N 1]);
+  if crop_z
+    Z(Z < 0) = 0;
+  end
+
+  Y_old = Y;
+  Y = Z \ X;
+  YY = Y;
+  %Y = Y.*repmat(1 - 2*(sum(Y,2)<0),[1 d]);
+  if crop_y
+    Y(Y < 0) = 0;
+  end
+
+  %subplot(2,1,1)
+  %plot(ZZ)
+  %subplot(2,1,2)
+  %plot(YY')
+  %pause(1)
+  
+  switch Options.crit
+  case {'convergence','conv'}
+    err = sum((Y(:)-Y_old(:)).^2)/sum(Y(:).^2);
+  case {'reconstruction','rec'}
+    err = X - Z*Y;
+    err = sum(err(:).^2)/SSX;
+  end
+
+  Msg = ['iter ' num2str(i) '; err: ' num2str(err)];
+  if prprog
+    prprogress(Options.verbose,['%s\n'],Msg);
+  elseif Options.verbose
+    disp(['als: ' Msg]);
+  end  
+
+  if err <= Options.eps
+    break;
+  end
+end
+
+
+if strcmp(Options.mode,'features')
+  ZZ = Y';
+  Y = Z';
+  Z = ZZ;
+  dd = d;
+  d = N;
+  N = dd;
+  clear ZZ dd
+end
+
+normalization = sqrt(sum(Y.^2,2));
+normalization(normalization==0) = 1;
+Y = Y./repmat(normalization,[1 d]);
+Z = Z.*repmat(normalization',[N 1]);
+
+if ~isempty(data_X)
+  Z = setdat(data_X, Z);
+  %Z.featlab = [repmat('conc',[n, 1]), num2str([1:n]','%-1d')];
+  Z.featlab = [1:n]';
+  Z = remove_spectra_info(Z);
+  Z.name = [data_X.name ': extracted channels'];
+
+  Y = dataset(Y);
+  %Y.ident    = cellstr([repmat('spectrum',[n, 1]), num2str([1:n]','%-1d')]);
+  Y.ident    = [1:n]';
+  Y.featlab  = featlab;
+  Y.featsize = featsize;
+  Y.user     = data_X.user;
+  Y.name = [data_X.name ': extracted spectra'];
+end
+
+return
+
+
+
+
+
+
Index: /hypertools/hypertools/applyPCA.m
===================================================================
--- /hypertools/hypertools/applyPCA.m	(revision 3)
+++ /hypertools/hypertools/applyPCA.m	(revision 3)
@@ -0,0 +1,66 @@
+% ApplyPCA Apply PCA to the hyperspectral image to find the most
+% principle components of the hyper images
+%
+%   IM = APPLYPCA(DATA, N)
+%
+% INPUT
+%      DATA: input dataset of hyperspectral image
+%      N   : number of principle components needed to find out
+% OUTPUT
+%      IM: Image of the principle components
+%
+% DESCRIPTION
+% Extract the most N principle components of hyper images
+% In case N = 1: represents data as a gray scale image
+% In case N = 3: represents data as a RGB image
+%
+%
+% Copyright: Dinh Viet Cuong, d.v.cuong@tudelft.nl
+% ICT group, Elect. Eng., Maths and Comp. Sc, 
+% Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: applyPCA.m,v 1.1 2009/01/16 15:03:50 dcuong Exp $
+
+function im = applyPCA(a, N)
+	if nargin == 0
+		error('error!, input dataset name');
+	elseif ~isa(a,'dataset')
+		error('error!, input dataset name');	
+	else
+		image1 = [];
+		% Convert dataset from feature type to object type
+		image1 = data2im(a);
+		a = im2obj(image1);
+		
+		% Apply PCA to hyper image
+		w = pca(a);
+		
+		% Convert mapping to dataset
+		[k,c] = size(w);
+		a = dataset(w.data.rot',w.labels(1:c,:));
+		a = setfeatsize(a,w.size_in);		
+		
+		switch N
+			case 1
+				a1 = a(1,:);
+				%print into file
+				%figure; show(a1);
+				%print -f1 -djpg component1.jpg
+				I1 = data2im(a1);
+				im = mat2gray(I1);
+			case 3
+				a1 = a(1,:); I1 = data2im(a1);
+				a2 = a(2,:); I2 = data2im(a2);
+				a3 = a(3,:); I3 = data2im(a3);
+				
+				im1 = mat2gray(I1); im(:,:,1) = im1;
+				im2 = mat2gray(I2); im(:,:,2) = im2;
+				im3 = mat2gray(I3); im(:,:,3) = im3;
+				
+				% show image
+				%imshow(im);		
+		end
+	end
+
+end
Index: /hypertools/hypertools/basesubm.m
===================================================================
--- /hypertools/hypertools/basesubm.m	(revision 3)
+++ /hypertools/hypertools/basesubm.m	(revision 3)
@@ -0,0 +1,98 @@
+% BASESUBM Baseline subtraction mapping
+% 
+%  W = BASESUBM(A,IND,CLIPOPT)
+% 
+% INPUT  
+%  A       dataset with a single spectrum
+%  IND     wavelength indices of the baseline region
+%  CLIPOPT clip negative values to zero? string 'clip' 
+%          or noclip' (opt, def: 'clip')
+%
+% OUTPUT
+%  W       baseline subtraction mapping
+%
+% DESCRIPTION
+% Baseline subtraction is a mapping, trained using a single spectrum A.
+% From this spectrum, a mean value over the baseline region defined by
+% wavelength indices IND is computed. When applied to a dataset with
+% spectra, wavelengths, defined by IND, are removed and from remaining
+% data, stored mean value is subtracted. By default, possible negative
+% values in the result are clipped to zero. In order to switch off the
+% clipping, use 'noclip' option.
+%
+% SEE ALSO
+% DATASETS, MAPPINGS
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: basesubm.m,v 1.3 2005/02/10 15:24:07 pavel Exp $
+
+function w = basesubm(a,ind,clipopt)
+
+	% No arguments given: return untrained mapping.
+
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename);
+		w = setname(w,'Baseline subtraction mapping');
+		return
+	end
+
+	if exist('ind','var') & ~isa(ind,'mapping')
+		% training
+		
+		isdataset(a);
+		[m,k]=getsize(a);
+
+		if m>1
+			prwarning(1,['more than one spctrum supplied,' ...
+				     ' using the first data sample']);
+			a=a(1,:);
+		end
+		
+		if ~exist('ind','var')
+			error(['indices of baseline wavelengths required' ...
+			       ' as 2nd parameter']);
+		end
+	
+		% clipping negative values?
+		pars.clip=1; % by default, we clip negative values to zero
+		if exist('clipopt','var') & ischar(clipopt)
+			if strcmp(clipopt,'noclip')
+				pars.clip=0;
+			else
+				error('unknown option');
+			end
+		end
+
+		x=+a(ind); % baseline region
+		
+		pars.meanval=mean(x); % mean of values in base-line region
+	        % indices of wavelengths we preserve in the data
+		pars.output_region=setdiff(1:k,ind); 
+		
+		w = mapping(mfilename,'trained',pars,getlablist(a),k,k-length(ind));
+		w = setname(w,'Baseline subtraction mapping');
+
+	else                      % Second argument is a a mapping: testing.
+		w = ind;
+		pars = getdata(w);		 	% Unpack the mapping.
+
+		out=+a(:,pars.output_region)-pars.meanval;
+		if pars.clip==1
+			% clip the possible negative values to zero
+			out(find(out<0))=0;
+		end
+		w = setdat(a,out,w);
+
+		% set the preserved (non-base line) wavelength indices
+		% as output feature labels
+		w=setfeatlab(w,pars.output_region');
+
+	end
+
+	return
+
+
+
Index: /hypertools/hypertools/basesubppm.m
===================================================================
--- /hypertools/hypertools/basesubppm.m	(revision 3)
+++ /hypertools/hypertools/basesubppm.m	(revision 3)
@@ -0,0 +1,73 @@
+% BASESUBM Baseline subtraction mapping
+% 
+%  W = BASESUBM(A,IND,CLIPOPT)
+% 
+% INPUT  
+%  A       dataset 
+%  IND     wavelength indices of the baseline region
+%  CLIPOPT clip negative values to zero? string 'clip' 
+%          or noclip' (opt, def: 'clip')
+%
+% OUTPUT
+%  W       baseline subtraction mapping
+%
+% DESCRIPTION
+% Baseline subtraction is a fixed mapping.
+% From this spectrum, a mean value over the baseline region defined by
+% wavelength indices IND is computed. When applied to a dataset with
+% spectra, a means over wavelengths defined by IND are computed.
+% These channels are removed and from remaining
+% data, mean values are subtracted. By default, possible negative
+% values in the result are clipped to zero. In order to switch off the
+% clipping, use 'noclip' option.
+%
+% SEE ALSO
+% DATASETS, MAPPINGS
+
+% Copyright: S. Verzakov, P. Paclik, s.verzakov@tudelft.nl
+
+% $Id: basesubppm.m,v 1.1 2006/05/03 03:47:27 serguei Exp $
+
+function w = basesubppm(a,ind,clipopt)
+
+  if nargin <= 1 
+    error('indices are not supplied');
+	end
+
+  if nargin < 3 | isempty(clipopt)
+    clipopt = 'clip';
+  end
+
+
+  % No dataset given: return fixed mapping.
+
+	if isempty(a)
+    if isempty(ind)
+      error('indices are not supplied');
+    end
+    w = mapping(mfilename, 'fixed', {ind, clipopt});
+		w = setname(w,'Baseline Subtraction Preprocessing Mapping');
+		return
+	end
+
+  isdataset(a);
+  [m,k]=getsize(a);
+
+	meanval = mean(+a(:,ind),2); % mean of values in base-line region
+	ind_rest = setdiff(1:k,ind); 
+  featlab  = a.featlab;
+  featlab  = featlab(ind_rest,:);
+  a.data   = +a(:,ind_rest) - repmat(meanval,[1, length(ind_rest)]);
+	
+
+	if strcmp(clipopt,'clip')
+		a(logical(+(a<0))) = 0;
+	end
+
+	a.featlab = featlab;
+  w = a;
+
+	return
+
+
+
Index: /hypertools/hypertools/cca_apply.m
===================================================================
--- /hypertools/hypertools/cca_apply.m	(revision 3)
+++ /hypertools/hypertools/cca_apply.m	(revision 3)
@@ -0,0 +1,89 @@
+%CCA_APPLY Canonical Correlation Analysis (applying)
+%  
+%  [T,U] = cca_apply(X,Y,W,Q)
+%  [T,U] = cca_apply(X,Y,W,Q,Options)
+%
+% INPUT
+%   X       [N -by- d_X] input data matrix, N samples, d_X variables; if X==[] then T==[] 
+%   Y       [N -by- d_Y] output data matrix, N samples, d_Y variables; if Y==[] then U==[] 
+%   W       [d_X -by- n] X weights  (X transformation matrix)
+%   Q       [d_Y -by- n] Y weights  (Y transformation matrix)
+%   Options structure returned by cca_train; if not supplied then will be no preprocessing performed
+%
+% OUTPUT
+%   T [N -by- n]  X scores (transformed (preprocessed) X)
+%   U [N -by- n]  Y scores (transformed (preprocessed) Y)
+%
+% DESCRIPTION
+% Applys precalculated CCA transformation to the new data.
+%
+% SEE ALSO
+% CCA_TRAIN
+
+% Copyright: S. Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: cca_apply.m,v 1.5 2005/02/07 10:03:21 pavel Exp $
+
+function [T,U] = cca_apply(X,Y,W,Q,Options)
+
+T = [];
+U = [];
+
+if nargin < 4 | nargin > 5
+  error('Invalid number of parameters');
+end
+
+if nargin < 5
+  Options  = [];
+end
+
+if ~isempty(X)
+  if isempty(W)
+    error('W cannot be empty if X is not empty');
+  end
+   
+  if size(X,2) ~= size(W,1)
+    error('size(X,2) ~= size(W,1)');
+  end
+end
+
+if ~isempty(Y)
+  if isempty(Q)
+    error('Q cannot be empty if Y is not empty');
+  end
+   
+  if size(Y,2) ~= size(Q,1)
+    error('size(Y,2) ~= size(Q,1)');
+  end
+end
+
+
+DefaultOptions.X_centering = [];
+DefaultOptions.Y_centering = [];
+DefaultOptions.X_scaling = [];
+DefaultOptions.Y_scaling = [];
+
+Options = updstruct(DefaultOptions, Options);
+
+[N_X, d_X] = size(X);
+[N_Y, d_Y] = size(Y);
+
+if N_X ~= N_Y
+	error('size(X,1) must be equal to size(Y,1)');
+else
+	N = N_X;
+end
+
+if ~isempty(X)
+  X = prepro(X, Options.X_centering, Options.X_scaling);
+  T = X*W;
+end  
+  
+if ~isempty(Y)
+  Y = prepro(Y, Options.Y_centering, Options.Y_scaling);
+  U = Y*Q;
+end  
+
+return;
Index: /hypertools/hypertools/cca_train.m
===================================================================
--- /hypertools/hypertools/cca_train.m	(revision 3)
+++ /hypertools/hypertools/cca_train.m	(revision 3)
@@ -0,0 +1,140 @@
+%CCA_TRAIN Canonical Correlation Analysis (training)
+%  
+%  [cr, XRes, YRes, Options] = cca_train(X,Y)
+%  [cr, XRes, YRes, Options] = cca_train(X,Y,Options)
+%
+% INPUT 
+%  X             [N -by- d_X] training input data matrix, N samples, d_X variables
+%  Y             [N -by- d_Y] training output data matrix, N samples, d_Y variables
+%
+%  Options.
+%   M_T          T (X scores) normalization: T(:,i)'*T(:,i) = M_T;
+%                by default M_T = N-1 (so if columns of X were mean-centered, columns of T are univariated)
+%   M_U          U (Y scores) normalization: U(:,i)'*U(:,i) = M_U; 
+%                by default M_U = N-1 (so if columns of Y were mean-centered, columns of U are univariated)
+%
+%   X_centering  do nothing (=[] or 0), do mean centering (=nan), center around some vaue v (=v);
+%                by default =[]
+%   Y_centering  do nothing (=[] or 0), do mean centering (=nan), center around some vaue v (=v);
+%                by default =[]
+%   X_scaling    do nothing (=[] or 1), divide each col by std (=nan), divide by some v (=v);
+%                by default =[] (scaling does not change T)
+%   Y_scaling    do nothing (=[] or 1), divide each col by std (=nan), divide by some v (=v); 
+%                by default =[] (scaling does not change U)
+%                
+% OUTPUT
+%  cr    [1- by -n] correlations between canonical components (cr(i)=corr(XRes(:,i),YRes(:,i)))
+%        n = min([N d_X d_Y]); n is the theoretical maximum of the number of components 
+%        with non-zero cr. In practice the number of such components can be less then n
+%        (e.g. due to mean-centering)
+%
+%  XRes.
+%   T    [N -by- n]    scores   (transformed (preprocessed) X)
+%   W    [d_X -by- n]  weights  (transformation matrix)
+%   P    [d_X -by- n]  loadings (back-transformation matrix or canonical structure)
+%
+%  YRes.
+%   U    [N -by- n]    scores   (transformed (preprocessed) Y)
+%   Q    [d_Y -by- n]  weights  (transformation matrix)
+%   C    [d_Y -by- n]  loadings (back-transformation matrix or canonical structure)
+%
+% Options.
+%   contains the same fields as in the input, but the values can be changed 
+%   (e.g. after mean centering X_centering = mean(X,1))
+%
+% DESCRIPTION
+% Computation of the linear transformations X to T and Y to U such that i-th columns of the
+% T and U have maximum possible correlation and at the same time are othogonal to the 
+% previous columns in both matrices. Columns of T and U are normalized to be univariated. 
+% Because X or/and Y can be not full-ranked, pinv is used in the algorithm.
+%
+% Relations between matrices (X and Y are assumed to be preprocessed):
+% 
+% T = X*W 
+% P = X'*T*pinv(T'*T)
+%
+% U = Y*Q
+% C = Y'*U*pinv(U'*U)
+%
+% T'*T = M_T*eye(n) i.e. columns of T are orthogonal and have the length sqrt(M_T); 
+% U'*U = M_U*eye(n) i.e. columns of U are orthogonal and have the length sqrt(M_U); 
+% if mean-centering was applied to X(Y) and M_T(M_U) = N-1 then the unbaised estimation of 
+% variance of each T(U) column is equal to 1. However a few last columns of T(U) can be zeros 
+% because X(Y) can be not full-ranked (e.g. due to mean-centering)
+% 
+%
+% SEE ALSO
+% CCA_APPLY
+
+% Copyright: S. Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: cca_train.m,v 1.9 2005/02/07 10:03:21 pavel Exp $
+
+function [cr, XRes, YRes, Options] = cca_train(X,Y,Options)
+
+	XRes = [];
+	YRes = [];
+
+	if nargin < 3
+		Options  = [];
+	end
+
+	[N_X, d_X] = size(X);
+	[N_Y, d_Y] = size(Y);
+
+	if N_X ~= N_Y
+		error('size(X,1) must be equal to size(Y,1)');
+	else
+		N = N_X;
+	end
+
+
+	DefaultOptions.M_T = N-1;
+	DefaultOptions.M_U = N-1;
+	DefaultOptions.X_centering = [];
+	DefaultOptions.Y_centering = [];
+	DefaultOptions.X_scaling = [];
+	DefaultOptions.Y_scaling = [];
+
+	Options = updstruct(DefaultOptions, Options);
+
+	[X, Options.X_centering, Options.X_scaling] = prepro(X, Options.X_centering, Options.X_scaling);
+	[Y, Options.Y_centering, Options.Y_scaling] = prepro(Y, Options.Y_centering, Options.Y_scaling);
+
+	if N >= d_X
+		[Ux,Sx,Vx] = svd(X,0);
+	else
+		[Vx,Sx,Ux] = svd(X',0);
+	end
+
+	if N >= d_Y
+		[Uy,Sy,Vy] = svd(Y,0);
+	else
+		[Vy,Sy,Uy] = svd(Y',0);
+	end
+
+	R = Ux'*Uy;
+
+	if size(R,1) >= size(R,2)
+		[W,cr,Q] = svd(R,0); 
+	else
+		[Q,cr,W] = svd(R',0); 
+	end
+
+	cr = diag(cr);
+
+	W = sqrt(Options.M_T)*Vx*pinv(Sx)*W;
+	Q = sqrt(Options.M_U)*Vy*pinv(Sy)*Q;
+
+	XRes.T = X*W;
+	YRes.U = Y*Q;  
+
+	XRes.W = W;
+	YRes.Q = Q;
+
+	XRes.P = X'*XRes.T*pinv(XRes.T'*XRes.T);
+	YRes.C = Y'*YRes.U*pinv(YRes.U'*YRes.U);
+
+	return;
Index: /hypertools/hypertools/ccam.m
===================================================================
--- /hypertools/hypertools/ccam.m	(revision 3)
+++ /hypertools/hypertools/ccam.m	(revision 3)
@@ -0,0 +1,114 @@
+%CCAM Canonical Correlation Analysis mapping
+%
+%  W = CCAM
+%  W = CCAM*A
+%
+% DESCRIPTION
+% CCAM routine provides a prtools mapping for Cannonical Correlation
+% Analysis, based on CCA_TRAIN and CCA_APPLY functions.
+%
+% SEE ALSO
+% CCA_TRAIN, CCA_APPLY
+
+% $Id: ccam.m,v 1.7 2005/05/10 11:02:56 serguei Exp $
+
+function [w,info]=ccam(par1,par2,par3)
+
+% No dataset given: return untrained mapping.
+if (nargin < 1) | (isempty(par1))
+  if nargin < 2
+    par2 = 0;
+  end  
+  if nargin < 3
+    par3 = 0;
+  end  
+  data = {par2, par3};
+  w = mapping(mfilename,'untrained',data);
+  w = setname(w,'Cannonical Correlation Analysis Mapping');
+  return
+end
+
+isdataset(par1);           % Assert that A is a dataset.
+
+% training
+if nargin < 2 | ~isa(par2,'mapping') 
+  % a*w when w is untrained or ccam(a,,) 
+  if nargin < 2
+    par2 = 0;
+  end  
+  if nargin < 3
+    par3 = 0;
+  end  
+  flag_t = par2; 
+  flag_u = par3;
+  
+  [m,k] = getsize(par1);
+  
+  if strcmp(par1.labtype,'crisp')
+    y=gettargets(setlabtype(par1,'soft'));
+  else
+    y=gettargets(par1);
+  end
+  
+  % options
+  Options.X_centering=[];
+  Options.Y_centering=[];
+  Options.X_scaling=[];
+  Options.Y_scaling=[];
+  
+  if flag_t
+    data.info = 't_train''*t_train=m_train; ';
+    Options.M_T=m;
+  else
+    data.info = 't_train''*t_train=m_train-1; ';
+    Options.M_T=m-1;
+  end
+  
+  if flag_u
+    data.info = [data.info 'u_train''*u_train=m_train;'];
+    Options.M_U=m;
+  else
+    data.info = [data.info 'u_train''*u_train=m_train-1;'];
+    Options.M_U=m-1;  
+  end
+  
+  [cr,XRes,YRes,Options]=cca_train(+par1,y,Options);
+  
+  data.W=XRes.W;
+  data.Q=YRes.Q;
+  data.Options=Options;
+  
+  % Save all useful data
+  w = mapping(mfilename,'trained',data,[],size(XRes.W,1),size(XRes.W,2));
+  w = setname(w,'Cannonical Correlation Analysis Mapping');
+  
+  if nargout > 1
+    info.cr   = cr;
+    info.XRes = XRes;
+    info.YRes = YRes;
+  end
+  
+  % applying
+else 
+  data = getdata(par2); % Unpack the mapping.
+  
+  if strcmp(par1.labtype,'crisp')
+    y=gettargets(setlabtype(par1,'soft'));
+  else
+    y=gettargets(par1);
+  end
+  
+  [T,U] = cca_apply(+par1,y,data.W,data.Q,data.Options);
+  
+  w = setdat(par1,T,par2);
+  %w = setlabtype(w,'targets');
+  %w = settargets(w,U);
+  
+  if nargout > 1
+    info = U;
+  end
+end
+
+return
+
+
Index: /hypertools/hypertools/chemimage.m
===================================================================
--- /hypertools/hypertools/chemimage.m	(revision 3)
+++ /hypertools/hypertools/chemimage.m	(revision 3)
@@ -0,0 +1,53 @@
+%CHEMIMAGE Create an image rendering the area under the part of spectra
+%
+%  IMOUT = CHEMIMAGE(IM,BANDS,VALUES)
+%
+% INPUT
+%   IM      spectral image (dip_image)
+%   BANDS   vector with two bands/wavelengths/wavenumbers indices
+%
+% OUTPUT
+%  IMOUT   gray-valued dip image (each pixels corresponds to area under the selected part of spectra); 
+%
+% DESCRIPTION
+% The routine produces an image rendering the area under the part of
+% spectra, defined by BANDS. 
+%
+% SEE ALSO
+% SHOWSI
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function imout=chemimage(im,bands)
+
+	if ~isa(im,'dip_image')
+		error('dip_image required');
+	end
+	
+	% lets fix the ordering by sorting:
+	[bands,ind]=sort(bands);
+
+	% area under the spectra
+	im=double(im(:,:,bands(1):bands(2)));
+	area=sum(im,3);
+	
+	% area under the baselines
+	
+	% we compute the area of trapezoid:
+        %      /| v2 	
+        %  v1 / |       area=(band2-band1)*mean(v1,v2)
+        %     | |
+	%     ---
+	% band1 band2
+
+	t=zeros(size(im,1),size(im,2),2);
+	t(:,:,1)=im(:,:,1);
+	t(:,:,2)=im(:,:,2);	
+	t=mean(t,3); % mean of values
+	
+	area=area - (t .* (bands(2)-bands(1)));
+	imout=dip_image( area );
+	
+	return
Index: /hypertools/hypertools/corrc.m
===================================================================
--- /hypertools/hypertools/corrc.m	(revision 3)
+++ /hypertools/hypertools/corrc.m	(revision 3)
@@ -0,0 +1,72 @@
+%CORRC Correlation classifier
+% 
+%  W = CORRC(A)
+% 
+% INPUT  
+%  A    Training dataset
+%
+% OUTPUT
+%  W    Correlation classifier mapping
+%
+% DESCRIPTION
+% By correlation classifier the new sample is prescribed to the class with 
+% whose mean it is the most co-directed (has the smallest angle)
+%
+% SEE ALSO
+% DATASETS, MAPPINGS
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: corrc.m,v 1.3 2003/12/09 13:19:59 pavel Exp $
+
+function w = corrc(a,arg2)
+
+	% No arguments given: return untrained mapping.
+
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename);
+		w = setname(w,'Correlation classifier');
+		return
+	end
+
+	if (~exist('arg2','var'))     % Second argument is not a mapping: training.
+
+		isdataset(a);           % Assert that A is a dataset.
+
+		[m,k,c] = getsize(a); M = classsizes(a);
+
+		% class means
+		pars.means=meancov(a);
+		
+		% Save all useful data.
+
+		w = mapping(mfilename,'trained',pars,getlablist(a),k,c);
+		w = setname(w,'Correlation classifier');
+
+	else                      % Second argument is a a mapping: testing.
+
+		w = arg2;
+		pars = getdata(w);		 	% Unpack the mapping.
+		[m,k] = getsize(a); 
+
+		c = size( pars.means, 1 );
+		t=+a;
+
+		% computing sqrt(x'x)
+		X = sqrt(sum(t.*t,2));
+
+		% class means
+		means=+pars.means;
+		M = sqrt(sum(means.*means,2));
+
+		out= (t * means')./ (X*M');
+		w = setdat(a,out,w);
+
+	end
+
+	return
+
+
+
Index: /hypertools/hypertools/dasam.m
===================================================================
--- /hypertools/hypertools/dasam.m	(revision 3)
+++ /hypertools/hypertools/dasam.m	(revision 3)
@@ -0,0 +1,55 @@
+%DASAM Spectral Angle Mapper (using acos)
+%
+%  D=DASAM(DATA)
+%  D=DASAM(DATA,PROTO)
+%
+% INPUT 
+%  DATA    testing dataset
+%  PROTO   training dataset (representation set)
+% 
+% OUTPUT 
+%  D       dataset with a distance (angles) matrix
+%
+% DESCRIPTION   
+% Variables in the output dataset D are angles (in the [0; pi) region) 
+% between DATA samples and PROTO samples. The number of samples in D is equal to the 
+% one of  DATA. D.OBJSIZE is the same as DATA.OBJSIZE. If PROTO is not supplied then
+% PROTO==DATA.
+%
+% SEE ALSO
+% DSAM
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: dasam.m,v 1.12 2005/02/10 15:24:07 pavel Exp $
+
+function d=dasam(data,proto)
+
+      if ~exist('proto','var'), proto=data; end
+
+      if size(data,2)~=size(proto,2)
+	      error('both datasets must have the same feature sizes');
+      end
+
+      sc=size(data,1); % training sample size
+      pc=size(proto,1); % test sample size
+
+      labdata=getlab(data);
+      labproto=getlab(proto);
+      objsize=data.objsize;
+      data2=data;
+      proto2=proto;
+      data=+data;
+      proto=+proto;
+
+      ndata=sqrt(sum(data.*data,2));
+      nproto=sqrt(sum(proto.*proto,2));
+
+      d = acos((data*proto')./(ndata*nproto'));
+
+      d=setdata(data2,real(d),getlab(proto2));
+      
+      return
+      
Index: /hypertools/hypertools/data2dip.m
===================================================================
--- /hypertools/hypertools/data2dip.m	(revision 3)
+++ /hypertools/hypertools/data2dip.m	(revision 3)
@@ -0,0 +1,68 @@
+%DATA2DIP Convert image in a dataset into a dip image
+%
+%  IM=DATA2DIP(A)
+%  IM=DATA2DIP(A,TYPE)
+%
+% INPUT
+%  A       dataset
+%  TYPE    data type (default: 'double'), see dip_image help 
+%          for all possible types
+%
+% OUTPUT
+%  IM      dip_image object
+%
+% DESCRIPTION
+% Conversion of a hyperspectral dataset into the dip image object.
+% The dataset object must have the DATASIZE parameter set.
+%
+% SEE ALSO
+% DIP2DATA
+
+% Copyright: Pavel Paclik, P.Paclik@ewi.tudelft.nl
+
+% $Id: data2dip.m,v 1.11 2005/11/02 14:57:58 pavel Exp $
+
+function im=data2dip(a,type)
+	
+	if ~isdipinstalled
+		error('DIPimage not installed');
+	end
+	
+	isdataset(a);
+	
+	if ~exist('type','var')
+		type='double';
+	end
+	
+	objsize=a.objsize;
+	if length(objsize)==2
+		im=dip_image(...
+		    reshape(+a,[objsize(1),objsize(2),size(a,2)]),...
+		    type );
+	elseif isvalidprop(a,'pos')
+	    % irregular object
+	    pos=getprop(a,'pos');
+	    if size(pos,2)~=2, error('2D pos matrix expected'); end
+
+	    bb=max(pos)-min(pos)+1;
+    
+	    % shift origin to leftmost pixel of the bounding box
+	    pos=pos-repmat(min(pos),size(pos,1),1)+1;
+	    
+	    pixind=sub2ind(bb,pos(:,1),pos(:,2));
+
+	    im=zeros([bb,size(a,2)]);
+	    im=reshape(im,prod(bb),size(a,2));
+
+	    im(pixind,:)=+a;
+	    
+	    im=reshape(im,[bb,size(a,2)]);
+
+	    im=dip_image(im);
+
+	else
+	    error('dataset does not contain image data');
+	end
+	
+	return
+	
Index: /hypertools/hypertools/dcityblock.m
===================================================================
--- /hypertools/hypertools/dcityblock.m	(revision 3)
+++ /hypertools/hypertools/dcityblock.m	(revision 3)
@@ -0,0 +1,59 @@
+%DCITYBLOCK City-block (Manhattan) distance
+%
+%  D=DCITYBLOCK(DATA)
+%  D=DCITYBLOCK(DATA,PROTO)
+%
+% INPUT 
+%  DATA    testing dataset
+%  PROTO   training dataset (representation set)
+% 
+% OUTPUT 
+%  D       dataset with a distance matrix
+%
+% DESCRIPTION   
+% Variables in the output dataset D are city-block distances between DATA
+% samples and PROTO samples. The number of samples in D is equal to the one
+% of DATA. D.OBJSIZE is the same as DATA.OBJSIZE. If PROTO is not supplied
+% then PROTO==DATA.
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: dcityblock.m,v 1.3 2005/02/10 15:24:07 pavel Exp $
+
+function d=dcityblock(data,proto)
+
+if ~exist('proto','var'), proto=data; end
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+sc=size(data,1); % training sample size
+pc=size(proto,1); % test sample size
+
+d=zeros(sc,pc);
+
+labdata=getlab(data);
+labproto=getlab(proto);
+objsize=data.objsize;
+data2=+data;
+proto2=+proto;
+
+% for computational reasons, we put the lopp over prototypes
+% into a mex file dist:
+if exist('distfunc')==3
+    d=distfunc(data2,proto2);
+else
+    for i=1:pc
+	t=repmat(proto2(i,:),sc,1);
+	d(:,i)=sum(abs(data2-t),2);
+    end
+end
+
+d=setdat(data,d);
+d=setfeatlab(d,labproto);
+
+return
+  
+
Index: /hypertools/hypertools/derfilter.m
===================================================================
--- /hypertools/hypertools/derfilter.m	(revision 3)
+++ /hypertools/hypertools/derfilter.m	(revision 3)
@@ -0,0 +1,57 @@
+% DERFILTER Gaussian derivative filter
+%
+%     OUT=DERFILTER(DATA,SIGMA)
+%
+% INPUT
+%   DATA  - dataset or data matrix
+%   SIGMA - smoothing parameter
+%
+% OUTPUT
+%   OUT   - output dataset or data matrix
+%
+% DESCRIPTION
+% DERFILTER computes smoothed 1st Gaussian derivative of signals (spectra)
+% in DATA using standard Matlab convolution tools. 
+
+% $Id: derfilter.m,v 1.4 2005/02/10 15:24:07 pavel Exp $
+
+function out=derfilter(data,sigma)
+    
+    
+    if ~exist('sigma','var'), sigma=2.0; end
+    % we use window -3 simga : +3 simga
+    x = floor(-3*sigma):ceil(3*sigma);
+    g = exp(-0.5*x.^2/sigma^2); 
+%    g = g/sum(g);
+    dg = -x.*g/sigma^2;
+    kernel = dg;
+    
+    sc=size(data,1); % sample count
+    fc=size(data,2);
+    kc=length(kernel)+10;
+
+    if isdataset(data)
+	data2=+data; % internal raw data
+    else
+	data2=data;
+    end
+    
+    % output
+    out=zeros(size(data));
+    
+    % extend the data by mirroring the tails
+    data2=[ data2(:,kc:-1:1) data2 data2(:,end:-1:fc-kc+1) ];
+    
+    outc=fc+2*kc+length(kernel)-1;  % size of the convolution output
+    % indices of a part corresponging to the original signal
+    ind = kc+ceil(length(kernel)/2):outc-kc-floor(length(kernel)/2);
+
+    % convolve the signals
+    for i=1:sc
+	t=conv(data2(i,:),kernel);
+	out(i,:)=t(ind);	
+    end
+	
+    if isdataset(data)
+	out=setdat(data,out);
+    end
Index: /hypertools/hypertools/dip2data.m
===================================================================
--- /hypertools/hypertools/dip2data.m	(revision 3)
+++ /hypertools/hypertools/dip2data.m	(revision 3)
@@ -0,0 +1,40 @@
+%DIP2DATA Convert a dip image into a dataset
+%
+%  D = DIP2DATA(DIP)
+%
+% INPUT
+%  DIP   dip image
+%
+% OUTPUT
+%  D     generated dataset
+%
+% DESCRIPTION
+% Conversion of a dip image object into the hyperspectral dataset.
+% The original image size is preserved in OBJSIZE parameter.
+%
+% SEE ALSO
+% DATA2DIP
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: dip2data.m,v 1.7 2005/11/02 14:29:04 pavel Exp $
+
+function d=dip2data(dip)
+
+	
+	if isa(dip,'dip_image')
+	
+		objsize=size(dip);
+		if length(objsize)==2, objsize=[objsize 1]; end
+		d=dataset(reshape(double(dip),objsize(1)*objsize(2),objsize(3)));
+		d.objsize=[objsize(2) objsize(1)];
+		
+		% generate object identifiers
+		d.ident=[1:prod(d.objsize)]';
+	else
+		error('dip_image required');
+	end
+		
+	return
Index: /hypertools/hypertools/dipimage/dipfig_getcurpos.m
===================================================================
--- /hypertools/hypertools/dipimage/dipfig_getcurpos.m	(revision 3)
+++ /hypertools/hypertools/dipimage/dipfig_getcurpos.m	(revision 3)
@@ -0,0 +1,55 @@
+%PT = DIPFIG_GETCURPOS(AX)
+%    Returns the coordinates of the mouse over the image in axes AX.
+%    PT is [x,y], so that indexing into the dip_image object is done
+%    by (pt(1),pt(2)).
+%
+%    If the mouse is outside the window, returns the closest coordinates
+%    within the window.
+%
+%    The axes 'units' are expected to be 'pixels'.
+%
+%    PT = DIPFIG_GETCURPOS(AX,CROP) is the same thing if CROP is non-zero.
+%    For CROP==0, the coordinates are not compared to the axis limits, so
+%    the returned value can be outside the window, and outside the image.
+
+% (C) Copyright 1999-2002               Pattern Recognition Group
+%     All rights reserved               Faculty of Applied Physics
+%                                       Delft University of Technology
+%                                       Lorentzweg 1
+%                                       2628 CJ Delft
+%                                       The Netherlands
+%
+% Cris Luengo, July 2001.
+% 24 August 2001: The bug we are correcting for is not there in MATLAB 6.
+% 25 August 2001: Removed the FIG parameter, which wasn't being used.
+% 29 April 2002:  Added the CROP parameter.
+
+% The offset for the Y axis is a fix for the fact that the position
+% reported by MATLAB trough 'CurrentPoint' is one pixel off in the Y-axis.
+% This is screen pixels, not axes coordinates.
+% This bug has been corrected in MATLAB 6.
+
+function pt = dipfig_getcurpos(ax,crop)
+pt = get(ax,'CurrentPoint');
+pt = [pt(1,1),pt(1,2)];
+curylim = get(ax,'YLim');
+curxlim = get(ax,'XLim');
+v = version;
+if v(1)=='5'
+   axpos = get(ax,'Position');
+   curyrange = diff(curylim);
+   pt(2) = pt(2) - curyrange/axpos(4);
+end
+pt = round(pt);
+if nargin==1 | crop
+   if pt(1) < curxlim(1)
+      pt(1) = ceil(curxlim(1));
+   elseif pt(1) > curxlim(2)
+      pt(1) = floor(curxlim(2));
+   end
+   if pt(2) < curylim(1)
+      pt(2) = ceil(curylim(1));
+   elseif pt(2) > curylim(2)
+      pt(2) = floor(curylim(2));
+   end
+end
Index: /hypertools/hypertools/dipimage/diptest.m
===================================================================
--- /hypertools/hypertools/dipimage/diptest.m	(revision 3)
+++ /hypertools/hypertools/dipimage/diptest.m	(revision 3)
@@ -0,0 +1,392 @@
+%DIPTEST   Interactive pixel testing
+%   DIPTEST ON turns on interactive testing of the current image.
+%   DIPTEST OFF turns it off.
+%   DIPTEST by itself toggles the state.
+%
+%   When DIPTEST is turned on, the current coordinates and pixel value are
+%   displayed while a mouse button is depressed. You can move the mouse
+%   while holding down the mouse button to find some coordinates. The right
+%   mouse button can be used to measure lengths.
+%
+%   DIPTEST only works on figure windows created through DIPSHOW.
+%
+%   Also: DIPTEST(H,'ON'), DIPTEST(H,'OFF'), etc. to specify a window handle.
+%
+%   See also DIPSHOW, DIPORIEN, DIPZOOM, DIPSTEP, DIPLINK.
+
+% (C) Copyright 1999-2001               Pattern Recognition Group
+%     All rights reserved               Faculty of Applied Physics
+%                                       Delft University of Technology
+%                                       Lorentzweg 1
+%                                       2628 CJ Delft
+%                                       The Netherlands
+%
+% Cris Luengo, July 2000
+% 2 September 2000:  Enabled DIPTEST for color images.
+% 9 November 2000:   Improved title bar display.
+% 29 March 2001:     Added right-button functionality.
+% 28 June 2001:      Fixed bug that occurred when clicking outside the image area.
+% 29 July 2001:      getCoords() is now dipfig_getcurpos(), a shared private function.
+% 16-26 August 2001: Changed DIPSHOW. This function changes accordingly.
+%                    Now supporting 1D images. Fixed bug for empty images
+% 15 September 2001: Using FORMATVALUE instead of NUM2STR to display pixel values.
+% 22 September 2001: Changed specs of 1D image display (again, *sigh*).
+
+%FIRST VERSION:
+% Cris Luengo, June/August 1999
+% Tested on MATLAB Version 5.2.1.1420 on PCWIN
+% Tested on MATLAB Version 5.3.0.10183 (R11) on PCWIN
+
+function menu_out = diptest(arg1,arg2)
+
+% Avoid being in menu
+if nargin == 1 & ischar(arg1) & strcmp(arg1,'DIP_GetParamList')
+   menu_out = struct('menu','none');
+   return
+end
+
+if nargin == 0
+   fig = get(0,'CurrentFigure');
+   if isempty(fig)
+      error('No figure window open to do operation on.')
+   end
+   action = 'toggle';
+elseif nargin == 1
+   if ischar(arg1)
+      fig = gcbf;
+      if ~isempty(fig)
+         switch lower(arg1)
+         case 'down'
+            diptestButtonDownFcn(fig);
+            return
+         case 'motion'
+            diptestMotionFcn(fig);
+            return
+         case 'motionr'
+            diptestMotionRFcn(fig);
+            return
+         case 'up'
+            diptestButtonUpFcn(fig);
+            return
+         case 'down1'
+            diptestButtonDown1Fcn(fig);
+            return
+         case 'motion1'
+            diptestMotion1Fcn(fig);
+            return
+         case 'up1'
+            diptestButtonUp1Fcn(fig);
+            return
+         otherwise
+            action = lower(arg1);
+         end
+      else
+         fig = get(0,'CurrentFigure');
+         if isempty(fig)
+            error('No figure window open to do operation on.')
+         end
+         action = lower(arg1);
+      end
+   else
+      try
+         fig = getfigh(arg1);
+      catch
+         error('Argument must be a valid figure handle.')
+      end
+      action = 'toggle';
+   end
+else
+   try
+      fig = getfigh(arg1);
+   catch
+      error('Argument must be a valid figure handle.')
+   end
+   action = lower(arg2);
+end
+if (length(fig) == 1) & ishandle(fig)
+   tag = get(fig,'Tag');
+   if strncmp(tag,'DIP_Image',9)
+      OneD = tag(11)=='1';
+      udata = get(fig,'UserData');
+      switch (action)
+      case 'toggle'
+         if strcmp(udata.state,'diptest')
+            dipfig_clear_state(fig,udata);
+         else
+            makeDIPtestObj(fig,udata,OneD);
+         end
+      case 'on'
+         if ~strcmp(udata.state,'diptest')
+            makeDIPtestObj(fig,udata,OneD);
+         end
+      case 'off'
+         if strcmp(udata.state,'diptest')
+            dipfig_clear_state(fig,udata);
+         end
+      end
+   end
+end
+
+
+%
+% Enable the diptest tool.
+%
+function makeDIPtestObj(fig,udata,OneD)
+udata.state = 'diptest';
+if OneD
+   set(fig,'WindowButtonDownFcn','diptest(''down1'')');
+else
+   set(fig,'WindowButtonDownFcn','diptest(''down'')');
+end
+set(fig,'WindowButtonUpFcn','',...
+        'WindowButtonMotionFcn','',...
+        'ButtonDownFcn','',...
+        'UserData',[]);   % Solve MATLAB bug!
+set(fig,'UserData',udata);
+dipfig_setpointer(fig,'cross');
+dipfig_set_action_check(fig,udata.state);
+
+
+%
+% Callback function for mouse down in images
+%
+function diptestButtonDownFcn(fig)
+if strncmp(get(fig,'Tag'),'DIP_Image',9)
+   img = get(fig,'CurrentObject');
+   if strcmp(get(img,'Type'),'image')
+      udata = get(fig,'UserData');
+      udata.ax = get(img,'Parent');
+      udata.oldAxesUnits = get(udata.ax,'Units');
+      udata.oldNumberTitle = get(fig,'NumberTitle');
+      set(udata.ax,'Units','pixels');
+      if strcmp(get(fig,'SelectionType'),'alt')
+         % Right mouse button
+         udata.coords = dipfig_getcurpos(udata.ax); % Always over image!
+         udata.lineh = line([udata.coords(1),udata.coords(1)],...
+             [udata.coords(2),udata.coords(2)],'EraseMode','xor','Color',[0,0,0.8]);
+         set(fig,'WindowButtonMotionFcn','diptest(''motionR'')',...
+                 'WindowButtonUpFcn','diptest(''up'')',...
+                 'NumberTitle','off','UserData',[]);   % Solve MATLAB bug!
+         set(fig,'UserData',udata);
+         updateDisplayR(fig,udata.ax,udata);
+      else
+         % Left mouse button
+         set(fig,'WindowButtonMotionFcn','diptest(''motion'')',...
+                 'WindowButtonUpFcn','diptest(''up'')',...
+                 'NumberTitle','off','UserData',[]);   % Solve MATLAB bug!
+         set(fig,'UserData',udata);
+         updateDisplay(fig,udata.ax,udata);
+      end
+   end
+end
+
+
+%
+% Callback function for mouse move in images
+%
+function diptestMotionFcn(fig)
+if strncmp(get(fig,'Tag'),'DIP_Image',9)
+   if strcmp(get(get(fig,'CurrentObject'),'Type'),'image')
+      udata = get(fig,'UserData');
+      updateDisplay(fig,udata.ax,udata);
+   end
+end
+
+function diptestMotionRFcn(fig)
+if strncmp(get(fig,'Tag'),'DIP_Image',9)
+   if strcmp(get(get(fig,'CurrentObject'),'Type'),'image')
+      udata = get(fig,'UserData');
+      updateDisplayR(fig,udata.ax,udata);
+   end
+end
+
+
+%
+% Callback function for mouse up in images
+%
+function diptestButtonUpFcn(fig)
+if strncmp(get(fig,'Tag'),'DIP_Image',9)
+   udata = get(fig,'UserData');
+   %if isfield(udata,'ax')
+      set(udata.ax,'Units',udata.oldAxesUnits);
+      set(fig,'WindowButtonMotionFcn','','WindowButtonUpFcn','',...
+              'NumberTitle',udata.oldNumberTitle);
+      udata = rmfield(udata,{'ax','oldAxesUnits','oldNumberTitle'});
+   %end
+   if isfield(udata,'lineh')
+      delete(udata.lineh);
+      udata = rmfield(udata,{'coords','lineh'});
+   end
+   dipfig_titlebar(fig,udata);
+   set(fig,'UserData',[]);    % Solve MATLAB bug!
+   set(fig,'UserData',udata);
+end
+
+
+%
+% Retrieve coordinates and image value, and update figure title.
+%
+function updateDisplay(fig,ax,udata)
+pt = dipfig_getcurpos(ax);
+if ~isempty(udata.colspace)
+   str = ['(',num2str(pt(1)),',',num2str(pt(2)),') : ',udata.colspace,' = ['];
+   data = double(udata.colordata(pt(1),pt(2)));
+   for ii=1:length(data)
+      str = [str,formatvalue(data(ii)),','];
+   end
+   str(end) = ']';
+   set(fig,'Name',str);
+else
+   if ndims(udata.imagedata)==0
+      value = 0; % Empty display!
+   else
+      value = double(udata.imagedata(pt(1),pt(2)));
+   end
+   set(fig,'Name',['(',num2str(pt(1)),',',num2str(pt(2)),') : ',formatvalue(value)]);
+end
+
+function updateDisplayR(fig,ax,udata)
+pt = dipfig_getcurpos(ax);
+set(udata.lineh,'XData',[udata.coords(1),pt(1)],'YData',[udata.coords(2),pt(2)]);
+delta = pt - udata.coords;
+len = sqrt(sum(delta.^2));
+if ~isempty(udata.colspace)
+   str = ['(',num2str(delta(1)),',',num2str(delta(2)),') ',num2str(len),' : ',...
+          udata.colspace,' = ['];
+   data = double(udata.colordata(pt(1),pt(2)));
+   for ii=1:length(data)
+      str = [str,formatvalue(data(ii)),','];
+   end
+   str(end) = ']';
+   set(fig,'Name',str);
+else
+   if ndims(udata.imagedata)==0
+      value = 0; % Empty display!
+   else
+      value = double(udata.imagedata(pt(1),pt(2)));
+   end
+   set(fig,'Name',['(',num2str(delta(1)),',',num2str(delta(2)),') ',...
+       num2str(len),' : ',formatvalue(value)]);
+end
+
+
+%
+% Callback function for mouse down in 1D images
+%
+function diptestButtonDown1Fcn(fig)
+if strncmp(get(fig,'Tag'),'DIP_Image_1D',12)
+   ax = findobj(fig,'Type','axes');
+   if length(ax)==1
+      udata = get(fig,'UserData');
+      if isfield(udata,'lineh'), return, end % avoid clicking with the other button
+      udata.ax = ax;
+      udata.oldAxesUnits = get(ax,'Units');
+      udata.oldNumberTitle = get(fig,'NumberTitle');
+      set(ax,'Units','pixels');
+      if strcmp(get(fig,'SelectionType'),'alt')
+         % Right mouse button
+         udata.coords = dipfig_getcurpos(ax); % Always over image!
+         udata.Zlineh = line([udata.coords(1),udata.coords(1)],get(ax,'YLim'),...
+                             'EraseMode','xor','Color',[0.7,0,0]);
+         udata.lineh = line([udata.coords(1),udata.coords(1)],get(ax,'YLim'),...
+                            'EraseMode','xor','Color',[0,0,0.8]);
+         set(fig,'WindowButtonMotionFcn','diptest(''motion1'')',...
+                 'WindowButtonUpFcn','diptest(''up1'')',...
+                 'NumberTitle','off','UserData',[]);   % Solve MATLAB bug!
+         set(fig,'UserData',udata);
+         updateDisplay1(fig,ax,udata);
+      else
+         % Left mouse button
+         udata.lineh = line([0,0],get(ax,'YLim'),'EraseMode','xor','Color',[0,0,0.8]);
+         set(fig,'WindowButtonMotionFcn','diptest(''motion1'')',...
+                 'WindowButtonUpFcn','diptest(''up1'')',...
+                 'NumberTitle','off','UserData',[]);   % Solve MATLAB bug!
+         set(fig,'UserData',udata);
+         updateDisplay1(fig,ax,udata);
+      end
+   end
+end
+
+
+%
+% Callback functions for mouse move in 1D images
+%
+function diptestMotion1Fcn(fig)
+if strncmp(get(fig,'Tag'),'DIP_Image_1D',12)
+   udata = get(fig,'UserData');
+   updateDisplay1(fig,udata.ax,udata);
+end
+
+
+%
+% Callback function for mouse up in 1D images
+%
+function diptestButtonUp1Fcn(fig)
+if strncmp(get(fig,'Tag'),'DIP_Image_1D',12)
+   udata = get(fig,'UserData');
+   set(udata.ax,'Units',udata.oldAxesUnits);
+   set(fig,'WindowButtonMotionFcn','','WindowButtonUpFcn','',...
+           'NumberTitle',udata.oldNumberTitle);
+   delete(udata.lineh);
+   udata = rmfield(udata,{'ax','oldAxesUnits','oldNumberTitle','lineh'});
+   if isfield(udata,'Zlineh')
+      delete(udata.Zlineh);
+      udata = rmfield(udata,{'coords','Zlineh'});
+   end
+   dipfig_titlebar(fig,udata);
+   set(fig,'UserData',[]);    % Solve MATLAB bug!
+   set(fig,'UserData',udata);
+end
+
+
+%
+% Retrieve 1D coordinate and image value, and update figure title.
+%
+function updateDisplay1(fig,ax,udata)
+pt = dipfig_getcurpos(ax);
+set(udata.lineh,'XData',[pt(1),pt(1)]);
+str = ['(',num2str(pt(1)),')'];
+if isfield(udata,'Zlineh')
+   delta = pt(1) - udata.coords(1);
+   len = abs(delta);
+   str = [str,' ',num2str(len)];
+end
+str = [str,' : '];
+if ~isempty(udata.colspace)
+   str = [str,udata.colspace,' = ['];
+   data = double(udata.colordata(pt(1)));
+   for ii=1:length(data)
+      str = [str,formatvalue(data(ii)),','];
+   end
+   str(end) = ']';
+else
+   str = [str,formatvalue(double(udata.imagedata(pt(1))))];
+end
+set(fig,'Name',str);
+%DIPFIG_CLEAR_STATE(FIG,UDATA)
+%    Disables all callbacks for the image in FIG, and updates UDATA.
+
+% (C) Copyright 1999-2001               Pattern Recognition Group
+%     All rights reserved               Faculty of Applied Physics
+%                                       Delft University of Technology
+%                                       Lorentzweg 1
+%                                       2628 CJ Delft
+%                                       The Netherlands
+%
+% Cris Luengo, July 2000.
+% 16-26 August 2001: Changed DIPSHOW. This function changes accordingly.
+
+function dipfig_clear_state(fig,udata)
+udata.state = 'none';
+
+if isfield(udata,'orientationim')
+   udata = rmfield(udata,'orientationim');
+end
+set(fig,'pointer','arrow',...
+        'WindowButtonDownFcn','',...
+        'WindowButtonUpFcn','',...
+        'WindowButtonMotionFcn','',...
+        'ButtonDownFcn','',...
+        'UserData',[]);   % Solve MATLAB bug!
+set(fig,'UserData',udata);
+dipfig_set_action_check(fig,udata.state);
Index: /hypertools/hypertools/dissimm.m
===================================================================
--- /hypertools/hypertools/dissimm.m	(revision 3)
+++ /hypertools/hypertools/dissimm.m	(revision 3)
@@ -0,0 +1,85 @@
+%DISSIMM General dissimilarity mapping
+%
+%   W=DISSIMM(A,TYPE)
+%
+% INPUT
+%   A     Dataset
+%   TYPE  string name of a dissimilarity function
+%   PAR   optional parameter for the dissimilarity function
+%         or a cell array with multiple parameters
+%
+% OUTPUT
+%   W     Dissimilarity mapping
+%
+% DESCRIPTION
+% DISSIMM provides a general dissimilarity mapping for any function with
+% two arguments (data and prototypes). While training, prototype objects
+% are stored together with a name of a function (TYPE), responsible for the
+% computation of dissimilarities. When executed, the specified
+% dissimilarity function is invoked again supplying the prototype
+% objects as the second argument. If case the function contains
+% parameters (e.g. smoothing parameter or the derivative degree), these
+% can be specified in a cell array PAR.
+%
+% EXAMPLES
+% constructing an untrained mapping (using dasam.m function):
+%  >> w=dissimm('dasam')
+% training the dissimilarity mapping:
+%  >> w2=a*w
+%  Dissimilarity mapping 'dasam', 2 to 100 trained  mapping   --> dissimm
+% produce the disismilarity matrix:
+%  >> D=b*w2
+%  10 by 100 dataset with 2 classes: [5  5]
+
+% $Id: dissimm.m,v 1.5 2005/02/10 15:24:07 pavel Exp $
+
+function w=dissimm(a,type,par)
+
+	if (nargin == 0)
+		w = mapping(mfilename,{});
+		w = setname(w,['Dissimilarity mapping']);
+		return
+	end
+
+	% allow simple construction of untrained mapping:
+	if nargin==1 & ischar(a), type=a; a=[]; end 
+	if isempty(a) & ischar(type)
+		if ~exist('par','var')
+			w = mapping(mfilename,{type});
+		else
+			w = mapping(mfilename,{type,par});
+		end
+		w = setname(w,['Dissimilarity mapping ''' type '''']);
+	end
+
+	if isdataset(a)
+		% train the dissimilarity mapping
+		[m,k,c] = getsize(a);
+		if ~exist('par','var'), par=[]; end
+		w = mapping(mfilename,'trained',{type,par,a},getlab(a),k,m);
+		w = setname(w,'Dissimilarity mapping');
+	end
+	
+	if isa(type,'mapping')
+		% execute the mapping
+		par=type{2};
+		proto=type{3};
+		if isempty(par)
+			eval(['w=' type{1} '(a,proto);']);
+		elseif ~iscell(par)
+			eval(['w=' type{1} '(a,proto,par);']);
+		else
+			str=['w=' type{1} '(a,proto'];
+			% parameter is a cell
+			for i=1:size(par,2)
+				str=[str sprintf(',%f',par{i})];
+			end
+			str=[str ');'];
+			eval(str);
+		end
+	end
+
+	return
+	
+
+
Index: /hypertools/hypertools/dkl.m
===================================================================
--- /hypertools/hypertools/dkl.m	(revision 3)
+++ /hypertools/hypertools/dkl.m	(revision 3)
@@ -0,0 +1,49 @@
+%DKL Kullback-Leibler divergence
+%
+%     D=DKL(DATA,PROTO)
+%
+% INPUT
+%   DATA   a dataset
+%   PROTO  the dataset with prototypes (representation set)
+% OUTPUT
+%   D      dataset with a distance matrix
+%
+% DESCRIPTION
+% The Kullback-Leibler divergence (pp. 151, Pattern Recognition, Theodoridis)
+%
+
+% $Id: dkl.m,v 1.3 2005/03/02 11:58:56 pavel Exp $
+
+function d=dkl(data,proto)
+
+fprintf(' dkl:');
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+sc=size(data,1); % training sample size
+pc=size(proto,1); % test sample size
+d=zeros(sc,pc);
+
+labdata=getlab(data);
+labproto=getlab(proto);
+data2=data; data=+data;
+proto2=proto; proto=+proto;
+
+% correct for zeros
+proto((+proto==0))=0.00001;
+data((+data==0))=0.00001;
+
+step=round(pc/10);
+for i=1:pc
+  t=repmat(proto(i,:),sc,1);
+  t=sum(log( t./data ).*data ,2) + sum(log( data./t ).*t ,2);
+  d(:,i)=t;
+  if mod(i,step)==0, fprintf('.'); end
+end
+
+d=setdat(data2,d);
+d=setfeatlab(d,labproto);
+
+return
+  
Index: /hypertools/hypertools/dkl2.m
===================================================================
--- /hypertools/hypertools/dkl2.m	(revision 3)
+++ /hypertools/hypertools/dkl2.m	(revision 3)
@@ -0,0 +1,59 @@
+%DKL Kullback-Leibler divergence
+%
+%     D=DKL(DATA,PROTO)
+%
+% INPUT
+%   DATA   a dataset
+%   PROTO  the dataset with prototypes (representation set)
+% OUTPUT
+%   D      dataset with a distance matrix
+%
+% DESCRIPTION
+% The Kullback-Leibler divergence (pp. 151, Pattern Recognition,
+% Theodoridis, p. 176 in 2nd edition)
+%
+
+% $Id: dkl2.m,v 1.2 2005/03/02 13:39:45 serguei Exp $
+
+function d=dkl2(data,proto)
+
+fprintf(' dkl2:');
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+sc=size(data,1); % training sample size
+pc=size(proto,1); % test sample size
+d=zeros(sc,pc);
+
+labdata=getlab(data);
+labproto=getlab(proto);
+data2=data; data=+data;
+proto2=proto; proto=+proto;
+
+
+% normalization: we consider a histogram being a set of probability
+% estimates
+data=data./repmat(sum(data,2),[1,size(data,2)]);
+proto=proto./repmat(sum(proto,2),[1,size(proto,2)]);
+
+step=round(pc/10);
+for i=1:pc
+  t=repmat(proto(i,:),[sc,1]);
+
+  w = warning;
+  warning('off');
+  l = log(t./data);
+  warning(w);  
+
+  l(~isfinite(l)) = 0;
+  d(:,i)=sum((t-data).*l ,2);
+
+  if mod(i,step)==0, fprintf('.'); end
+end
+
+d=setdat(data2,d);
+d=setfeatlab(d,labproto);
+
+return
+  
Index: /hypertools/hypertools/dkl_true.m
===================================================================
--- /hypertools/hypertools/dkl_true.m	(revision 3)
+++ /hypertools/hypertools/dkl_true.m	(revision 3)
@@ -0,0 +1,94 @@
+%DKL Kullback-Leibler divergence
+%
+%     D=DKL_TRUE(DATA,PROTO,DELTA)
+%
+% INPUT
+%   DATA   a dataset
+%   PROTO  the dataset with prototypes (representation set)
+%   DELTA  regularization parameter (by default = 0)
+% OUTPUT
+%   D      dataset with a distance matrix
+%
+% DESCRIPTION
+% The Kullback-Leibler divergence (pp. 151, Pattern Recognition,
+% Theodoridis, p. 176 in 2nd edition)
+%
+
+% $Id: dkl_true.m,v 1.2 2005/04/08 13:46:17 serguei Exp $
+
+function d=dkl_true(data,proto,delta)
+
+fprintf(' dkl_true:');
+
+if nargin < 3
+  delta = 0;
+end
+
+if delta < 0
+  error('regularization parameter delta is negative');
+end
+
+nb = size(proto,2);
+if size(data,2)~=nb
+  error('both datasets must have the same feature sizes');
+end
+
+ns=size(data,1);  % the number of sampes
+np=size(proto,1); % the number of prototypes
+
+labdata=getlab(data);
+labproto=getlab(proto);
+
+
+data2=data; data=+data;
+proto2=proto; proto=+proto;
+
+
+% normalization: we consider a histogram being a set of probability
+% estimates
+data=data./repmat(sum(data,2),[1,size(data,2)]);
+proto=proto./repmat(sum(proto,2),[1,size(proto,2)]);
+
+if delta > 0
+  proto = (1-delta)*proto + delta/nb;
+  data = (1-delta)*data + delta/nb;
+  if ~isfinite(log(delta/nb))
+    prwarning(1,'regularization parameter too small to prevent infinite distances');
+  end
+end
+
+d=zeros(ns,np);
+if np <= ns
+  zind_data = find(data == 0);
+  for j=1:np
+    product = repmat(proto(j,:),[ns,1]);
+    zind = zind_data(product(zind_data)==0);
+
+    w = warning;
+    warning('off');
+    product = (data - product).*log(data./product);
+    warning(w);  
+    product(zind) = 0; 
+    d(:,j) = sum(product,2);
+  end
+
+else  
+  zind_proto = find(proto == 0);
+  for i=1:ns
+    product = repmat(data(i,:),[np,1]);
+    zind = zind_proto(product(zind_proto)==0);
+
+    w = warning;
+    warning('off');
+    product = (product - proto).*log(product./proto);
+    warning(w);  
+    product(zind) = 0; 
+    d(i,:) = sum(product,2)';
+  end
+end
+
+d=setdat(data2,d);
+d=setfeatlab(d,labproto);
+
+return
+  
Index: /hypertools/hypertools/dkla.m
===================================================================
--- /hypertools/hypertools/dkla.m	(revision 3)
+++ /hypertools/hypertools/dkla.m	(revision 3)
@@ -0,0 +1,57 @@
+%DKLA Assymetric Kullback-Leibler divergence
+%
+%     D=DKLA(DATA,PROTO)
+%
+% INPUT
+%   DATA   a dataset
+%   PROTO  the dataset with prototypes (representation set)
+% OUTPUT
+%   D      dataset with a distance matrix
+%
+% DESCRIPTION
+% The Kullback-Leibler divergence (pp. 151, Pattern Recognition,
+% Theodoridis, p. 176 in 2nd edition)
+%
+
+% $Id: dkla.m,v 1.1 2005/03/03 14:34:17 serguei Exp $
+
+function d=dkla(data,proto)
+
+fprintf(' dkla:');
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+sc=size(data,1); % training sample size
+pc=size(proto,1); % test sample size
+d=zeros(sc,pc);
+
+labdata=getlab(data);
+labproto=getlab(proto);
+data2=data; data=+data;
+proto2=proto; proto=+proto;
+
+
+% normalization: we consider a histogram being a set of probability
+% estimates
+data=data./repmat(sum(data,2),[1,size(data,2)]);
+proto=proto./repmat(sum(proto,2),[1,size(proto,2)]);
+
+step=round(pc/10);
+for i=1:pc
+  w = warning;
+  warning('off');
+  l = log(repmat(proto(i,:),[sc,1])./data);
+  warning(w);  
+  l(~isfinite(l)) = 0;
+ 
+  d(:,i)=l*proto(i,:)';
+
+  if mod(i,step)==0, fprintf('.'); end
+end
+
+d=setdat(data2,d);
+d=setfeatlab(d,labproto);
+
+return
+  
Index: /hypertools/hypertools/dkolmogorov.m
===================================================================
--- /hypertools/hypertools/dkolmogorov.m	(revision 3)
+++ /hypertools/hypertools/dkolmogorov.m	(revision 3)
@@ -0,0 +1,60 @@
+%DKOLMOGOROV Kolmogorov distance
+%
+%  D=DKOLMOGOROV(DATA)
+%  D=DKOLMOGOROV(DATA,PROTO)
+%
+% INPUT
+%  DATA  testing dataset
+%  PROTO training dataset (representation set)
+% 
+% OUTPUT
+%  D     dataset with a distance matrix
+%
+% DESCRIPTION
+% In these routine each spectrum is treated as a density of some distribution.
+% "Cumulative distribution function" for each spectrum is calculted.
+% Kolmogorov distance is a maximum of an absolute difference between 
+% two cumulative distribution functions. 
+% The number of objects in the output dataset D is equal to the one of DATA.
+% The number of features in D is equal to the number of objects in PROTO.
+% If PROTO is not supplied then PROTO==DATA.
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: dkolmogorov.m,v 1.3 2004/03/03 10:16:56 pavel Exp $
+
+function d=dkolmogorov(data,proto)
+
+%fprintf(' dkolmogorov:');
+
+if ~exist('proto','var'), proto=data; end
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+sc=size(data,1); % training sample size
+pc=size(proto,1); % test sample size
+if sc<2, errot('at least two samples are required'); end
+if pc<2, errot('at least two samples are required'); end
+
+labdata=getlab(data);
+labproto=getlab(proto);
+data2=data; data=+data;
+proto2=proto; proto=+proto;
+
+data=(cumsum(data'))';
+proto=(cumsum(proto'))';
+
+d=zeros(sc,pc);
+%step=round(pc/10);
+for i=1:pc
+  t=repmat(proto(i,:),sc,1);
+  d(:,i)=max(abs(data-t),[],2);
+end
+% d=dataset(d,labdata,'featlab',labproto);
+d=setdata(data2,d,getlab(proto2));
+      
+return
+  
Index: /hypertools/hypertools/dlh.m
===================================================================
--- /hypertools/hypertools/dlh.m	(revision 3)
+++ /hypertools/hypertools/dlh.m	(revision 3)
@@ -0,0 +1,51 @@
+%DLH likelihood distance
+%
+%     D=DLH(DATA,PROTO)
+%
+% INPUT
+%   DATA   a dataset
+%   PROTO  the dataset with prototypes (representation set)
+% OUTPUT
+%   D      dataset with a distance matrix
+%
+% DESCRIPTION
+% d(i,j) = - sum(log(data(i,:))*proto(j,:)')
+%
+
+% $Id: dlh.m,v 1.2 2005/04/08 11:29:08 pavel Exp $
+
+function d=dlh(data,proto)
+
+fprintf(' dlh:');
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+sc=size(data,1); % training sample size
+pc=size(proto,1); % test sample size
+d=zeros(sc,pc);
+
+labdata=getlab(data);
+labproto=getlab(proto);
+data2=data; data=+data;
+proto2=proto; proto=+proto;
+
+
+% normalization: we consider a histogram being a set of probability
+% estimates
+data=data./repmat(sum(data,2),[1,size(data,2)]);
+proto=proto./repmat(sum(proto,2),[1,size(proto,2)]);
+
+w = warning;
+warning('off');
+l = log(proto);
+warning(w);  
+l(~isfinite(l)) = 0;
+
+d = -(data*l');
+
+d=setdat(data2,d);
+d=setfeatlab(d,labproto);
+
+return
+  
Index: /hypertools/hypertools/dlh_true.m
===================================================================
--- /hypertools/hypertools/dlh_true.m	(revision 3)
+++ /hypertools/hypertools/dlh_true.m	(revision 3)
@@ -0,0 +1,103 @@
+%DLH_TRUE likelyhood distance
+%
+%     D=DLH_TRUE(DATA,PROTO,DELTA)
+%
+% INPUT
+%   DATA   a dataset
+%   PROTO  the dataset with prototypes (representation set)
+%   DELTA  reg parameter (by defautl =0)
+% OUTPUT
+%   D      dataset with a distance matrix
+%
+% DESCRIPTION
+% DATA and PROTO preprocessed in such a way that 
+% sum(DATA(i,:)) = sum(PROTO(j,:)) = 1
+%  
+% D computed as: 
+% D(i,j) = - DATA(i,:)*log(PROTO(j,:))'
+%
+% if DATA(i,k) == 0 then DATA(i,k)*log(PROTO(j,k)) 
+% considered as equal to zero
+%
+
+% $Id: dlh_true.m,v 1.7 2005/04/08 13:44:50 serguei Exp $
+
+function d=dlh_true(data,proto,delta)
+
+fprintf(' dlh_true:');
+
+if nargin < 3
+  delta = 0;
+end
+
+if delta < 0
+  error('regularization parameter delta is negative');
+end
+
+nb = size(proto,2);
+if size(data,2)~=nb
+  error('both datasets must have the same feature sizes');
+end
+
+ns=size(data,1);  % the number of sampes
+np=size(proto,1); % the number of prototypes
+
+labdata=getlab(data);
+labproto=getlab(proto);
+
+data2=data; 
+data=+data;
+
+%proto2=proto; 
+proto=+proto;
+
+% normalization: we consider a histogram being a set of probability
+% estimates
+data=data./repmat(sum(data,2),[1,nb]);
+proto=proto./repmat(sum(proto,2),[1,nb]);
+if delta > 0
+  proto = (1-delta)*proto + delta/nb;
+  if ~isfinite(log(delta/nb))
+    prwarning(1,'regularization parameter too small to prevent infinite distances');
+  end
+end
+
+%if delta > 0
+%  proto = (1-delta)*proto + repmat((delta/nb)*sum(proto,2),[1,nb]);
+%end
+%proto=proto./repmat(sum(proto,2),[1,nb]);
+
+w = warning;
+warning('off');
+proto = log(proto);
+warning(w);  
+
+%if delta > 0 & isfinite(log(delta/nb))
+%  d = data*proto';
+%  d=setdat(data2,-d);
+%  d=setfeatlab(d,labproto);
+%  return
+%end
+
+d=zeros(ns,np);
+if np <= ns
+  zind = find(data == 0);
+  for j=1:np
+    product = data.*repmat(proto(j,:),[ns, 1]);
+    product(zind) = 0;
+    d(:,j) = sum(product,2);
+  end
+else  
+  for i=1:ns
+    zind = find(data(i,:) == 0);
+    product = repmat(data(i,:),[np, 1]).*proto;
+    product(:,zind) = 0;
+    d(i,:) = sum(product,2)';
+  end
+end
+
+d=setdat(data2,-d);
+d=setfeatlab(d,labproto);
+
+return
+  
Index: /hypertools/hypertools/dmatch.m
===================================================================
--- /hypertools/hypertools/dmatch.m	(revision 3)
+++ /hypertools/hypertools/dmatch.m	(revision 3)
@@ -0,0 +1,57 @@
+%DMATCH Match distance
+%
+%  D=DMATCH(DATA,PROTO)
+%
+% INPUT
+%  DATA   testing dataset
+%  PROTO  training dataset (representation set)
+%
+% OUTPUT
+%  D      dataset with a distance matrix
+%
+% DESCRIPTION
+% In these routine each spectrum is treated as a density of some distribution.
+% "Cumulative distribution function" for each spectrum is calculted.
+% The output dataset D contains the match distances between such cdf's of 
+% DATA and PROTO datasets. Match distance is a sum of absolute differences 
+% between two cumulative distribution functions.
+% The number of objects in the output dataset D is equal to the one of DATA.
+% The number of features in D is equal to the number of objects in PROTO.
+% If PROTO is not supplied then PROTO==DATA.
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: dmatch.m,v 1.4 2005/02/07 14:42:50 pavel Exp $
+
+function d=dmatch(data,proto)
+
+if ~exist('proto','var'), proto=data; end
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+sc=size(data,1); % training sample size
+pc=size(proto,1); % test sample size
+if sc<2, errot('at least two samples are required'); end
+if pc<2, errot('at least two samples are required'); end
+
+labdata=getlab(data);
+labproto=getlab(proto);
+data2=data; data=+data;
+proto2=proto; proto=+proto;
+
+data=(cumsum(data'))';
+proto=(cumsum(proto'))';
+
+d=zeros(sc,pc);
+%step=round(pc/10);
+for i=1:pc
+  t=repmat(proto(i,:),sc,1);
+  d(:,i)=sum(abs(data-t),2);
+end
+d=setdata(data2,d,labproto);
+
+return
+  
Index: /hypertools/hypertools/dquadform.m
===================================================================
--- /hypertools/hypertools/dquadform.m	(revision 3)
+++ /hypertools/hypertools/dquadform.m	(revision 3)
@@ -0,0 +1,60 @@
+%DQUADFORM Quadratic-form distance
+%
+%  D=DQUADFORM(DATA,PROTO)
+%
+% INPUT
+%  DATA   testing dataset
+%  PROTO  training dataset (representation set)
+%
+% OUTPUT
+%  D      dataset with a distance matrix
+%
+% DESCRIPTION
+% In these routine each spectrum is treated as a density of some distribution (histogram).
+% The output dataset D contains the quadratic-form distances between such histograms from
+% DATA and PROTO datasets. 
+% Quadratic-form distance between two histograms h and k is
+% sqrt((h-k)'*A*(h-k)) where h and k are columns and A(i,j) = 1-d(i,j)/dmax
+%   d(i,j) is the absolute distance between bins (wavelengthes in our case) i and j 
+%   dmax is the maximum d(i,j)
+%
+% The number of objects in the output dataset D is equal to the one of DATA.
+% The number of features in D is equal to the number of objects in PROTO.
+% If PROTO is not supplied then PROTO==DATA.
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: dquadform.m,v 1.4 2005/02/07 14:42:50 pavel Exp $
+
+function d=dquadform(data,proto)
+
+if ~exist('proto','var'), proto=data; end
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+sc=size(data,1); % training sample size
+pc=size(proto,1); % test sample size
+
+fc=size(data,2);
+
+a=abs(repmat(0:(fc-1),fc,1)-repmat((0:(fc-1))',1,fc));
+a=1-a./(fc-1);
+
+labdata=getlab(data);
+labproto=getlab(proto);
+data2=data; data=+data;
+proto2=proto; proto=+proto;
+
+d=zeros(sc,pc);
+for i=1:pc
+  t=data-repmat(proto(i,:),sc,1);
+  d(:,i)=sum((t*a).*t, 2);
+end
+
+d=setdata(data2,d,labproto);
+  
+return
+  
Index: /hypertools/hypertools/drawident.m
===================================================================
--- /hypertools/hypertools/drawident.m	(revision 3)
+++ /hypertools/hypertools/drawident.m	(revision 3)
@@ -0,0 +1,39 @@
+% DRAWIDENT Draw overlay image highlighting identifiers of dataset subset
+%
+%    DRAWIDENT(DATA,SUBSET)
+%
+% INPUT
+%    DATA     spectral image dataset
+%    SUBSET   subset of the image (dataset) to be highlighted
+%
+% DESCRIPTION
+% DRAWIDENT renders the spectral image dataset in a dip_image window.
+% Then, image pixels corresponding to the data samples in SUBSET dataset
+% are highlighted by overlaying with the image.
+
+% $Id: drawident.m,v 1.2 2005/02/10 15:24:07 pavel Exp $
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function drawident(data,subset)
+	
+	% render the dataset as a dip image
+	im=data2dip(data);
+	
+	% get idents
+	id=subset.ident;
+	id=[id{:}];
+	
+	% create an overlay image
+	z=dip_image(zeros(data.objsize),'bin');
+	
+	% tag the points
+	z(id)=1;
+	
+	% create overlay
+	if length(size(im))==3
+		im=squeeze(im(:,:,1));
+	end
+	out=overlay(im,z,[max(im) 0 0])
Index: /hypertools/hypertools/dsam.m
===================================================================
--- /hypertools/hypertools/dsam.m	(revision 3)
+++ /hypertools/hypertools/dsam.m	(revision 3)
@@ -0,0 +1,77 @@
+%DSAM Spectral Angle Mapper (normalized inner product)
+%
+%  D=DSAM(DATA)
+%  D=DSAM(DATA,PROTO)
+%
+% INPUT 
+%  DATA    testing dataset
+%  PROTO   training dataset (representation set)
+% 
+% OUTPUT 
+%  D       dataset with a distance (normalized inner products) matrix
+%
+% DESCRIPTION   
+% Variables in the output dataset D are normalized inner products
+% between DATA samples and PROTO samples. The number of samples in D is equal to the 
+% one of  DATA. D.OBJSIZE is the same as DATA.OBJSIZE. If PROTO is not supplied then
+% PROTO==DATA.
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: dsam.m,v 1.7 2005/05/10 20:08:46 serguei Exp $
+
+function d=dsam(data,proto)
+
+if ~exist('proto','var'), proto=data; end
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+
+v=size(data,2);
+s=size(data,1);
+p=size(proto,1);
+
+
+%labdata  = getlab(data);
+labproto = getlab(proto);
+
+d = data;
+d = setdata(d,zeros(s,1));
+
+data  = +data;
+proto = +proto;
+
+if 0
+step = 300;
+
+b = 1:step:s;
+e = step:step:s;
+if length(e) < length(b)
+  e = [e s];
+end  
+
+for i=1:length(b)
+  data(b(i):e(i),:) = data(b(i):e(i),:)./repmat(sqrt(sum(data(b(i):e(i),:).^2,2)), [1 v]);
+end
+
+b = 1:step:p;
+e = step:step:p;
+if length(e) < length(b)
+  e = [e p];
+end  
+
+for i=1:length(b)
+  proto(b(i):e(i),:) = proto(b(i):e(i),:)./repmat(sqrt(sum(proto(b(i):e(i),:).^2,2)), [1 v]);
+end
+d = setdata(d, real(sqrt(1-min((data*proto'),1))), labproto);
+end
+
+ndata=sqrt(sum(data.*data,2));
+nproto=sqrt(sum(proto.*proto,2));
+d = setdata(d, real(sqrt(1-min((data*proto')./(ndata*nproto'),1))), labproto);
+
+return
+  
Index: /hypertools/hypertools/dshape.m
===================================================================
--- /hypertools/hypertools/dshape.m	(revision 3)
+++ /hypertools/hypertools/dshape.m	(revision 3)
@@ -0,0 +1,72 @@
+%DSHAPE Spectral distance using shape (Savitsky-Golay smoothing)
+%
+%   D=DSHAPE(DATA)
+%   D=DSHAPE(DATA,PROTO)
+%   D=DSHAPE(DATA,PROTO,WINSIZE,DER)
+%
+% INPUT
+%  DATA    testing dataset
+%  PROTO   training dataset (representation set)
+%  WINSIZE window size for the Saivitsky-Golay filter
+%  DER     derivative order (default: 1)
+%
+% OUTPUT
+%  D       dataset with a distance matrix
+%   
+% DESCRIPTION
+% This distance reflects the differences in shape of spectra: It is the L1
+% (city-block) distance between smoothed first derivatives of DATA and
+% PROTO datasets. Smoothing is performed using a Savitsky-Golay filter with
+% window size WSIZE.  By default: WSIZE=11; PROTO=DATA; DER=1;
+%
+% For the sake of speed, a distfunc MEX file is provided implementing
+% the city block distance computation. It is used if present.
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: dshape.m,v 1.5 2005/02/08 10:23:51 pavel Exp $
+
+function d=dshape(data,proto,wsize,der)
+
+if ~exist('proto','var'), proto=data; end
+if ~exist('wsize','var'), wsize=11; end
+if ~exist('der','var'), der=1; end
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+sc=size(data,1); % training sample size
+pc=size(proto,1); % test sample size
+
+d=zeros(sc,pc);
+
+labdata=getlab(data);
+labproto=getlab(proto);
+objsize=data.objsize;
+data2=data; data=+data;
+proto2=proto; proto=+proto;
+
+ws=smoothm('sg',wsize,1,1);
+data=data2*ws;
+data=data./(repmat(max(+data,[],2),1,size(data,2))+eps);
+proto=proto2*ws;
+proto=proto./(repmat(max(+proto,[],2),1,size(proto,2))+eps);
+
+% for computational reasons, we put the lopp over prototypes
+% into a mex file dist:
+if exist('distfunc','file')
+    fprintf(1,'...using the distfunc MEX implementation\n');
+    d=distfunc(+data,+proto);
+else
+    for i=1:pc
+	t=repmat(+proto(i,:),sc,1);
+	d(:,i)=sum(abs(data-t),2);
+    end
+end
+
+d=setdata(data2,d,labproto);
+
+return
+  
Index: /hypertools/hypertools/dspec_shape.m
===================================================================
--- /hypertools/hypertools/dspec_shape.m	(revision 3)
+++ /hypertools/hypertools/dspec_shape.m	(revision 3)
@@ -0,0 +1,90 @@
+%DSPEC_SHAPE Spectral distance using shape (Gaussian smoothing)
+%
+%   D=DSPEC_SHAPE(DATA)
+%   D=DSPEC_SHAPE(DATA,PROTO)
+%   D=DSPEC_SHAPE(DATA,PROTO,SIGMA,DER,USEDIP)
+%
+% INPUT
+%  DATA    testing dataset
+%  PROTO   training dataset (representation set)
+%  SIGMA   parameter for the gaussian filter
+%  DER     derivative order (default: 1)
+%  USEDIP  use DIPImage for smoothed derivatives (default: 1 i.e. run
+%          convolution in Matlab)
+%
+% OUTPUT
+%  D       dataset with a distance matrix
+%   
+% DESCRIPTION
+% This distance reflects the differences in shape of spectra:
+% It is the L1 (city-block) distance between smoothed first derivatives of
+% DATA and PROTO datasets. Smoothing is performed by convolving with the
+% gaussian filter with the parameter SIGMA. By default: SIGMA==1;
+% PROTO==DATA.
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Spectral distance using shape (Gaussian smoothing)
+
+% $Id: dspec_shape.m,v 1.13 2005/02/10 15:24:07 pavel Exp $
+
+function d=dspec_shape(data,proto,sigma,der,usedip)
+
+%fprintf(' dspec_shape:');
+
+if ~exist('proto','var'), proto=data; end
+if ~exist('sigma','var'), sigma=1; end
+if ~exist('der','var'), der=1; end
+if ~exist('usedip','var'), usedip=1; end
+
+if size(data,2)~=size(proto,2)
+  error('both datasets must have the same feature sizes');
+end
+sc=size(data,1); % training sample size
+pc=size(proto,1); % test sample size
+
+d=zeros(sc,pc);
+
+labdata=getlab(data);
+labproto=getlab(proto);
+objsize=data.objsize;
+data2=data; data=+data;
+proto2=proto; proto=+proto;
+
+if usedip==1
+    fprintf(1,'using DIPImage\n');
+    data=double(dip_gauss(dip_image(+data),[1 0],[sigma sigma],[der 0]));
+    proto=double(dip_gauss(dip_image(+proto),[1 0],[sigma sigma],[der 0]));
+else
+    % use standard Matlab convolution
+    fprintf(1,'using derfilter\n');
+    data=derfilter(+data,sigma);
+    proto=derfilter(+proto,sigma);    
+end
+
+data=data./repmat(max(data,[],2),1,size(data,2));
+proto=proto./repmat(max(proto,[],2),1,size(proto,2));
+
+% for computational reasons, we put the lopp over prototypes
+% into a mex file dist:
+if exist('distfunc')==3
+    d=distfunc(data,proto);
+else
+    for i=1:pc
+	t=repmat(proto(i,:),sc,1);
+	d(:,i)=sum(abs(data-t),2);
+    end
+end
+
+if prversion>3.2
+  d=dataset(d,labdata,'featlab',labproto);
+else
+%  d=dataset(d,labdata,labproto);
+  d=setdata(data2,d,labproto);
+end
+
+% the distance dataset will inherit the objsize from the input dataset
+d=setobjsize(d,objsize);
+
+return
+  
Index: /hypertools/hypertools/edgedetection.m
===================================================================
--- /hypertools/hypertools/edgedetection.m	(revision 3)
+++ /hypertools/hypertools/edgedetection.m	(revision 3)
@@ -0,0 +1,293 @@
+% EdgeDetection Detecting edge in hyperspectral image
+%
+%    A = EDGEDETECTION(DATASET, ALG)
+%
+% INPUT
+%   DATASET name of dataset
+%   ALG   edge detection algorithm ('Zenzo' or 'Cluster')
+%
+% OUTPUT
+%   A      dataset
+
+% DESCRIPTION
+% Di Zenzor is a gradient based edge detection method, which extended the
+% concept of gradient criteria for grayscale image to multi-demensional image.
+% Algorithm.
+% Step 1. Extract each band from hyperspectral image
+% Step 2. Calculate gradient value for each pixel
+% Step 3. Determine threshold based on gradient's histogram
+% Step 4. Create final edge image of hyperspectral
+
+% Copyright: Dinh Viet Cuong, d.v.cuong@tudelft.nl
+% ICT group, Elect. Eng., Maths and Comp. Sc, 
+% Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: edgedetection.m,v 1.1 2009/01/16 14:55:35 dcuong Exp $
+
+function edge = edgedetection(a,m)
+
+	if nargin == 0
+		error('error!, input dataset name');
+	elseif ~isa(a,'dataset')
+		error('error!, input dataset name');	
+	else
+		switch lower(m)
+		  case {'zenzo','ze'}
+	
+			% Get width, height, and nChannels of hyperspectral image
+			[imheight, imwidth] = getobjsize(a);
+			
+		  
+		  	% Calculate gradient and edgethreshold values
+			[gradient, edgethresh] = calgradient(a);
+			
+			edge = zeros(imheight, imwidth);
+			
+			%edgethreshold = mean(mean(gradient1))
+			
+			x = find(gradient < edgethresh);
+			edge(x) = 0;
+			x = find(gradient > edgethresh);
+			edge(x) = 1;
+		
+		  case {'cluster','cl'}
+		  	
+			% remove the label
+			data = +a;
+			
+			% create a subset of a
+		  	b = gendat(data,1500);
+			
+                        % Use it for finding 5 clusters, for example
+			[lab,w] = emclust(b,nmc,4);
+			
+                  	% Classify the entire image and show it
+			c = a*w;
+			
+			e = spatm(c)*maxc;
+			
+			%figure; classim(e);
+			
+			% check the confidence belonging to a cluster of a pixels
+			[conf,J] = max(e*classc,[],2);
+			
+			labels = reshape(conf,getobjsize(a));
+			
+			% Convert data to image
+			im = data2im(a);
+			
+			% Get width, height, and nChannels of hyperspectral image
+			[imheight, imwidth, nim] = size(im);
+			
+			edge = zeros(imheight, imwidth);
+
+			% if conf of a pixel is smaller than 0.55, it is considered as edge candidate
+			thresh = 0.55;
+			
+			x = find(labels <= thresh);
+			edge(x) = 1;
+			x = find(labels > thresh);
+			edge(x) = 0;
+			%show(edge);
+			
+			% Calculate gradient value for these pixels;
+			[gradient, edgethresh] = calgradient(a);
+			
+			% gradient threshold is 0.5
+			edgethresh = edgethresh /2	
+			% refine the result
+			%x = find(gradient <= edgethresh);
+			%edge(x) = 0;
+			
+		  case {'gradientcluster','gc'}
+
+		        % Stage 1. Calculate gradient value for each band
+		  	
+			% Step 1. Smooth hyperspectral image
+			sigma = 1; % assign default sigma value;
+			smoothimage = datgauss(a, sigma);
+			
+			% Step 2. Convert dataset to image
+			im = data2im(smoothimage);
+			
+			% Get width, height, and nChannels of hyperspectral image
+			[imheight, imwidth, nim] = size(im);
+			
+			dy = zeros(imheight, imwidth, nim); 
+			dx = zeros(imheight, imwidth, nim);
+
+			% Step 3. Calculate the first derivative of the image
+			for i = 1: nim
+				dy(:,:,i) = [diff(im(:,:,i)); zeros(1, imwidth)]; % add the border
+				dx(:,:,i) = [diff(im(:,:,i)')' zeros(imheight,1)]; % add the border
+				gradient(:,:,i) = dx(:,:,i).^2 + dy(:,:,i).^2;
+				
+				%gradient(:,:,i) = sqrt(gradient(:,:,i));
+				% Normalize the gradient
+				%gradient(:,:,i) = gradient(:,:,i) ./ sum(sum(gradient(:,:,i)));
+			end
+			
+			% Step 2. Cluster in feature bases
+			
+			% Create dataset
+			d = im2feat(gradient);
+			d = dataset(+d, [], 'objsize', [imheight imwidth]);
+			
+			%struct(d)
+			
+		  	b = gendat(d,1500);
+			
+                        % Use it for finding 6 clusters
+			[lab,w] = emclust(b,nmc,6);
+			
+			% Classify the entire image and show it
+			c = d*w;
+			
+			e = spatm(c)*maxc;
+			%e = spatm(c)*prodc;
+			
+			labs = e*labeld;
+			setlabels(d,labs);
+			
+			figure; scatterd(d);
+			%show(e);
+			%sprintf('structure of c:')
+			%struct(c)
+			
+			%sprintf('data of c:')
+			%double(c*classc)
+					
+			%size(c)
+			%labels = c*labeld
+			%size(labels)			
+			
+			%e = spatm(c)*maxc;
+			% replace this function
+			%figure; classim(c);
+
+			% Merge non-background clusters into one cluster
+			
+			%lab = e*labeld;
+			%seg = segment_comb(setlabels(d,lab),5);
+			%show(seg);
+									
+			[mx,J] = max(double(e*classc),[],2);
+			
+			
+			total = zeros(1, size(c,2));
+			
+			t = unique(J(:));
+			count = hist(J(:),t);
+			
+			[maxv pos] = max(count);
+			
+			x = find(J == pos);
+			labels(x) = 1;
+			
+			x = find(J ~= pos);
+			labels(x) = 2;
+		
+			labels = reshape(labels,getobjsize(c));
+			edge = labels;
+			clear labels;
+ 		 end
+	end
+end		
+	
+function [gradient, edgethresh] = calgradient(a)
+
+%input: a: input dataset;
+%output: gradient: gradient value
+%        edge threshold value
+
+	% Step 1. Smooth hyperspectral image
+	sigma = 1; % assign default sigma value;
+	smoothimage = datgauss(a, sigma);
+			
+	% Step 2. Convert dataset to image
+	im = data2im(smoothimage);
+			
+	% Get width, height, and nChannels of hyperspectral image
+	[imheight, imwidth, nim] = size(im);
+			
+	gradient_x_x = zeros(imheight, imwidth); 
+	gradient_x_y = zeros(imheight, imwidth); 
+	gradient_y_y = zeros(imheight, imwidth);
+			
+	d1 = zeros(imheight, imwidth); 
+	d2 = zeros(imheight, imwidth);
+			
+	gradient1 = zeros(imheight, imwidth); 	
+	gradient2 = zeros(imheight, imwidth); 
+			
+	% Step 3. Calculate the first derivative of the image
+	for i = 1: nim
+		dy(:,:,i) = [diff(im(:,:,i)); zeros(1, imwidth)]; % add the border
+		dx(:,:,i) = [diff(im(:,:,i)')' zeros(imheight,1)]; % add the border
+				
+		% Step 4. Calculate the gradient strength of each image
+		gradient_x_x = gradient_x_x + dx(:,:,i).^2;
+		gradient_y_y = gradient_y_y + dy(:,:,i).^2;
+		gradient_x_y = gradient_x_y + dx(:,:,i) .* dy(:,:,i);
+	end
+			
+	% Step 5. Calculate the global gradient direction of every pixel in hyperspectral image
+	m = gradient_x_x - gradient_y_y;
+			
+	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+	% There are 2 possible result for atan function, 
+	% the first one is smaller than pi/2
+	% the other is larger than pi/1
+	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+			
+	m(m ==0) = 1e-10;
+	d1 = 0.5 * atan2((2*gradient_x_y) , m);
+			
+	y = d1 < 0;
+	d1 = d1 + pi*y;
+			
+	y = d1 > pi/2;
+	d1 = d1 - pi*y;
+	d2 = d1 + pi/2;
+			
+	% Step 6. Calculate the global gradient strength of every pixel in hyperspectral. 
+	% One gradient is maximum value, and the other is minimum value.
+	% Select the larger one.
+			
+	gradient = sqrt(0.5*( (gradient_x_x + gradient_y_y) +...
+	            (gradient_x_x - gradient_y_y) .* cos(2*d1) + 2 *...
+	            gradient_x_y .* sin(2*d1)));
+			
+	gradient2 = sqrt(0.5*( (gradient_x_x + gradient_y_y) +...
+	            (gradient_x_x - gradient_y_y) .* cos(2*d2) + 2 *...
+	             gradient_x_y .* sin(2*d2)));
+			
+	y = find(gradient < gradient2);
+	gradient(y)=gradient2(y);
+						
+	% Normalize the global gradient
+	gradient = gradient ./ sum(sum(gradient));
+			
+	% Step 7. Determine threshold for edge detection based on histogram
+	g = reshape(gradient, 1, imwidth*imheight);
+			
+	[his,val] = hist(g);
+			
+	cout = 0;t = 1;
+	
+	% for zenzor method
+	%threshold = 0.6 * imwidth * imheight;
+	
+	% for clustering method
+	threshold = 0.75 * imwidth * imheight;
+			
+	while cout < threshold  
+		cout = cout + his(1,t);
+	 	t = t+1;
+       end
+			
+	edgethresh = val(1,t);
+
+end
+  	
Index: /hypertools/hypertools/featself_simple.m
===================================================================
--- /hypertools/hypertools/featself_simple.m	(revision 3)
+++ /hypertools/hypertools/featself_simple.m	(revision 3)
@@ -0,0 +1,116 @@
+%FEATSELF_SIMPLE Simple forward feature selection
+% 
+% 	[W,R] = FEATSELF(A,CRIT,K,T)
+% 
+% Forward selection of K features using the dataset A. CRIT sets the 
+% criterion used by the feature evaluation routine FEATEVAL. If the 
+% data set T is given, it is used as test set for FEATEVAL. For K=0 
+% the optimal feature set (maximum value of FEATEVAL) is returned. 
+% The result W can be used for selecting features by B*W.  Defaults: 
+% crit='NN', K=0. In R the search is step by step reported:
+% 
+% 	R(:,1) : number of features
+% 	R(:,2) : criterion value
+% 	R(:,3) : added / deleted feature
+% 
+% See also MAPPINGS, DATASETS, FEATEVAL, FEATSELO, FEATSELB, FEATSELI,
+% FEATSELP, FEATSELM
+
+% Copyright: R.P.W. Duin, duin@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function [W,R,info] = featself_simple(A,crit,ksel,T,initset)
+if nargin < 2, crit = 'NN'; end
+if nargin < 3, ksel = 0; end
+if nargin < 4, T = []; end
+
+if nargin == 0 | isempty(A)
+	W = mapping('featself',{crit,ksel,T});
+	W = setname(W,'Forward Feature Selection');
+    return
+end
+
+[m,k,c] = getsize(A);
+featlist = getfeatlab(A);
+
+if ~isempty(T)
+	if k ~= size(T,2)
+		error('Data sizes do not match')
+ 	end
+end
+
+Cmax = 0;
+if ~exist('initset','var')
+    I = [1:k];
+    J = [];
+else
+    % we start from a given subset
+    I = setdiff(1:k,initset);
+    J = initset;
+end
+R = [];
+Iopt = J;
+iter=1;
+crit_eval=0; % number of crit evaluation
+thesameres=0;
+while length(J) < k
+	C = zeros(1,length(I));
+	fprintf(1,'[%d: (%d) ',iter,length(I));	
+	for j = 1:length(I)
+		L = [J,I(j)];
+		if isempty(T)
+			C(j) = feateval(A(:,L),crit);
+		else
+			C(j) = feateval(A(:,L),crit,T(:,L));
+		end
+		if C(j) > Cmax
+			Cmax = C(j);
+			Iopt = L;
+		end
+%		fprintf(1,'.');
+	end
+	crit_eval=crit_eval+length(I);
+	
+	[mx,j] = max(C);
+	J = [J,I(j)];
+  	I(j) = [];
+	
+	% is the criterion is a classification performance
+	% and we reached full separability, stop
+	if isa(crit,'mapping') & Cmax==1
+	   break
+	end
+	r = [length(J),mx,J(end)];
+	disp(r)
+	R = [R; r];
+	% increase counter if the same result happens again
+	if (size(R,1)>1)
+		if R(end-1,2)==R(end,2)
+			thesameres=thesameres+1; 
+			fprintf(1,'T%d ',thesameres);
+		else
+			thesameres=0; 			
+		end
+	end
+	% stopping criterion:
+	% stop, when reaching requested feature count or perfect
+        % separation or if we're above 95% accuracy and the same value repeats 10
+        % times and the improvement is smaller then 0.5% (simple, hee? :-)
+	if length(J) == ksel | r(2)==1.0 | ...
+		      (size(R,1)>1 & (R(end,2)/R(end-1,2))<1.005 & ...
+		       ( R(end,2)>=0.95 | thesameres>10 )  )
+	   % increase less then a percent?
+	   info.crit_eval=crit_eval;	   
+	   W = cmapm(k,J);
+	   W = setlabels(W,featlist(J,:));
+	   W = setname(W,'Forward Feature Selection');
+	   return
+	end
+	iter=iter+1;	
+end
+info.crit_eval=crit_eval;
+W = cmapm(k,Iopt);
+W = setlabels(W,featlist(Iopt,:));
+W = setname(W,'Forward Feature Selection');
+return
Index: /hypertools/hypertools/fig2dip.m
===================================================================
--- /hypertools/hypertools/fig2dip.m	(revision 3)
+++ /hypertools/hypertools/fig2dip.m	(revision 3)
@@ -0,0 +1,71 @@
+% FIG2DIP Retrieve DIP images from figures via handles or indices
+%
+%    DIP = FIG2DIP(FIGH)
+%
+% INPUT
+%   FIGH   vector with figure handles or figure indices
+%
+% OUTPUT
+%   DIP    DIP image
+%
+% DESCRIPTION
+% Retrieves 2D DIP images via figure handles or indices. If a vector of
+% handles (indices) is given, the function returns a multi-band image.
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: fig2dip.m,v 1.5 2005/11/02 14:29:17 pavel Exp $
+
+function dip=fig2dip(figh)
+	
+	if ~all(ishandle(figh))
+		if all(round(figh)==figh)
+			% assuming these are figure numbers
+			% construct the vector with figure handles
+			t=[];
+			for i=1:length(figh)
+				t=[t figure(i)];
+			end
+			figh=t;
+		else
+			error(['if number are supplied, these must be' ...
+			       ' integers (figure numbers)']);
+		end
+	end
+	
+	dip=get_one_dip(figh(1));
+	if length(figh)>1
+		t=dip;
+		dip=dip_image(zeros(size(t,2),size(t,1),length(figh)));
+		dip(:,:,0)=t;
+		clear t;
+		for i=2:length(figh)
+			dip(:,:,i-1)=get_one_dip(figh(i));
+		end
+	end
+	
+	return
+	
+function d=get_one_dip(figh)
+
+		if ishandle(figh)
+			
+			ud=get(figh,'userdata');
+			
+%			if isfield(ud,'slices')
+%				% multidiomensional dip_image 
+%				d=ud.slices;
+			if isfield(ud,'imagedata')
+				% single band dip_image
+				d=ud.imagedata;
+			else
+				error('unknown format');
+			end
+		else
+			error('figure handle required');
+		end
+	
+	return
+	
Index: /hypertools/hypertools/genfeatsel.m
===================================================================
--- /hypertools/hypertools/genfeatsel.m	(revision 3)
+++ /hypertools/hypertools/genfeatsel.m	(revision 3)
@@ -0,0 +1,171 @@
+%GENFEATSEL Genetic feature selection algorithm
+%
+%       [W,P,E]=GENFEATSEL(DATA,N,GENC,WIN,T,PM)
+%
+% INPUT
+%    DATA   original dataset
+%    N      population size (default N=500)
+%    GENC   generation count (default genc=30)
+%    WIN    untrained classifier to be used estimate error
+%           (opt, def: fisherc)
+%    T      feasibility threshold on error (opt,def:0.05)
+%    PM     mutation rate (opt,def: Pm=0.05)
+%    DIM    number of features switched on initially
+%           (opt,def: dim=[2 size(data,2)])
+%
+% OUTPUT
+%    W     feature selection mapping (the best subset found)
+%    P     the final population (uint8 matrix, each row is a
+%          binary-encoded feature subset)
+%    E     error rate for each population individuum
+%
+% DESCRIPTION
+% Genetic algorithm-based feature selection.
+%
+% REFERENCE 
+% Siedlecki, Sklansky, A note on genetic algorithms for
+% large-scale feature selection, Pattern Recognition Letters, vol.10,
+% pp.335-347, 1989
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: genfeatsel.m,v 1.6 2005/02/10 15:24:07 pavel Exp $
+
+function [w,P,e]=genfeatsel(data,N,genc,win,t,Pm,dim)
+
+	if ~exist('N','var'), N=500; end
+	if ~exist('genc','var'), genc=30; end	
+	if ~exist('win','var'), win=fisherc; end			
+	if ~exist('t','var'), t=0.05; end		
+	if ~exist('Pm','var'), Pm=0.05; end	
+	if ~exist('dim','var'), dim=[2 size(data,2)]; end
+	
+	m=0.01; % error margin
+	const=1/(exp(1)-1);
+
+	f=zeros(N,1); % fitness function
+	newf=f;
+	
+	epsilon=1.01;
+
+	fc=size(data,2); % feature count
+	
+	P=create_init_pop(N,fc,dim);
+	M=P; % mating set
+
+	fc2=floor(fc/2); % index of a band half-way 
+	N2=floor(N/2); % index of a population sample half-way
+	
+	% evaluate initial population
+	l=sum(P,2); % number of features per individual
+	e=get_err(data,P,win); % population errors
+	J=l+const*(exp((e-t)./m)-1); % criterion
+	% compute the fitness function
+	for i=1:N
+		f(i)=epsilon*max(J-J(i));
+	end
+	[temp,ind]=sort(-f);
+		
+	if all(f==0)
+		error('zero criterion');
+	end
+	
+	for g=1:genc
+		fprintf(1,'[%d',g);
+
+		% choose the mating set
+		
+		cumf=cumsum(f);
+		x=floor(rand(1,N)*N);
+
+		for i=1:N
+			temp=find(cumf>=x(i));
+			M(i,:)=P(temp(1),:);
+		end
+		
+		fprintf(1,'.');
+		
+		% crossover
+		
+		temp=randperm(fc); % crossover features are selected randomly 
+		
+		M=[M(randperm(N),temp(1:fc2)), M(randperm(N),temp(fc2+1:fc))];
+
+		% evaluate crit on new members
+		newe=get_err(data,M,win);
+		newJ=sum(M,2)+const*(exp((newe-t)./m)-1); % criterion
+		% compute the fitness function
+		for i=1:N
+			newf(i)=epsilon*max(newJ-newJ(i));
+		end
+
+		% mutate the new offspring
+		temp=find(rand(N,fc)<=Pm);
+		M(temp)=not(M(temp));
+
+		% get the best from both sets
+		[temp,newind]=sort(-[f;newf]);
+		newind=newind(1:N); % indices in the combined population
+		temp=[P; M]; % combined population
+		P=temp(newind,:);
+
+		% update the population		
+		temp=[f;newf]; f=temp(newind);
+		temp=[e;newe]; e=temp(newind);
+		temp=[J;newJ]; J=temp(newind);		
+		l=sum(P,2);
+
+		fprintf(1,':]');
+	end
+	
+	[temp,ind]=sort(J); % sort according to the criterion
+	P=P(ind,:); % update the order
+	e=e(ind);
+	ind=find(P(1,:)==1); % feature indices
+
+	w=cmapm(fc,ind);
+	
+	return
+	
+	
+% N - number of individuals to create
+% d - number of dimensions (features) we search in
+% dim - how many dimensions should be switched on
+%       Dim may be a vector specifying lower and upper bound)
+function P=create_init_pop(N,d,dim)
+
+	% population matrix
+	P=repmat(uint8(0),N,d);
+
+	[ignore,ind]=sort(rand(N,d),2);
+	clear ignore
+	
+	% feature count per individual:
+	if length(dim)==1
+		% constant number of switched on-dimensions
+		fc=dim*ones(N,1);
+	else
+		fc=dim(1)+floor(rand(N,1)*dim(2));
+	end
+	
+	for i=1:N
+		P(i,ind(i,1:fc(i)))=1;
+	end
+	
+	return
+	
+% measure the error for each feature setup (chromosome) in P
+% on data using user-defined mapping w
+function e=get_err(data,P,win)
+	
+	e=zeros(size(P,1),1);
+	for i=1:size(P,1)
+		ind=find(P(i,:)>0);
+                w=data(:,ind)*win;
+		e(i)=data(:,ind)*w*testc;
+	end
+	
+	return
+	
Index: /hypertools/hypertools/get_percentile.m
===================================================================
--- /hypertools/hypertools/get_percentile.m	(revision 3)
+++ /hypertools/hypertools/get_percentile.m	(revision 3)
@@ -0,0 +1,101 @@
+% GET_PERCENTILE computes percentiles of a data sample
+%
+%   PERC=GET_PERCENTILE(DATA,P,DIM)
+%
+% INPUT
+%   DATA   data sample (double array or dataset)
+%   P      percentiles (may be a vector)
+%   DIM    defines along which direction percentile should be computed
+%          optional; by default the first non-singleton is used (if data is not a scalar)
+%
+% OUTPUT
+%   PERC   scalar, vector, or matrix of doubles with percentiles
+%
+% DESCRIPTION
+% For 0 < P < 1, this routine returns 100*P percentiles of DATA.
+% Multidimensional arrays and PRTools datasets (will be converted into double) are supported.
+%
+% Percentiles will be calculated along the direction DIM. By default DIM is the first
+% non-singleton direction. If DATA is K-by-...-by-SIZE(DATA,DIM)-by-...-by-M matrix and P is 
+% a vector of length L then PERC has dimensions M-by-...-by-L-by-...-by-K.
+%
+% perc = get_percentile((1:5),[0.5, 0.75]);
+% returns perc == [3, 4];
+%
+% perc = get_percentile((1:5)',[0.5, 0.75]);
+% returns perc == [3; 4];
+%
+% perc = get_percentile([(1:5)', (11:15)'],[0.5, 0.75]);
+% returns perc == [[3; 4], [13; 14]];
+%
+% z = cat(3,[1 1; 1 11], [2 2; 2 12], [3 3; 3 13], [4 4; 4 14], [5 5; 5 15]); 
+% perc = get_percentile(z,[0.5, 0.75], 3);
+% returns perc == cat(3, [3 3; 3 13], [4 4; 4 14]);
+%
+% to ensure that percentiles are always calculated for featues 
+% over the objects of dataset use 
+% perc = get_percentile(data,p,1);
+
+% $Id: get_percentile.m,v 1.2 2005/10/19 11:33:37 serguei Exp $
+
+function perc = get_percentile(data,p,dim)
+  if nargin < 3 
+    dim = [];   
+  end    
+
+  if any(p>=1.0 | p<=0)
+		error('0 < p < 1 is required');
+	end
+	
+  if isempty(data)
+    error('can''t compute percentiles on empty data');
+  end
+
+  if isdataset(data)
+    data = +data;
+    if size(data,1) == 1 & size(data,2) ~= 1 & ~isequal(dim,1)
+      prwarning(1,'only one object in dataset; percentile(s) will be computed over features');  
+    end
+  end  
+  
+  if isempty(dim)
+    sz  = size(data);
+    dim = find(sz > 1);
+    if isempty(dim)
+      dim = 1;
+      %error('can''t compute percentile on scalar');  
+    else
+     dim = dim(1);
+    end
+  end
+  
+  %if size(data,1)==1, data=data'; end
+	perm  = [dim, (1:(dim-1)), ((dim+1):length(size(data)))];
+  data  = permute(data,perm); 
+	
+  p = p(:);
+  data = sort(data,1);
+  t = size(data,1)*p;
+
+	p_size = size(data);
+  p_size(1) = length(p);
+  perc =zeros(p_size);
+  
+	for i=1:length(p)
+		if t(i)==floor(t(i))
+			% t is integer
+			perc(i,:)=mean(data([t(i) t(i)+1],:));
+		else
+			perc(i,:)=data(floor(t(i))+1,:);
+		end
+	end
+		
+	% compatibility
+  %if length(size(data)) == 2 & size(data,2) == 1, return, end 
+  
+  perc = ipermute(perc,perm);
+  
+  
+  
+  
+  return
Index: /hypertools/hypertools/get_spec_colormap.m
===================================================================
--- /hypertools/hypertools/get_spec_colormap.m	(revision 3)
+++ /hypertools/hypertools/get_spec_colormap.m	(revision 3)
@@ -0,0 +1,29 @@
+%GET_SPEC_COLORMAP Generate colormap for label images
+%
+%  M = GET_SPEC_COLORMAP
+%
+% OUTPUT
+%  [256-by-3] colormap
+%
+% DESCRIPTION
+% Result is the colormap suitable for the label images 
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: get_spec_colormap.m,v 1.5 2005/02/10 15:24:07 pavel Exp $
+
+function m=get_spec_colormap
+ 
+  m = [0 0 0; 0 0 1; 1 0 0; 1 1 1; 0 1 1; 0 1 0; 1 0 1]; 
+ 
+  m = [m ; perms([ 0 0.6 1])];
+  
+  m = [m ; perms([0 0.3 1])];
+     
+% other pallete may be obtained by randomizing the existing
+% dipimage label palette.
+% It seems quite good and high contrast.
+% >> prlseed(31); ind=randperm(size(m,1)); m3=m(ind,:); colormap(m3)
+
Index: /hypertools/hypertools/getli.m
===================================================================
--- /hypertools/hypertools/getli.m	(revision 3)
+++ /hypertools/hypertools/getli.m	(revision 3)
@@ -0,0 +1,72 @@
+%GETLI Return label image from a dataset or label vector
+%
+%  LI = GETLI(A,B)
+%
+% INPUT
+%  A    dataset, label vector or several collated label vectors
+%  B    if A is a label vector, B should be a dataset; size of the image defined by the B.OBJSIZE
+%
+% OUTPUT
+%  LI   label image 
+%
+% DESCRIPTION
+% Converts a dataset, a label vector or several collated label vectors
+% into a dip image (or matrix, if DIPimage is not installed).
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: getli.m,v 1.7 2005/02/10 15:24:07 pavel Exp $
+
+function li=getli(a,b)
+	
+	if isdataset(a)
+	
+	   objsize=a.objsize;
+	   
+	   if length(objsize)==1
+	      
+	      % the dataset does not contain image
+	      % we can still return the labels reorganised
+	      % into a square
+	      
+	      sc=size(a,1); % sample count
+	      
+	      t=ceil(sqrt(sc));
+	      t2=ceil(sc/t);
+	      
+	      objsize=[t t2];
+	      
+	      li=zeros(t,t2);
+	      li(1:sc)=a.nlab;
+	      li(sc+1:end)=NaN;
+	      
+	   elseif length(objsize)==2
+	      % classical 2D image stored in a dataset
+	      li=reshape( a.nlab, objsize(1), objsize(2) );
+	   else
+	      error('unknown objsize');
+	   end
+	   
+	elseif isnumeric(a) 
+		t=sort(size(a));
+		if t(1)>1
+			li=a;
+		elseif exist('b','var') & isdataset(b) & length(b.objsize)==2
+	   
+			% we have a label vector and a dataset defining its objsize
+			li=reshape( a, [b.objsize, size(a,2)] );
+		else
+			error('dataset defining image size is required');
+		end
+	end
+
+	if isdipinstalled
+	   li=dip_image(li);
+	else
+	   prwarning(2,'DIPimage not installed, returning matrix');
+	end
+	
+	return
+	
Index: /hypertools/hypertools/gldbm.m
===================================================================
--- /hypertools/hypertools/gldbm.m	(revision 3)
+++ /hypertools/hypertools/gldbm.m	(revision 3)
@@ -0,0 +1,199 @@
+%GLDBM Generalised Local Discriminant Bases GLDB (bottom-up, Fisher crit)
+% 
+%  W = GLDBM(A)
+% 
+% INPUT  
+%  A    Training dataset
+%
+% OUTPUT
+%  W    best bases mapping
+%
+% DESCRIPTION 
+% Generalised Best Bases mapping is a feature extraction
+% technique for spectral datasets with two classes. Groups of adjacent
+% features (wavelengths) are identified in the input dataset such that
+% criterion combining Fisher separability and inter-band correlation is
+% maximized in each group. Output dataset is created by
+% projecting wavelengths in each group to the 1D Fisher subspace.  The
+% procedure is defined for two class problems, if a multi-class dataset is
+% supplied, a cell array of mappings will be computed.  A multi-class
+% classifier, based on this routine, is implemented as PREXP algorithm
+% ALG_GLDBM
+%
+% REFERENCE 
+% Kumar,Ghosh,Crawford: Best-Bases Feature Extraction Algorithms for
+% Classification of Hyperspectral Data, IEEE Trans.on Geoscience and
+% Remote Sensing, bol.39, no.7, July 2001
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, ALG_GLDBM
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: gldbm.m,v 1.10 2005/02/10 15:24:07 pavel Exp $
+
+function [w,crit] = gldbm(a,arg2)
+
+	% No arguments given: return untrained mapping.
+
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename);
+		w = setname(w,'Best Bases mapping');
+		return
+	end
+
+	if (~exist('arg2','var'))     % Second argument is not a mapping: training.
+
+		isdataset(a);           % Assert that A is a dataset.
+
+		[m,k,c] = getsize(a); M = classsizes(a);
+		
+		if c>2
+			% for multi-class problem, create all pair-wise extractors
+			w={};
+			iter=[];
+			for i=1:c-1
+				for j=i+1:c
+					fprintf(1,'(%d-%d',i,j);
+					t=seldat(a,[i j]);
+					eval(['w{i,j}=' mfilename '(t);']);
+					fprintf(1,') ');
+				end
+			end
+			return
+		end
+
+		% counter with ten steps
+		t=floor(k/10); % usually, only 80% bands is processed
+		counts=t*ones(1,10);
+		counts(1:mod(m,10))=counts(1:mod(m,10))+1;
+		counts=cumsum(counts);
+		
+		Q=corrcoef(+a);
+		[U,G]=meancov(a);
+
+		m=0;              % level
+		Nm=size(a,2);
+		l=1:size(a,2); % lower bounds of group-bands
+		u=1:size(a,2); % upper bounds of group-bands
+
+		% compute crit for each single band group:
+		I=crit_eval(l,u,Q,+U(1,:),+U(2,:),G(:,:,1),G(:,:,2));
+
+		while 1
+			% make possible merges:
+			pl=l(1:Nm-1);
+			pu=u(2:Nm);
+			
+			% eval criterium
+			crit=crit_eval(pl,pu,Q,+U(1,:),+U(2,:),G(:,:,1),G(:,:,2));
+			[maxval,ind]=max(crit);
+			while length(crit)>0
+				% if the merge candidate with the
+                                % highest crit.value yields smaller
+                                % criterium then maximum of the original
+                                % groups, choose 2nd best (3rd,... until
+                                % the end
+				if maxval<max(I([ind ind+1]))
+					crit(ind)=[];
+					[maxval,ind]=max(crit);
+				else
+					break
+				end
+			end
+			if length(crit)==0
+				% no merge candidate left, return what
+                                % we have at the moment.
+				[crit,clf]=crit_eval(l,u,Q,+U(1,:),+U(2,:),G(:,:,1),G(:,:,2));
+
+				% parameters
+				pars.clf=clf; pars.l=l; pars.u=u; pars.info_iter=m;
+				w = mapping(mfilename,'trained',pars,(1:length(l))',k,length(pars.l));
+				w = setname(w,'Best Bases mapping');
+				
+				return
+			end
+			
+			% update crit vector
+			I(ind)=maxval;
+			I(ind+1)=[];
+
+			u(ind)=u(ind+1);
+			u(ind+1)=[];
+			l(ind+1)=[];
+
+			m=m+1;
+			Nm=Nm-1;
+			try
+				if m==counts(1)
+					counts(1)=[];
+					fprintf('.');
+				end
+			catch
+				fprintf(1,'XX');
+% $$$ 				whos
+% $$$ 				m
+% $$$ 				counts
+% $$$ 				pause
+			end
+				
+
+			if Nm==1
+				% all the features were lumped together
+				[crit,clf]=crit_eval(l,u,Q,+U(1,:),+U(2,:),G(:,:,1),G(:,:,2));
+				% parameters
+				pars.clf=clf; pars.l=l; pars.u=u; pars.info_iter=m;
+				w = mapping(mfilename,'trained',pars,(1:length(l))',k,length(pars.l));
+				w = setname(w,'Best Bases mapping');
+				
+				return; 
+			end
+		end
+
+	else                      % Second argument is a a mapping: testing.
+
+		w = arg2;			
+		pars = getdata(w); % Unpack the mapping.
+		[m,k] = getsize(a); 
+
+		% create an output dataset
+		out=[];
+		for i=1:length(pars.clf)
+			% get the subset of bands...
+			t=+a(:,pars.l(i):pars.u(i));
+			% ... and project it to 1D Fisher subspace
+			out=[out t*pars.clf(i).w];
+		end
+	
+		w = setdat(a,out);
+		w=setfeatlab(w,(1:size(w,2))');
+	end
+
+return
+
+
+
+function [I,clf]=crit_eval(l,u,Q,mua,mub,sigmaa,sigmab)
+
+	I=zeros(1,length(l));
+
+	clf=[];
+	for i=1:length(l)
+		
+		C=min(min( Q( l(i):u(i), l(i):u(i) ) ));
+		
+		W=0.5*( sigmaa( l(i):u(i), l(i):u(i) )+sigmab( l(i):u(i), l(i):u(i) ) );
+		t=( mua( l(i):u(i) ) - mub( l(i):u(i) ) )';
+		B=t*t';
+		
+		w=pinv(W)*t;
+		D=(w'*B*w)/(w'*W*w);
+		
+		I(i)=C*D;
+		
+		clf(i).w=w;
+	end
+	
+	
Index: /hypertools/hypertools/gldbm_cat.m
===================================================================
--- /hypertools/hypertools/gldbm_cat.m	(revision 3)
+++ /hypertools/hypertools/gldbm_cat.m	(revision 3)
@@ -0,0 +1,32 @@
+% GLDBM_CAT Concatenate GDLB mappings
+%
+%   WOUT=GLDBM_CAT(WIN)
+%
+% DESCRIPTION
+% Concatenate a set of GLDB mappings given in a cell array.
+
+function wout=gldbm_cat(win)
+   
+   if ~iscell(win)
+      error('cell array with gldbm mappings expected');
+   end
+
+   tout.clf=[];
+   tout.l=[];
+   tout.u=[];
+   
+   for i=1:prod(size(win))
+      
+      t=win{i};
+      if ~isempty(t)
+	 t=+t; % get data
+	 tout.clf=[tout.clf t.clf];
+	 tout.l=[tout.l t.l];
+	 tout.u=[tout.u t.u];
+      end
+   end
+   s=struct(win{i});
+   wout=mapping('gldbm','trained',tout,...
+		s.labels,s.size_in,length(tout.l));
+   
+   return
Index: /hypertools/hypertools/gldbm_featsel.m
===================================================================
--- /hypertools/hypertools/gldbm_featsel.m	(revision 3)
+++ /hypertools/hypertools/gldbm_featsel.m	(revision 3)
@@ -0,0 +1,65 @@
+% GLDBM_FEATSEL Select bases in GLDB mapping using a feat.sel. mapping
+%
+%    W=GLDBM_FEATSEL(WGLDB,WFEATSEL)
+%
+% INPUT
+%    WGLDB     GLDB mapping
+%    WFEATSEL  feature selection mapping
+%
+% OUTPUT
+%    W         reduced GLDB mapping
+%
+
+function w=gldbm_featsel(wgldb,wfeatsel)
+
+   if iscell(wgldb) & iscell(wfeatsel)
+
+      % We address the cell array using a linear index.
+      % In the end, we reshape the cell array into the original
+      % dimensions. 2D arrays (pair-wise) are supported.
+      for i=1:prod(size(wgldb))
+	 eval(sprintf('w{i}=%s(wgldb{i},wfeatsel{i});',mfilename));
+      end
+      w=reshape(w,size(wgldb));
+% $$$       
+% $$$       % call this function recursively for each class pair
+% $$$       w={};
+% $$$       for i=1:size(wgldb,1)
+% $$$ 	 for j=i+1:size(wgldb,2)
+% $$$ 	    eval(sprintf('w{%d,%d}=%s(wgldb{i,j},wfeatsel{i,j});',...
+% $$$ 			 i,j,mfilename));
+% $$$ 	 end
+% $$$       end
+      return
+   end
+
+   % for nested calls: for empty inputs return empty cell
+   if isempty(wgldb) & isempty(wfeatsel)
+      w=[];
+      return
+   end
+   
+   if ~ismapping(wfeatsel) | isempty(findstr('Feature Selection',getname(wfeatsel)))
+      error('Trained feature selection mapping is required');
+   end
+
+   if iscell(+wfeatsel)
+       % using cmapm feature selection mapping
+       ind=wfeatsel{2};
+   elseif isnumeric(+wfeatsel)
+       % using featsel mapping
+       ind=+wfeatsel; % selected features (== GLDB bases)
+   else
+       error('unknown feature selection mapping')
+   end
+   
+   t=+wgldb;
+   tout.clf=t.clf(ind);
+   tout.l=t.l(ind);
+   tout.u=t.u(ind);
+   
+   s=struct(wgldb);
+   
+   w=mapping('gldbm','trained',tout,...
+	     s.labels,s.size_in,length(tout.l));
+   return
Index: /hypertools/hypertools/gldbm_mc_featsel.m
===================================================================
--- /hypertools/hypertools/gldbm_mc_featsel.m	(revision 3)
+++ /hypertools/hypertools/gldbm_mc_featsel.m	(revision 3)
@@ -0,0 +1,86 @@
+% GLDBM_MC_FEATSEL Apply the feature selection to a multi-class GLDB mapping
+%
+%   W=GLDBM_MC_FEATSEL(WGLDB,WFEATSEL)
+%
+% INPUT
+%    WGLDB     GLDB mapping
+%    WFEATSEL  feature selection mapping
+%
+% OUTPUT
+%    W         reduced GLDB mapping
+%
+% DESCRIPTION
+% Results of a multi-class GLDB criterion and a follow-up feature selection
+% are merged into a single GLDB mapping.
+
+function w=gldbm_mc_featsel(wgldb,wfeatsel)
+	
+	tw=+wgldb;
+	featind=+wfeatsel;
+	if ~isnumeric(featind)
+	    featind=featind{2}; % indices of selected features 
+	end
+	
+	% group indices: output features mapped to gldb groups
+	% 111233
+	% 3 features from group 1, 1 from 2, 2 from 3 etc.
+	groupc=size(tw.clf,2);
+	temp=zeros(1,groupc);
+	for i=1:groupc
+	    temp(i)=size(tw.clf(i).w,2); % output size of the group
+	end
+	fout=genlab(temp);
+
+        groups=zeros(1,groupc); % flag: is the info for this output group?
+	gdata=[];
+
+	for i=1:length(featind) 
+
+	    % extract the group
+	    g=fout(featind(i)); % the group of feature featind(i)
+
+	    W=tw.clf(g).w; % projection matrix
+	    
+	    % binary map of selected features inside fout
+	    binmap=zeros(1,length(fout));
+	    binmap(featind(i))=1; % mark the feature we're interested in
+	    gind=find(fout==g); % get the indices of the group's features
+	    temp=binmap(gind); % get the part of the binary map belonging
+                               % to the group we're dealing with
+	    ind=find(temp); % ind should be the index of our feature inside our group
+	    if isempty(ind), error(' feature not found in the group'); end
+
+	    % get only the column corresponding to the ind-th feature
+	    W=W(:,ind);
+	    
+	    if ~groups(g) % the group does not exist yet
+		gdata(g).clf=W;
+		gdata(g).l=tw.l(g);
+		gdata(g).u=tw.u(g);
+		groups(g)=1; % mark as existing
+	    else
+		gdata(g).clf=[gdata(g).clf W];
+		% the band boundaries do not change!
+	    end
+	end
+
+	% output gldb mapping
+	tout.clf=[];
+	tout.l=[];
+	tout.u=[];
+
+	outd=0; % output dimensionality
+	% construct output gldb structure
+        gind=find(groups); % existing groups
+        for i=1:sum(groups)
+	    tout.clf(i).w=gdata(gind(i)).clf; 
+	    outd=outd+size(gdata(gind(i)).clf,2);
+	    tout.l(i)=gdata(gind(i)).l;
+	    tout.u(i)=gdata(gind(i)).u;	   
+	end
+
+	s=struct(wgldb);
+	
+	w=mapping('gldbm','trained',tout,...
+		  s.labels,s.size_in,outd);
+	
Index: /hypertools/hypertools/gldbm_multi.m
===================================================================
--- /hypertools/hypertools/gldbm_multi.m	(revision 3)
+++ /hypertools/hypertools/gldbm_multi.m	(revision 3)
@@ -0,0 +1,192 @@
+%GLDBM_MULTI GLDB bottom-up, multi-class crit using Fisher separability
+% 
+%  W = GLDBM(A)
+% 
+% INPUT  
+%  A    Training dataset
+%
+% OUTPUT
+%  W    best bases mapping
+%
+% DESCRIPTION
+% Generalised Best Bases mapping is a feature extraction technique for
+% spectral datasets with two classes. Groups of adjacent features
+% (wavelengths) are identified in the input dataset such that Fisher
+% criterion is maximized in each group. Output dataset is created by
+% projecting wavelengths in each group to the 1D Fisher subspace.
+%
+% REFERENCE 
+% Kumar,Ghosh,Crawford: Classification of Hyperspectral Data using
+% Best-bases Feature Extraction Algorithm
+%
+% SEE ALSO
+% DATASETS, MAPPINGS
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: gldbm_multi.m,v 1.4 2005/02/10 15:24:07 pavel Exp $
+
+function w = gldbm_multi(a,arg2)
+
+	% No arguments given: return untrained mapping.
+		
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename);
+		w = setname(w,'Best Bases mapping');
+		return
+	end
+
+	if (~exist('arg2','var'))     % Second argument is not a mapping: training.
+
+		isdataset(a);           % Assert that A is a dataset.
+
+		[m,k,c] = getsize(a); M = classsizes(a);
+
+		% counter with ten steps
+		t=floor(m/10); 
+		counts=t*ones(1,10);
+		counts(1:mod(m,10))=counts(1:mod(m,10))+1;
+		counts=cumsum(counts);
+		
+		m=0;              % level
+		
+		if mod(size(a,2),2)==0
+			t=size(a,2);
+		else
+			t=size(a,2)-1;
+		end
+		l=1:2:t; % lower bounds of group-bands
+		u=2:2:t; % upper bounds of group-bands
+		u(end)=size(a,2); % asure that we use all bands
+		Nm=length(l);
+
+		% compute crit for each single band group:
+		I=crit_eval(l,u,a);
+
+		while 1
+			% make possible merges:
+			pl=l(1:Nm-1);
+			pu=u(2:Nm);
+			
+			% eval criterium
+			crit=crit_eval(pl,pu,a);
+			[maxval,ind]=max(crit);
+			while length(crit)>0
+				% if the merge candidate with the
+                                % highest crit.value yields smaller
+                                % criterium then maximum of the original
+                                % groups, choose 2nd best (3rd,... until
+                                % the end
+				if maxval<max(I([ind ind+1]))
+					crit(ind)=[];
+					[maxval,ind]=max(crit);
+				else
+					break
+				end
+			end
+			if length(crit)==0
+				% no merge candidate left, return what
+                                % we have at the moment.
+				[crit,clf]=crit_eval(l,u,a);
+
+				% parameters
+				pars.clf=clf; pars.l=l; pars.u=u; pars.info_iter=m;
+				
+				% get the output feature size from the clf
+				featcount=0; for i=1:length(pars.clf), featcount=featcount + size(pars.clf(i).w,2); end
+				w = mapping(mfilename,'trained',pars,getlablist(a),k,featcount);
+				w = setname(w,'Best Bases mapping');
+				
+				return
+			end
+			
+			% update crit vector
+			I(ind)=maxval;
+			I(ind+1)=[];
+
+			u(ind)=u(ind+1);
+			u(ind+1)=[];
+			l(ind+1)=[];
+			
+			m=m+1;
+			Nm=Nm-1;
+			fprintf('.');
+% $$$ 			if m==counts(1)
+% $$$ 				counts(1)=[];
+% $$$ 				fprintf('.');
+% $$$ 			end
+
+			if Nm==1
+				% all the features were lumped together
+				[crit,clf]=crit_eval(l,u,a);
+				% parameters
+				pars.clf=clf; pars.l=l; pars.u=u; pars.info_iter=m;
+				% get the output feature size from the clf
+				featcount=0; for i=1:length(pars.clf), featcount=featcount + size(pars.clf(i).w,2); end
+				w = mapping(mfilename,'trained',pars,getlablist(a),k,featcount);
+				w = setname(w,'Best Bases mapping');
+				return; 
+			end
+		end
+
+	else                      % Second argument is a a mapping: testing.
+
+		w = arg2;
+		pars = getdata(w);		 	% Unpack the mapping.
+		[m,k] = getsize(a); 
+
+		% create an output dataset
+		out=[];
+		for i=1:length(pars.clf)
+			% get the subset of bands...
+			t=+a(:,pars.l(i):pars.u(i));
+			% ... and project it to 1D Fisher subspace
+			out=[out t*pars.clf(i).w];
+		end
+	
+		w = setdat(a,out);
+	end
+
+return
+
+
+function [I,clf]=crit_eval(l,u,data)
+
+	I=zeros(1,length(l));
+
+	prior=getprior(data);
+	clf=[];
+	[m,k,c]=getsize(data);
+	for k=1:length(l)
+
+		Q=corrcoef(+data(:,l(k):u(k)));
+		% correlation
+		C=min(min( Q ));
+		
+		% turn within-class scatter into identity matrix
+		w = klms(data(:,l(k):u(k)));
+		b = data(:,l(k):u(k))*w;
+		U = +meancov(b);
+		d = ones(size(U,1));
+		
+		% Compute the weights E to be used in the modified between-scatter matrix G
+		% E should diminish the influence of large distances D.
+		e = ones(size(U,1));%0.5*erf(sqrt(d)/(2*sqrt(2))); 
+		B = zeros(size(b,2));
+		for j = 1:c
+			for i=j+1:c
+				% Marco-Loog Mapping
+				B = B + prior(i)*prior(j)*e(i,j)*(U(j,:)-U(i,:))'*(U(j,:)-U(i,:))/d(i,j); 
+				B = (B + B')/2;		% Avoid a numerical inaccuracy: cov. matrix should be symmetric!
+			end
+		end
+		
+		% criterion for the k-th feature group
+		[F,V] = eig(B);
+		[V,ind] = sort(-diag(V)); 
+		fc=min(size(b,2),c)-1; % maximal number of features
+		clf(k).w=F(:,ind(1:fc)); % projection matrix:
+		I(k)=C*sum(-V(1:fc)); % criterion is a sum of eigenvalues
+	end
Index: /hypertools/hypertools/gldbm_td.m
===================================================================
--- /hypertools/hypertools/gldbm_td.m	(revision 3)
+++ /hypertools/hypertools/gldbm_td.m	(revision 3)
@@ -0,0 +1,207 @@
+%GLDBM_TD GLDB using top-down criterion (Fisher separability)
+% 
+%  W = GLDBM_TD(A)
+% 
+% INPUT  
+%  A    Training dataset
+%
+% OUTPUT
+%  W    best bases mapping
+%
+% DESCRIPTION 
+% Generalised Best Bases mapping is a feature extraction technique for
+% spectral datasets with two classes.  This function implements the
+% top-down approach starting from a single group with all the wavelengths,
+% recursively identifying the best possible split points.  Groups of
+% adjacent features (wavelengths) are identified in the input dataset such
+% that Fisher criterion is maximized in each group. Output dataset is
+% created by projecting wavelengths in each group to the 1D Fisher
+% subspace.  The procedure is defined for two class problems, if a
+% multi-class dataset is supplied, a cell array of mappings will be
+% computed.  Multi-class classifier, based on this routine, is implemented
+% as PREXP algorithm ALG_GLDBM
+%
+% REFERENCE 
+% Kumar,Ghosh,Crawford: Classification of Hyperspectral Data using
+% Best-bases Feature Extraction Algorithm
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, GLDBM
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: gldbm_td.m,v 1.5 2005/02/10 15:24:07 pavel Exp $
+
+function [w,crit] = gldbm_td(a,arg2)
+
+	% No arguments given: return untrained mapping.
+
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename);
+		w = setname(w,'Best Bases mapping (top-down)');
+		return
+	end
+
+	if (~exist('arg2','var'))     % Second argument is not a mapping: training.
+
+		isdataset(a);           % Assert that A is a dataset.
+
+		[m,k,c] = getsize(a); M = classsizes(a);
+		
+		if c>2
+			% for multi-class problem, create all pair-wise extractors
+			w={};
+			iter=[];
+			for i=1:c-1
+				for j=i+1:c
+					fprintf(1,'(%d-%d',i,j);
+					t=seldat(a,[i j]);
+					eval(['w{i,j}=' mfilename '(t);']);
+					fprintf(1,') ');
+				end
+			end
+			return
+		end
+
+		% counter with ten steps
+		t=floor(k/10); % usually, only 80% bands is processed
+		counts=t*ones(1,10);
+		counts(1:mod(m,10))=counts(1:mod(m,10))+1;
+		counts=cumsum(counts);
+		
+		Q=corrcoef(+a);
+		[U,G]=meancov(a);
+
+		m=0;              % level
+		Nm=size(a,2);
+		
+		% in top-down approach, each group of bands is defined by its limits (l,u),
+		% flag saying if it should be processed further and a criterion value:
+		
+		l=1;  % lower bounds of group-bands
+		u=Nm; % upper bounds of group-bands
+		process=1; % should the group be processed?
+		I=0;    % criterion values for each group
+
+		% compute crit for each single band group:
+%		I=crit_eval(l,u,Q,+U(1,:),+U(2,:),G(:,:,1),G(:,:,2));
+
+		while 1
+		    
+		    % we'll go over all the groups and process the processable ones:
+		    temp=find(process==1);
+		    gid=temp(1); % the 1st group in queue to be processed
+%		    fprintf(1,' l=%d,u=%d ',l(gid),u(gid));
+		    
+		    % make possible merges:
+		    % pl and pu refer to the possible left subgroup!
+		    gc=u(gid)-l(gid)+1; % number of possible left subgroups
+		    pl=repmat( l(gid), 1, gc-1 ); % possible beginnings of the left new subgroup
+		    pu=pl(1):u(gid)-1;
+
+		    % eval criterium for left subgroups:
+		    crit1=crit_eval(pl,pu,Q,+U(1,:),+U(2,:),G(:,:,1),G(:,:,2));
+		    
+		    % eval criterion for right subgroups:
+		    crit2=crit_eval(pu+1,repmat(u(gid),1,gc-1),Q,+U(1,:),+U(2,:),G(:,:,1),G(:,:,2));		    
+		    
+		    maxval=max([crit1; crit2]);
+		    [maxval,ind]=max(maxval);
+
+		    newcrit=[crit1(ind) crit2(ind)];
+		    
+		    % pu(ind) is the best possible splitting index
+
+		    % decide which of the two new subgroups should be processed further
+		    newprocess=[0 0]; % by default: don't process
+		    if crit1(ind)>I(gid) & ind>1
+			% decompose the left subgroup
+			newprocess(1)=1;
+		    end
+		    if crit2(ind)>I(gid) & gc-ind>1
+			% decompose the left subgroup
+			newprocess(2)=1;
+		    end
+
+		    % update high-level group definition:
+		    if gid==1
+			% we're splitting the firrst group
+			l=[ 1       pu(ind)+1 l(2:end)];
+			u=[ pu(ind) u(1)      u(2:end)];
+			process=[newprocess process(2:end)];
+			I=[newcrit I(2:end)];
+		    elseif gid==Nm
+			% we're splitting the last group
+			l=[ l(1:end-1) l(gid) pu(ind)+1];
+			u=[ u(1:end-1) pu(ind) Nm];
+			process=[process(1:end-1) newprocess];
+			I=[I(1:end-1) newcrit];
+		    else
+			% we're in the middle
+			l=[ l(1:gid-1) l(gid) pu(ind)+1 l(gid+1:end)];
+			u=[ u(1:gid-1) pu(ind) u(gid)   u(gid+1:end)];
+			process=[process(1:gid-1) newprocess process(gid+1:end)];
+			I=[I(1:gid-1) newcrit I(gid+1:end)];			
+		    end
+		    fprintf(1,'(%d) ', sum(process));
+		    
+		    if isempty(find(process==1))
+			% no candidates for progress left, return what
+			% we have at the moment.
+			[crit,clf]=crit_eval(l,u,Q,+U(1,:),+U(2,:),G(:,:,1),G(:,:,2));
+
+			% parameters
+			pars.clf=clf; pars.l=l; pars.u=u; pars.info_iter=m;
+			w = mapping(mfilename,'trained',pars,(1:length(l))',k,length(pars.l));
+			w = setname(w,'Best Bases mapping (top-down)');
+			
+			return
+		    end
+		end % while
+	else % Second argument is a a mapping: testing.
+
+		w = arg2;			
+		pars = getdata(w); % Unpack the mapping.
+		[m,k] = getsize(a); 
+
+		% create an output dataset
+		out=[];
+		for i=1:length(pars.clf)
+			% get the subset of bands...
+			t=+a(:,pars.l(i):pars.u(i));
+			% ... and project it to 1D Fisher subspace
+			out=[out t*pars.clf(i).w];
+		end
+	
+		w = setdat(a,out);
+		w=setfeatlab(w,(1:size(w,2))');
+	end
+
+return
+
+
+
+function [I,clf]=crit_eval(l,u,Q,mua,mub,sigmaa,sigmab)
+
+	I=zeros(1,length(l));
+
+	clf=[];
+	for i=1:length(l)
+		
+		C=min(min( Q( l(i):u(i), l(i):u(i) ) ));
+		
+		W=0.5*( sigmaa( l(i):u(i), l(i):u(i) )+sigmab( l(i):u(i), l(i):u(i) ) );
+		t=( mua( l(i):u(i) ) - mub( l(i):u(i) ) )';
+		B=t*t';
+		
+		w=pinv(W)*t;
+		D=(w'*B*w)/(w'*W*w);
+		
+		I(i)=C*D;
+		
+		clf(i).w=w;
+	end
+	
+	
Index: /hypertools/hypertools/gldbm_td_ae.m
===================================================================
--- /hypertools/hypertools/gldbm_td_ae.m	(revision 3)
+++ /hypertools/hypertools/gldbm_td_ae.m	(revision 3)
@@ -0,0 +1,245 @@
+%GLDBM_TD GLDB using top-down criterion (apparent error)
+% 
+%  W = GLDBM_TD(A)
+% 
+% INPUT  
+%  A    Training dataset
+%
+% OUTPUT
+%  W    best bases mapping
+%
+% DESCRIPTION 
+% Generalised Best Bases mapping is a feature extraction technique for
+% spectral datasets with two classes.  This function implements the
+% top-down approach starting from a single group with all the wavelengths,
+% recursively identifying the best possible split points.  Groups of
+% adjacent features (wavelengths) are identified in the input dataset such
+% that Fisher criterion is maximized in each group. Output dataset is
+% created by projecting wavelengths in each group to the 1D Fisher
+% subspace.  The procedure is defined for two class problems, if a
+% multi-class dataset is supplied, a cell array of mappings will be
+% computed.  Multi-class classifier, based on this routine, is implemented
+% as PREXP algorithm ALG_GLDBM
+%
+% REFERENCE 
+% Kumar,Ghosh,Crawford: Classification of Hyperspectral Data using
+% Best-bases Feature Extraction Algorithm
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, GLDBM
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: gldbm_td_ae.m,v 1.2 2005/02/10 15:24:07 pavel Exp $
+
+function [w,crit] = gldbm_td_ae(a,arg2)
+
+	% No arguments given: return untrained mapping.
+
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename);
+		w = setname(w,'Best Bases mapping (top-down,bootstrapped ae)');
+		return
+	end
+
+	if (~exist('arg2','var'))     % Second argument is not a mapping: training.
+
+		isdataset(a);           % Assert that A is a dataset.
+
+		[m,k,c] = getsize(a); M = classsizes(a);
+		
+		if c>2
+			% for multi-class problem, create all pair-wise extractors
+			w={};
+			iter=[];
+			for i=1:c-1
+				for j=i+1:c
+					fprintf(1,'(%d-%d',i,j);
+					t=seldat(a,[i j]);
+					eval(['w{i,j}=' mfilename '(t);']);
+					fprintf(1,') ');
+				end
+			end
+			return
+		end
+
+		% counter with ten steps
+		t=floor(k/10); % usually, only 80% bands is processed
+		counts=t*ones(1,10);
+		counts(1:mod(m,10))=counts(1:mod(m,10))+1;
+		counts=cumsum(counts);
+		
+		Q=corrcoef(+a);
+		[U,G]=meancov(a);
+
+		m=0;              % level
+		Nm=size(a,2);
+		
+		% in top-down approach, each group of bands is defined by its limits (l,u),
+		% flag saying if it should be processed further and a criterion value:
+
+		bi=[];  % band info structure
+		
+		bi.l=1;  % lower bounds of group-bands
+		bi.u=Nm; % upper bounds of group-bands
+		bi.process=1; % should the group be processed?
+		bi.crit=0;    % criterion values for each group
+
+		% compute crit for each single band group:
+%		bi.crit=crit_eval(l,u,a,bi);
+		
+		while 1
+		    
+		    % we'll go over all the groups and process the processable ones:
+		    temp=find(bi.process==1);
+		    gid=temp(1); % the 1st group in queue to be processed
+%		    fprintf(1,' l=%d,u=%d ',l(gid),u(gid));
+		    
+		    % make possible merges:
+		    % pl and pu refer to the possible left subgroup!
+		    gc=bi.u(gid)-bi.l(gid)+1; % number of possible left subgroups
+		    pl=repmat( bi.l(gid), 1, gc-1 ); % possible beginnings of the left new subgroup
+		    pu=pl(1):bi.u(gid)-1;
+
+		    % eval criterium for left subgroups:
+		    crit1=crit_eval(pl,pu,a,bi);
+		    
+		    % eval criterion for right subgroups:
+		    crit2=crit_eval(pu+1,repmat(bi.u(gid),1,gc-1),a,bi);
+		    
+		    maxval=max([crit1; crit2]);
+		    [maxval,ind]=max(maxval);
+
+		    newcrit=[crit1(ind) crit2(ind)];
+		    
+		    % pu(ind) is the best possible splitting index
+
+		    % decide which of the two new subgroups should be processed further
+		    newprocess=[0 0]; % by default: don't process
+		    if crit1(ind)>bi.crit(gid) & ind>1
+			% decompose the left subgroup
+			newprocess(1)=1;
+		    end
+		    if crit2(ind)>bi.crit(gid) & gc-ind>1
+			% decompose the left subgroup
+			newprocess(2)=1;
+		    end
+
+		    % update high-level group definition:
+		    if gid==1
+			% we're splitting the firrst group
+			bi.l=[ 1       pu(ind)+1 bi.l(2:end)];
+			bi.u=[ pu(ind) bi.u(1)      bi.u(2:end)];
+			bi.process=[newprocess bi.process(2:end)];
+			bi.crit=[newcrit bi.crit(2:end)];
+		    elseif gid==Nm
+			% we're splitting the last group
+			bi.l=[ bi.l(1:end-1) bi.l(gid) pu(ind)+1];
+			bi.u=[ bi.u(1:end-1) pu(ind) Nm];
+			bi.process=[bi.process(1:end-1) newprocess];
+			bi.crit=[bi.crit(1:end-1) newcrit];
+		    else
+			% we're in the middle
+			bi.l=[ bi.l(1:gid-1) bi.l(gid) pu(ind)+1 bi.l(gid+1:end)];
+			bi.u=[ bi.u(1:gid-1) pu(ind) bi.u(gid)   bi.u(gid+1:end)];
+			bi.process=[bi.process(1:gid-1) newprocess bi.process(gid+1:end)];
+			bi.crit=[bi.crit(1:gid-1) newcrit bi.crit(gid+1:end)];			
+		    end
+		    fprintf(1,'(%d) ', sum(bi.process));
+
+		    % history:
+%			pars.l=bi.l; pars.u=bi.u; pars.info_iter=m;
+%			w = mapping(mfilename,'trained',pars,getlablist(a),k,length(pars.l));
+%			w = setname(w,'Best Bases mapping (top-down,bootstrapped ae)');
+%		    history{end+1}=w
+		    
+		    
+		    if isempty(find(bi.process==1))
+			% no candidates for progress left, return what
+			% we have at the moment.
+			%crit=crit_eval(bi.l,bi.u,a,bi);
+
+			% parameters
+			%pars.clf=clf; % (features == means are made on the spot)
+			crit=bi.crit;
+			pars.l=bi.l; pars.u=bi.u; pars.info_iter=m;
+			w = mapping(mfilename,'trained',pars,getlablist(a),k,length(pars.l));
+			w = setname(w,'Best Bases mapping (top-down,bootstrapped ae)');
+			
+			return
+		    end
+		end % while
+	else % Second argument is a a mapping: testing.
+
+		w = arg2;			
+		pars = getdata(w); % Unpack the mapping.
+		[m,k] = getsize(a); 
+
+		% create an output dataset
+		out=[];
+		for i=1:length(pars.l)
+			% get the mean of a subset of bands...
+			t=mean(+a(:,pars.l(i):pars.u(i)),2);
+			out=[out t];
+		end
+	
+		w = setdat(a,out);
+		w=setfeatlab(w,(1:size(w,2))');
+	end
+
+return
+
+function crit=crit_eval(l,u,a,bi)
+
+    bt=5; % how many times to bootstrap
+    err=zeros(1,bt); % bootstrapped errors
+	
+    crit=zeros(1,length(l));
+
+    clf=[];
+    for i=1:length(l)
+	
+	b=a(:,l(i):u(i));
+	b=setdat(b,mean(+b,2)); % merge wavelengths somputing mean
+
+	for j=1:bt
+	    
+	    c=bootstrap(b,size(b,1),10+j);
+	    
+	    w=ldc(c); % estimate Gaussian parameters
+	
+	    err(j)=b*w*testc; % error on the original training set
+	
+	end
+	
+	fprintf(1,'.');
+	% log-odds criterion
+	crit(i)=mean(err);
+	
+    end
+    
+    
+    return
+
+
+% BOOTSTRAP - bootstrap the data
+%
+%     [d,ind]=bootstrap(a,n,seed)
+%
+% in : a - original dataset
+%      n - number of output samples to generate
+%      seed - random seed (opt)
+% out: d - output dataset with bootstraped samples
+%      ind - indices of original samples, stored in the output dataset
+
+function [d,ind]=bootstrap(a,n,seed)
+
+if ~exist('seed','var'), seed=42; end
+prlseed(seed)
+
+ind=floor(1+rand(1,n)*size(a,1));
+d=a(ind,:);
+
+return
Index: /hypertools/hypertools/gldbm_td_prob.m
===================================================================
--- /hypertools/hypertools/gldbm_td_prob.m	(revision 3)
+++ /hypertools/hypertools/gldbm_td_prob.m	(revision 3)
@@ -0,0 +1,223 @@
+% experimental: GLDB using top-down criterion (Log-odds)
+
+%GLDBM_TD Generalised Best Bases (top-down) mapping for spectra
+% 
+%  W = GLDBM_TD(A)
+% 
+% INPUT  
+%  A    Training dataset
+%
+% OUTPUT
+%  W    best bases mapping
+%
+% DESCRIPTION 
+% Generalised Best Bases mapping is a feature extraction technique for
+% spectral datasets with two classes.  This function implements the
+% top-down approach starting from a single group with all the wavelengths,
+% recursively identifying the best possible split points.  Groups of
+% adjacent features (wavelengths) are identified in the input dataset such
+% that Fisher criterion is maximized in each group. Output dataset is
+% created by projecting wavelengths in each group to the 1D Fisher
+% subspace.  The procedure is defined for two class problems, if a
+% multi-class dataset is supplied, a cell array of mappings will be
+% computed.  Multi-class classifier, based on this routine, is implemented
+% as PREXP algorithm ALG_GLDBM
+%
+% REFERENCE 
+% Kumar,Ghosh,Crawford: Classification of Hyperspectral Data using
+% Best-bases Feature Extraction Algorithm
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, GLDBM
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: gldbm_td_prob.m,v 1.4 2005/02/10 15:24:07 pavel Exp $
+
+function [w,crit,history] = gldbm_td_prob(a,arg2)
+
+	% No arguments given: return untrained mapping.
+
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename);
+		w = setname(w,'Best Bases mapping (top-down,log-odds)');
+		return
+	end
+
+	if (~exist('arg2','var'))     % Second argument is not a mapping: training.
+
+		isdataset(a);           % Assert that A is a dataset.
+
+		[m,k,c] = getsize(a); M = classsizes(a);
+		
+		if c>2
+			% for multi-class problem, create all pair-wise extractors
+			w={};
+			iter=[];
+			for i=1:c-1
+				for j=i+1:c
+					fprintf(1,'(%d-%d',i,j);
+					t=seldat(a,[i j]);
+					eval(['w{i,j}=' mfilename '(t);']);
+					fprintf(1,') ');
+				end
+			end
+			return
+		end
+
+		% counter with ten steps
+		t=floor(k/10); % usually, only 80% bands is processed
+		counts=t*ones(1,10);
+		counts(1:mod(m,10))=counts(1:mod(m,10))+1;
+		counts=cumsum(counts);
+		
+		Q=corrcoef(+a);
+		[U,G]=meancov(a);
+
+		m=0;              % level
+		Nm=size(a,2);
+		
+		% in top-down approach, each group of bands is defined by its limits (l,u),
+		% flag saying if it should be processed further and a criterion value:
+
+		bi=[];  % band info structure
+		
+		bi.l=1;  % lower bounds of group-bands
+		bi.u=Nm; % upper bounds of group-bands
+		bi.process=1; % should the group be processed?
+		bi.crit=0;    % criterion values for each group
+
+%		history={};
+		
+		% compute crit for each single band group:
+%		bi.crit=crit_eval(l,u,a,bi);
+		
+		while 1
+		    
+		    % we'll go over all the groups and process the processable ones:
+		    temp=find(bi.process==1);
+		    gid=temp(1); % the 1st group in queue to be processed
+%		    fprintf(1,' l=%d,u=%d ',l(gid),u(gid));
+		    
+		    % make possible merges:
+		    % pl and pu refer to the possible left subgroup!
+		    gc=bi.u(gid)-bi.l(gid)+1; % number of possible left subgroups
+		    pl=repmat( bi.l(gid), 1, gc-1 ); % possible beginnings of the left new subgroup
+		    pu=pl(1):bi.u(gid)-1;
+
+		    % eval criterium for left subgroups:
+		    crit1=crit_eval(pl,pu,a,bi);
+		    
+		    % eval criterion for right subgroups:
+		    crit2=crit_eval(pu+1,repmat(bi.u(gid),1,gc-1),a,bi);
+		    
+		    maxval=max([crit1; crit2]);
+		    [maxval,ind]=max(maxval);
+
+		    newcrit=[crit1(ind) crit2(ind)];
+		    
+		    % pu(ind) is the best possible splitting index
+
+		    % decide which of the two new subgroups should be processed further
+		    newprocess=[0 0]; % by default: don't process
+		    if crit1(ind)>bi.crit(gid) & ind>1
+			% decompose the left subgroup
+			newprocess(1)=1;
+		    end
+		    if crit2(ind)>bi.crit(gid) & gc-ind>1
+			% decompose the left subgroup
+			newprocess(2)=1;
+		    end
+
+		    % update high-level group definition:
+		    if gid==1
+			% we're splitting the firrst group
+			bi.l=[ 1       pu(ind)+1 bi.l(2:end)];
+			bi.u=[ pu(ind) bi.u(1)      bi.u(2:end)];
+			bi.process=[newprocess bi.process(2:end)];
+			bi.crit=[newcrit bi.crit(2:end)];
+		    elseif gid==Nm
+			% we're splitting the last group
+			bi.l=[ bi.l(1:end-1) bi.l(gid) pu(ind)+1];
+			bi.u=[ bi.u(1:end-1) pu(ind) Nm];
+			bi.process=[bi.process(1:end-1) newprocess];
+			bi.crit=[bi.crit(1:end-1) newcrit];
+		    else
+			% we're in the middle
+			bi.l=[ bi.l(1:gid-1) bi.l(gid) pu(ind)+1 bi.l(gid+1:end)];
+			bi.u=[ bi.u(1:gid-1) pu(ind) bi.u(gid)   bi.u(gid+1:end)];
+			bi.process=[bi.process(1:gid-1) newprocess bi.process(gid+1:end)];
+			bi.crit=[bi.crit(1:gid-1) newcrit bi.crit(gid+1:end)];			
+		    end
+		    fprintf(1,'(%d) ', sum(bi.process));
+% $$$ 
+% $$$ 		    % history:
+% $$$ 			pars.l=bi.l; pars.u=bi.u; pars.info_iter=m;
+% $$$ 			w = mapping(mfilename,'trained',pars,getlablist(a),k,length(pars.l));
+% $$$ 			w = setname(w,'Best Bases mapping (top-down,log-odds)');
+% $$$ 		    history{end+1}=w
+		    
+		    
+		    if isempty(find(bi.process==1))
+			% no candidates for progress left, return what
+			% we have at the moment.
+			%crit=crit_eval(bi.l,bi.u,a,bi);
+
+			% parameters
+			%pars.clf=clf; % (features == means are made on the spot)
+			crit=bi.crit;
+			pars.l=bi.l; pars.u=bi.u; pars.info_iter=m;
+			w = mapping(mfilename,'trained',pars,getlablist(a),k,length(pars.l));
+			w = setname(w,'Best Bases mapping (top-down,log-odds)');
+			
+			return
+		    end
+		end % while
+	else % Second argument is a a mapping: testing.
+
+		w = arg2;			
+		pars = getdata(w); % Unpack the mapping.
+		[m,k] = getsize(a); 
+
+		% create an output dataset
+		out=[];
+		for i=1:length(pars.l)
+			% get the mean of a subset of bands...
+			t=mean(+a(:,pars.l(i):pars.u(i)),2);
+			out=[out t];
+		end
+	
+		w = setdat(a,out);
+		w=setfeatlab(w,(1:size(w,2))');
+	end
+
+return
+
+function crit=crit_eval(l,u,a,bi)
+    
+	crit=zeros(1,length(l));
+
+	clf=[];
+	for i=1:length(l)
+	
+	    b=a(:,l(i):u(i));
+	    b=setdat(b,mean(+b,2)); % merge wavelengths somputing mean
+	    
+	    w=qdc(b); % estimate Gaussian parameters
+	    
+	    b=b*w; % get the probabilities
+	    
+	    b1=seldat(b,1); % class1
+	    b2=seldat(b,2); % class2
+	    
+	    % log-odds criterion
+	    crit(i)=sum(log((+b1(:,1))./((+b1(:,2))+eps)))/size(b1,1)+...
+		    sum(log((+b2(:,2))./((+b2(:,1))+eps)))/size(b2,1);
+	    
+	end
+    
+    
+    return
+
Index: /hypertools/hypertools/gldbm_visualize.m
===================================================================
--- /hypertools/hypertools/gldbm_visualize.m	(revision 3)
+++ /hypertools/hypertools/gldbm_visualize.m	(revision 3)
@@ -0,0 +1,54 @@
+function out=gldbm_visualize(win,type,bc)
+    
+    if ~exist('type','var'), type='weights'; end
+    
+    if ~iscell(win), win={win}; end
+    
+    t=+win{1};
+    t=t.u;
+    if ~exist('bc','var') % if max bc is given from outside
+	bc=t(end); % band count
+    end
+    
+    out=zeros(length(win),bc);
+    
+    switch type
+	case {'weights','w'}
+	 % for each mapping:
+	 for i=1:length(win)
+	     
+	     wgldb=win{i};
+	     s=+wgldb;
+	     featex=s.clf; % feature extraction mappings
+	     
+	     gc=length(s.l); % number of wavelength groups
+	     
+	     for j=1:gc
+		 weights=featex(j).w;
+		 out(i,s.l(j):s.u(j))=abs(weights');
+	     end
+	 end
+	
+     case {'bands'}
+      
+      % plot the bands, identified in several folds
+
+      % for each mapping:
+      for i=1:length(win)
+	  
+	  wgldb=win{i};
+	  s=+wgldb;
+	  
+	  gc=length(s.l); % number of wavelength groups
+
+	  flag=1;
+	  for j=1:gc
+	      val=((j/2)-round(j/2))==0;
+	      out(i,s.l(j):s.u(j))=val;
+	  end
+      end
+	
+      
+      
+    end
+    
Index: /hypertools/hypertools/isdipinstalled.m
===================================================================
--- /hypertools/hypertools/isdipinstalled.m	(revision 3)
+++ /hypertools/hypertools/isdipinstalled.m	(revision 3)
@@ -0,0 +1,18 @@
+% ISDIPINSTALLED Tests if DIPimage is installed
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: isdipinstalled.m,v 1.2 2003/10/29 15:06:05 serguei Exp $
+
+
+function t=isdipinstalled
+	
+	if exist('dip_image')
+		t=1;
+	else
+		t=0;
+	end
+	
+	return
Index: /hypertools/hypertools/license.txt
===================================================================
--- /hypertools/hypertools/license.txt	(revision 3)
+++ /hypertools/hypertools/license.txt	(revision 3)
@@ -0,0 +1,97 @@
+Open Software LICENSE 
+
+1. Background
+
+The Hypertools software as provided here under the terms and conditions of
+this LICENSE, has been developed within a research project DTF.5699 with
+the title: "The analysis of spatial structures in hyperspectral images" at
+Delft University of Technology, Delft, the Netherlands. Research project
+DTF.5699, has been financed by Technology Foundation STW. It is made
+available in this open source license to make further research in a broader
+public possible.
+
+2. Definitions:
+LICENSE:        This agreement 
+LICENSEE:       "You"   
+LICENSOR:       Technology Foundation STW, van Vollenhovelaan 661, 
+                Post Box 3021, 3502 GA Utrecht, The Netherlands, 
+                phone +31 (0)30 6001 211, fax +31 (0)30 6014 408, 
+                http://www.stw.nl  
+and
+                Delft University of Technology, Mekelweg 4, 
+                2600 GA Delft, The Netherlands, http://www.tudelft.nl 
+ORIGINAL SOFTWARE:    Original software means the Hypertools software as 
+                      first distributed 2. November 2005 by Licensor
+PURPOSE:        Research purposes (non commercial)
+
+
+3. License conditions:
+
+Licensor hereby grants You a world-wide, royalty-free, non-exclusive,
+perpetual license for research purposes which allows you to do the
+following: You can copy, modify the copies of the Original Software or its
+Derivatives worldwide, free of charge to prepare derivative works
+("Derivative Works") based upon the Original Work; to distribute copies of
+the Original Work and Derivative Works to the public, only after having
+informed the author of the Original Software by email
+(P.Paclik@ewi.tudelft.nl) of a modification, with the provision that copies
+of Original Work or Derivative Works that You distribute shall be licensed
+under the same terms and conditions of this open software license Any copy
+or Derivative Works shall show the following copyright notice : Copyright
+(C) 2005 Pavel Paclik and Serguei Verzakov.  You cannot use the software
+for commercial purposes. Any commercial use needs the prior written
+approval of Technology Foundation STW (for contact details see above)
+legally authorised to represent the Licensor in this matter.
+
+4.Publications 
+
+In case you wish to publish a scientific article wherein you
+mention the Original Software you must mention the author of this Original
+Software. In your publication you may refer to the following publications:
+
+P.Paclik, S.Verzakov, R.P.W.Duin, Hypertools 2.0: the toolbox for spectral
+image analysis, technical report, ICT Group, TU Delft, The Netherlands,
+November 2005
+
+
+5. Short Description
+With the Original Software a user manual is provided. This manual is a
+short description of the Original Software. It is in no way intended as
+complete user instruction.
+
+6. LIABILITY & WARRANTY
+
+BECAUSE THE ORIGINAL SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE ORIGINAL SOFTWARE OR THE USER MANUAL, TO THE EXTENT
+PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING.
+LICENSOR AND/OR THE COPYRIGHT HOLDERS PROVIDE THE SOFTWARE "AS IS" WITHOUT
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF
+THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME
+THE COSTS OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.  THE LICENSOR
+DOES NOT GUARANTEE AND CANNOT BE HOLD LIABLE THAT THE ORIGINAL SOFTWARE IS
+FREE OF RIGHTS (including but not limited to patent rights). THE USE OF
+THIS ORIGINAL SOFTWARE IS FOR YOUR ENTIRE RISK AND YOU CANNOT HOLD LIABLE
+THE LICENSOR NOR ANY COPYRIGHT HOLDER, NOR ANY OTHER PARTY WHO MAY HAVE
+MODIFIED AND/OR REDISTRIBUTED THE ORIGINAL SOFTWARE (DERIVATIVE WORKS) FOR
+ANY CLAIM WHATSOEVER OF THIRD PARTIES.
+
+IN NO EVENT , WILL LICENSOR, ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO
+MAY MODIFY AND/OR REDISTRIBUTE THE ORIGINAL SOFTWARE (DERIVATIVE WORKS) AS
+PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
+SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
+INABILITY TO USE THE ORIGINAL SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS
+OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
+THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+7. Acceptance by exercising any right
+By exercising any of the rights granted to You in this agreement, You
+indicate Your acceptance of this License and all of its terms and
+conditions. This License shall terminate immediately and you may no longer
+exercise any of the rights granted to You by this License upon Your failure
+to honour the terms and conditions of this Agreement.
+
+--------------------
Index: /hypertools/hypertools/liknonc.m
===================================================================
--- /hypertools/hypertools/liknonc.m	(revision 3)
+++ /hypertools/hypertools/liknonc.m	(revision 3)
@@ -0,0 +1,228 @@
+% LIKNONC Liknon feature extractor and classifier
+%
+%     W=LIKNONC(A,C)
+%
+% INPUT
+%   A   input dataset
+%   C   optional C constant (tradeoff between misclassification and
+%       sparseness), default C=1
+%
+% OUTPUT
+%   W   Liknon classifier mapping
+%
+% DESCRIPTION
+% Liknon is a feature extractor and classifier developed by Michael
+% I.Jordan. By optimizing L1 norm, a sparse solution and linear
+% classifier is obtained. For reference, look at:
+%
+% REFERENCE
+%   Bhattacharyya, C., Grate, L.R., Rizki, A., Radisky, D.C., Molina, F.J.,
+%   Jordan, M.I., Bissell, M.J. and Mian, I.S. "Simultaneous relevant
+%   feature identification and classification in high-dimensional spaces:
+%   application to molecular profiling data." Signal Processing (2002).
+%
+
+% $Id: liknonc.m,v 1.4 2005/02/10 15:24:07 pavel Exp $
+
+function w=liknonc(a,m)
+
+   if (nargin < 1) | (isempty(a)  & ~exist('m','var'))  
+      % Definition: an untrained mapping.
+      w = mapping(mfilename,{});
+      w = setname(w,'Liknon classifier');
+
+   elseif isempty(a) & isnumeric(m)
+       
+      w = mapping(mfilename,{m});
+      w = setname(w,'Liknon classifier');
+      
+   elseif ~exist('m','var') | ~ismapping(m)
+      
+       if exist('m','var') & isnumeric(m) & length(m)==1
+	   % we assume the parameter is a C constant
+	   C=m;
+       else
+	   C=1; % default
+       end
+      % Training: W will be the trained mapping.
+      [m,k,c] = getsize(a);
+
+      [n,lablist]=classsizes(a);
+      
+      % prepare +1 / -1 labels
+      y=[ones(n(1),1);-1*ones(n(2),1)];
+      
+      % run Michael I. Jordan's lpc
+      [w,b]=lpc(+a,y,C);
+      
+      % select only non-zero dimensions
+      ind=find(w~=0);
+      w=w(ind);
+      
+      w=mapping(mfilename,'trained',{ind,w,b},a.lablist,k,c);
+      
+   else 
+
+      % Execution of the mapping, W will be a dataset.
+      v = +m;
+      
+      ind=v{1}; % indices of features to be used
+      w=v{2}; % weight vector
+      b=v{3}; % bias
+
+      out=(+a(:,ind))*w+b;
+      
+      d=zeros(size(out,1),2);
+      ind=find(out>0);
+      d(ind,1)=out(ind);
+      ind=setdiff(1:size(out,1),ind);
+      d(ind,2)=-out(ind);
+      
+      % the best is minimum, we turn it by switching the sign:
+      w=dataset(d,getlab(a),'featlab',getlab(m));
+      
+      w=setdata(a,d);
+      w=setfeatlab(w,getlab(m));
+      
+   end
+   
+   return
+   
+% ----------------------------------------
+
+function [a, bias] = lpc(X,Y,C)
+%  Usage: [a, bias] = lpc(X,Y,C)
+%
+%  Parameters: X      - Training inputs
+%              Y      - Training signs
+%              C      - parameter
+% this is the heart of the LIKNON system.  The matrix X and vector
+% of labels Y are the input data.  This routine creates the linear
+% programming matrix, calls the linear solver to solve it, and then
+% maps the results back into the desired result vector a and scaler b.
+
+% the problem being solved is find a hyperplane ax + b such that
+% most of the vector a values are zero.  This is done by transforming
+% it into an approximation that can be solved by linear programming.
+% If we want the solution that has the fewest non-zero a components,
+% that is a NP hard problem: min the L0 (L zero) norm of a, which is the
+% count of non-zero components.  An approximation is to min the L1 norm,
+% which is the sum of the absolute values: min (sum abs(a[i])).  This
+% is what liknon solves.
+
+% Min:  sum (abs(a[i])) + C * sum(slack[j]);
+% subject to constraints:
+%   y[j] * (a'x[j] + b) >= 1 - slack[j]
+%   slack[j] >= 0.
+
+% x[j] is the j'th row of the matrix X, y[j] is the j'th value of the
+% experiment label (must be either +1 or -1).  There is one slack for
+% each row.  We want the vector a, scalar b and vector slack as
+% results.
+
+% linear programming requires the variables to have limited range,
+% such as the slack's all being not-negative.  This is a typical constraint.
+% Since the a components can be anything, we need to transform the problem.
+% The trick is splitting the a's and b into two parts, a "positive" and 
+% "negative" part.  Only one of which will be non-zero at the end.
+
+% so:
+% let a[i] = u[i] - v[i], and b = b+ - b-.
+% now the problem becomes:
+% Min: sum (u[i] + v[i]) + C * sum(slack[j])
+% subject to constraints:
+%   y[j] * ((u[i] - v[i])'x[j] + b+ - b-) >= 1 - slack[j]
+%   slack[j], u[i], v[i], b+, b- , >= 0.
+
+% This is the problem being solved.
+
+%This problem is published in a couple of papers:
+% Bhattacharyya, C., Grate, L.R., Rizki, A., Radisky, D.C., Molina, F.J., 
+% Jordan, M.I., Bissell, M.J. and Mian, I.S. "Simultaneous relevant feature
+% identification and classification in high-dimensional spaces: application
+% to molecular profiling data." Signal Processing (2002). 
+
+% Grate, L.R., Bhattacharyya, C., Jordan, M.I. and Mian, I.S. "Integrated
+% analysis of transcript profiling and protein sequence data." Mechanisms
+% of Ageing and Development (2002).
+
+% Grate, Bhattacharyya, Jordan, Mian. "simultaneous relevant feature
+% identification and classification in high-dimensional spaces".  WABI2002
+
+% 
+  if (nargin <3) % check correct number of arguments
+    help lpc 
+  else
+
+    [n, m]= size(X); % input data, n rows (examples), m cols (genes)
+
+    epsilon = 1e-12; % values smaller will round to zero.
+    I = eye(n); 
+    % Construct the  matrix
+%fprintf('Constructing %d %d\n',n,m);
+    % Build the problem matrix. 
+    H = zeros(n, 2*m +n+2);  
+    for i = 1:n
+        % build array for the constraints, see above equation.
+        % fill array.  a is split into two parts, u,v.
+        %               u       v        slacks     b+  b-
+      H(i,:) = Y(i)*[ X(i,:), -X(i,:), Y(i)*I(i,:), 1, -1];  
+    end
+    rhs = ones(n,1);    %constraints right-hand-side, all 1's (since slacks moved over to left side.)
+    f = ones(2*m,1);               % 1, multiply u, v
+    f(2*m+1:2*m+n) = C*ones(n,1);  % C * slacks
+    f(2*m+n+1) = 0;                % b+, b- are not part of the min equation.
+    f(2*m+n+2) = 0; 
+
+     vlb = zeros(2*m+n+2,1);      % lower bounds array: all >= 0
+
+%fprintf('starting %s\n',datestr(now));
+%st = cputime;
+
+    % The linprog matlab call solves min f'x, subject to Hx <= rhs
+    % since multiply by -1, subject to -Hx >= -rhs
+
+    defaults = linprog('defaults');   
+    defaults=optimset(defaults,'Display','none');
+    [x,fval,exitflag,output,lambda] = linprog(f, -H, -rhs,[],[], vlb,[],[],defaults);
+    
+%fprintf('Execution time: %4.1f seconds\n',cputime - st);
+    
+   u = x(1:m);      % u are the "positive" halves of a
+   v = x(m+1:2*m);  % v are the "negative" halves of a
+   xi = x(2*m + n); % the "slacks" 
+   bias = x(2*m + n + 1)-x(2*m+n+2);
+   a = u - v;       % build a from the u, v vectors.
+ %The problem is now solved.  But due to finite machine precision, there
+ %exists noise in the solutions.  Smash all "too small to care" values
+ %to zero.
+   for i =1 :m
+     if(abs(a(i)) < epsilon)
+        a(i) = 0;
+     end
+   end
+end    
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Copyright (c) 1997-2002 The Regents of the University of California.
+% All rights reserved.
+% Permission is hereby granted, without written agreement and without
+% license or royalty fees, to use, copy, modify, and distribute this
+% software and its documentation for any purpose, provided that the above
+% copyright notice and the following two paragraphs appear in all copies
+% of this software.
+%
+% IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+% FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+% ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+% THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
+% SUCH DAMAGE.
+%
+% THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
+% PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
+% CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+% ENHANCEMENTS, OR MODIFICATIONS.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Index: /hypertools/hypertools/maf.m
===================================================================
--- /hypertools/hypertools/maf.m	(revision 3)
+++ /hypertools/hypertools/maf.m	(revision 3)
@@ -0,0 +1,158 @@
+%MAF Maximum autocorrelation mapping
+% 
+% 	[W,ALF] = MAF(A,N)
+% 	[W,N] = MAF(A,ALF)
+%
+% INPUT
+%    A    dataset
+%    N    number of returned components
+%    ALF  counterpart of fraction of preserved variance in PCA
+%
+% OUTPUT
+%    W    traned MAF mapping
+%
+% DESCRIPTION
+% This is a special purpose version of PCA for images stored as features
+% in the dataset. The covariance matrix is slightly modified such that
+% the covariances are computed for the one-pixel shifted images.
+% Futher, transormed data are constraind to be univariated.
+% As a result the transormation maximizes image autocorrelation.
+
+% This code comes from prtools 3.1.6:
+% 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
+
+% $Id: maf.m,v 1.7 2007/01/26 10:16:46 serguei Exp $
+
+function [w,q,acov] = maf(a,alf)
+
+	if nargin < 2 | isempty(alf), alf = inf; end
+	if nargin < 1 | isempty(a)
+		w = mapping('maf',alf); return
+	end
+
+	isdataset(a);
+	isfeatim(a);
+	
+	[m,k,c]=getsize(a);
+	
+	u = [];
+  % The reduction of dimensionality
+  % is not really neccessary: it makes data smaller but for the cost 
+  % of extra svd on all data, cov matrix computation and eig on it. 
+  % If we have enough memory, it is faster to compute acov on all the data and then do eig.
+  %if m <= k
+	%	u = reducm(a);
+	%	a = a*u;
+	%	korg = k;
+	%	[m,k] = size(a);
+  % end
+
+  G = imcov(data2im(a));
+
+	[F V] = eig(G);
+	[v,I] = sort(-diag(V));
+	if alf == inf
+		n = ni;
+		q = ni;
+	elseif alf >= 1
+		n = alf;
+		if n > k
+			error('Illegal dimensionality requested');
+		end
+		q = sum(v(1:n))/sum(v);
+		I = I(1:n);
+	elseif alf > 0
+		vv = v'*triu(ones(k,k)) / sum(v) - alf;
+		J = find(vv > 0);
+		n = J(1); q = n;
+		I = I(1:n);
+	elseif alf == 0
+		w = ones(1,k);
+		ww = v'*triu(ones(k,k)) / sum(v);
+		w(1:length(ww)) = ww;
+		return
+	elseif alf > -1
+		alf = abs(alf);
+		v = flipud(v); I = flipud(I);
+		vv = v'*triu(ones(k,k)) / sum(v) - alf;
+		J = find(vv > 0);
+		n = J(1)-1; q = n;
+		I = I(1:n);
+	else
+		n = abs(alf);
+		v = flipud(v); I = flipud(I);
+		if n > k
+			error('Illegal dimensionality requested');
+		end
+		q = sum(v(1:n));
+		sv = sum(v);
+		if sv ~= 0, q = q/sv; end
+		I = I(1:n);
+	end
+	
+  acov = abs(v);
+  
+  F = F(:,I);
+  
+  if ~isempty(u)
+	  offset = u.data.offset*F;  
+    F = u.data.rot*F; 
+  else
+    offset = -mean(a*F);        
+  end
+  
+  w = affine(F,offset);
+
+  return
+
+%IMCOV Image covariance
+%
+%	c = imcov(a)
+
+function c = imcov(a)
+	[m,n,k] = size(a);
+	g = mean(reshape(a,m*n,k));
+	J = bord(reshape(1:m*n,m,n),NaN);
+  
+  %c = zeros(k,k);
+  %for i=1:k
+	%  a1 = a(:,:,i) - g(i);
+	%	 for j=i:k
+	%	   a2 = a(:,:,j) - g(j);
+	%		 cc = mean(mean(a1.*a2(J(1:m,2:n+1)) + a1.*a2(J(3:m+2,2:n+1))));
+	%		 cc = cc + mean(mean(a1.*a2(J(2:m+1,1:n)) + a1.*a2(J(2:m+1,3:n+2))));
+	%		 cc = cc/4;
+	%		 c(i,j) = cc; c(j,i) = cc;
+  %  end
+  %end
+
+  % if we have enough memory we can do vectorization
+  a = permute(a,[3, 1, 2])-repmat(g',[1 m n]);
+  c = a(:,:)*(a(:,J(1:m,2:n+1))' + a(:,J(3:m+2,2:n+1))' + a(:,J(2:m+1,1:n))' + a(:,J(2:m+1,3:n+2))')/4;
+  c = (c+c')/2;
+  return
+
+% C = bord(A,n,m)
+% Puts a border of width m (default m=1) around image A
+% and gives it value n. If n = NaN: mirror image values.
+function C = bord(A,n,m);
+	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
+	return
+	
Index: /hypertools/hypertools/maxsimc.m
===================================================================
--- /hypertools/hypertools/maxsimc.m	(revision 3)
+++ /hypertools/hypertools/maxsimc.m	(revision 3)
@@ -0,0 +1,90 @@
+%MAXSIMC Maximum similarity classifier
+% 
+%  W=MAXSIMC(A)
+% 
+% INPUT  
+%  A    Training dataset with dissimilarities to prototypes
+%
+% OUTPUT
+%  W    Maximum similarity classifier mapping
+%
+% DESCRIPTION
+% Maximum similarity classifier assigns an example to a class of the
+% maximally similar prototype. During training, only information about the
+% classes is % stored, but no data or parameters. During execution,
+% MAXSIMC expects that dataset with dissimilarities to training prototypes
+% is supplied. For each class, minimum dissimilarity is returned for each
+% class. Classifier outrput is a negative dissimilarity i.e. similarity
+% apropritate for prtools routines such as TESTC or CLASSD, may be used
+% directly.
+%
+% SEE ALSO
+% DATASETS, MAPPINGS, MINDISTC
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: maxsimc.m,v 1.3 2005/02/10 10:00:54 pavel Exp $
+
+function w=maxsimc(a,arg2)
+	
+	% No arguments given: return untrained mapping.
+
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename,{});
+		w = setname(w,'Maximum similarity classifier');
+		return
+	end
+
+	if (~exist('arg2','var'))     % Second argument is not a mapping: training.
+		
+		% in training, we do nothing
+		[m,k,c] = getsize(a);     % size of the training set		
+		data=[];
+		w = mapping(mfilename,'trained',data,getlablist(a),k,c);
+		w = setname(w,'Maximum similarity classifier');
+		
+	else
+		
+		% execution of minimum similarity classifier
+		
+		% input dataset is supposed to be a set of
+                % dissimilarities to training prototypes
+
+		ll=getlab(arg2); % lablist from the trained classifier
+		flab=getfeatlab(a); % feature labels
+
+		% nlab indices of a colums
+		featind=matchlablist(flab,ll);
+		featindll=unique(featind); % unique class ids
+		
+		out=zeros(size(a,1),size(ll,1));
+
+		for i=1:length(featindll)
+			
+			ind=find(featind==featindll(i));
+			
+			% we find minimum similarity for each test object
+			m=max(+a(:,ind),[],2);
+		
+			out(:,i)=m;
+		end
+
+		% first, we create a new dataset with original labels
+		% (we cannot setdat because the output has different
+                % feature labels)
+                w=dataset(out,getlab(a));
+		
+		% previous operation sorted the lablist into alphabetic
+                % order!
+		
+		% now, we set the correct feature labels for the output
+                % columns: sorted lablist is already in w, the feature
+                % labels are unique class names from the original
+                % training set lablist ll
+                w=dataset(out,getlab(w),'lablist',w.lablist,'featlab',ll(featindll,:),'prior',a.prior);
+	end
+	
+	return
+	
Index: /hypertools/hypertools/meansubppm.m
===================================================================
--- /hypertools/hypertools/meansubppm.m	(revision 3)
+++ /hypertools/hypertools/meansubppm.m	(revision 3)
@@ -0,0 +1,41 @@
+% BASESUBM Baseline subtraction mapping
+% 
+%  W = MEANSUBPPM(A)
+% 
+% INPUT  
+%  A       dataset 
+%
+% OUTPUT
+%  W       mean value of the spectrum subtraction mapping
+%
+% DESCRIPTION
+% Mean value subtraction from each spectra
+%
+% SEE ALSO
+% DATASETS, MAPPINGS
+
+% Copyright: S. Verzakov, P. Paclik, s.verzakov@tudelft.nl
+
+% $Id: meansubppm.m,v 1.1 2007/03/22 16:17:06 serguei Exp $
+
+function w = meansubppm(a,w)
+
+  % No dataset given: return fixed mapping.
+	if isempty(a)
+    w = mapping(mfilename, 'fixed');
+		w = setname(w,'Mean Value Subtraction Preprocessing Mapping');
+		return
+	end
+
+  isdataset(a);
+  [m,k]=getsize(a);
+
+	meanval = mean(+a,2); % mean of values in base-line region
+  a.data   = +a - repmat(meanval,[1, k]);
+ 
+  w = a;
+
+	return
+
+
+
Index: /hypertools/hypertools/mex/CVS/Entries
===================================================================
--- /hypertools/hypertools/mex/CVS/Entries	(revision 3)
+++ /hypertools/hypertools/mex/CVS/Entries	(revision 3)
@@ -0,0 +1,3 @@
+/distfunc.c/1.2/Wed Mar  3 13:13:23 2004//
+/distfunc.mexglx/1.1/Mon Feb  7 10:02:17 2005/-kb/
+D
Index: /hypertools/hypertools/mex/CVS/Repository
===================================================================
--- /hypertools/hypertools/mex/CVS/Repository	(revision 3)
+++ /hypertools/hypertools/mex/CVS/Repository	(revision 3)
@@ -0,0 +1,1 @@
+hypertools/mex
Index: /hypertools/hypertools/mex/CVS/Root
===================================================================
--- /hypertools/hypertools/mex/CVS/Root	(revision 3)
+++ /hypertools/hypertools/mex/CVS/Root	(revision 3)
@@ -0,0 +1,1 @@
+:pserver:davidt@shannon.et.tudelft.nl:/cvs/pavel
Index: /hypertools/hypertools/mex/distfunc.c
===================================================================
--- /hypertools/hypertools/mex/distfunc.c	(revision 3)
+++ /hypertools/hypertools/mex/distfunc.c	(revision 3)
@@ -0,0 +1,86 @@
+/*
+	distfunc.c - L1 metric between samples and prototypes
+
+	(c) 2004 Pavel Paclik, pavel@ph.tn.tudelft.nl
+
+	$Id: distfunc.c,v 1.2 2004/03/03 13:13:23 pavel Exp $
+
+  in order to make a MEX file in Matlab use:
+  >> mex distfunc.c -lmatlb
+
+*/
+
+#include <mex.h>
+#include <memory.h>
+#include <string.h>
+
+void mexFunction(
+                 int nlhs,       mxArray *plhs[],
+                 int nrhs, const mxArray *prhs[]
+		 )
+{
+  double *wp1, *wp2;
+  double* pd;
+  double dtemp;
+  int fc,sc,
+    pc; /* number of prototypes */
+  mxArray *arr,*arr2, *aout; /* input matrices */
+
+  int i,j,k; /* iterators */
+  int is_full_matrix=0; /* flag if we compute the whole sqaure matrix */
+
+  arr=(mxArray*)mlfTranspose(prhs[0]);
+  sc=mxGetN(arr);
+  fc=mxGetM(arr);
+
+  if( nrhs == 1 ) {
+    arr2=arr;
+    is_full_matrix=1; /* we may compute just half of the matrix */
+  } else {
+    arr2=(mxArray*)mlfTranspose(prhs[1]);
+  }
+   
+  pc=mxGetN(arr2);
+  if( fc != mxGetM(arr2) ) {
+    mexErrMsgTxt("input matrices must have the same number of columns\n");
+    return;
+  }
+
+  /*
+  if( mxGetN(prhs[nrhs-1])==mxGetM(prhs[nrhs-1]) & mxGetN(prhs[nrhs-1])==1 )
+    {
+      i=(int)*mxGetPr(prhs[nrhs-1]);
+      if(i>=0 & i<3) debug_level=i;
+      mexPrintf(" debug_level=%d,%d ",debug_level,i);
+    }
+  */
+
+  /* create output distance matrix */
+  aout=mxCreateDoubleMatrix(sc,pc,mxREAL);
+  pd=mxGetPr(aout);
+
+  wp1=mxGetPr(arr);
+  wp2=mxGetPr(arr2);
+  /*  mexPrintf(" %f, %f | %f, %f \n ",wp1[fc],wp1[fc+1],wp2[0],wp2[1]); */
+
+  for(i=0; i<pc; i++) 
+    {
+      for(j=0; j<sc; j++, pd++) 
+	{
+	  /* pointers to start of feature vectors */
+	  wp1=mxGetPr(arr); wp1+=fc*j;
+	  wp2=mxGetPr(arr2); wp2+=fc*i;
+	  for( k=0; k<fc; k++, wp1++, wp2++ ) 
+	    {
+	      dtemp=(*wp1) - (*wp2);
+	      /* absolute value */
+	      dtemp= dtemp<0.0?-dtemp:dtemp;
+	      *pd += dtemp;
+	    }
+	}
+    }
+
+  plhs[0]=aout;
+
+  return;
+}
Index: /hypertools/hypertools/mindistc.m
===================================================================
--- /hypertools/hypertools/mindistc.m	(revision 3)
+++ /hypertools/hypertools/mindistc.m	(revision 3)
@@ -0,0 +1,99 @@
+%MINDISTC Minimum distance classifier
+% 
+%  W=MINDISTC(A)
+% 
+% INPUT  
+%  A    Training dataset with dissimilarities to training prototypes
+%
+% OUTPUT
+%  W    Minimum distance classifier mapping
+%
+% DESCRIPTION
+% Minimum distance classifier measures minimum distance to a prototype from
+% each class. During training, only information about the classes is
+% stored, but no data or parameters. During execution, MINDISTC expects
+% that dataset with dissimilarities to training prototypes is supplied.
+% For each class, minimum dissimilarity is returned for each class. 
+% Classifier outrput is a negative dissimilarity i.e. similarity
+% apropritate for prtools routines such as TESTC or CLASSD, may be used
+% directly.
+%
+% SEE ALSO
+% DATASETS, MAPPINGS
+
+% Copyright: P. Paclik, pavel@@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: mindistc.m,v 1.12 2005/04/08 12:57:21 pavel Exp $
+
+function w=mindistc(a,arg2)
+	
+	% No arguments given: return untrained mapping.
+
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename,{});
+		w = setname(w,'Minimum distance classifier');
+		return
+	end
+
+	if (~exist('arg2','var'))     % Second argument is not a mapping: training.
+		
+		% in training, we do nothing
+		[m,k,c] = getsize(a);     % size of the training set		
+		data=[];
+		w = mapping(mfilename,'trained',data,getlablist(a),k,c);
+		w = setname(w,'Minimum distance classifier');
+		
+	else
+		
+		% execution of minimum distance classifier
+		
+		% input dataset is supposed to be a set of
+                % dissimilarities to training prototypes
+
+		ll=getlab(arg2); % lablist from the trained classifier
+		flab=getfeatlab(a); % feature labels
+
+		if ~strcmp(class(ll),class(flab))
+		    error(['lablist of the classifier and feature labels' ...
+			   ' of the mapping are of different format']);
+		end
+		
+		% nlab indices of a colums
+		featind=matchlablist(flab,ll);
+		featindll=unique(featind); % unique class ids
+		
+		out=zeros(size(a,1),size(ll,1));
+
+		for i=1:length(featindll)
+			
+			ind=find(featind==featindll(i));
+			
+			% we find minimum distance for each test object
+			m=min(+a(:,ind),[],2);
+			
+			out(:,i)=m;
+			
+		end
+
+		out=-out;
+		
+		% first, we create a new dataset with original labels
+		% (we cannot setdat because the output has different
+                % feature labels)
+                w=dataset(out,getlab(a));
+		
+		% previous operation sorted the lablist into alphabetic
+                % order!
+		
+		% now, we set the correct feature labels for the output
+                % columns: sorted lablist is already in w, the feature
+                % labels are unique class names from the original
+                % training set lablist ll
+                w=dataset(out,getlab(w),'lablist',w.lablist,'featlab', ...
+			  ll(featindll,:),'prior',a.prior,'user',a.user);
+		w.ident=a.ident;
+	end
+	
+	return
Index: /hypertools/hypertools/nlgldbm.m
===================================================================
--- /hypertools/hypertools/nlgldbm.m	(revision 3)
+++ /hypertools/hypertools/nlgldbm.m	(revision 3)
@@ -0,0 +1,200 @@
+%NLGLDBM Non-linear Fisher multi-class GLDB (bottom-up) mapping for spectra
+% 
+%  W = NLGLDBM(A)
+% 
+% INPUT  
+%  A    Training dataset
+%
+% OUTPUT
+%  W    best bases mapping
+%
+% DESCRIPTION
+% This routine implements Generalised Local Discriminant Bases (GLDB)
+% feature extraction using a multi-class criterion based on non-linear
+% Fisher mapping. Groups of adjacent features (wavelengths) are identified
+% in the input dataset such that Fisher criterion is maximized in each
+% group. Output dataset is created by projecting wavelengths in each group
+% to the Fisher subspace with dimensionality min(# of wavelengths in a
+% group,# of classes)-1.
+%
+% SEE ALSO
+% DATASETS, MAPPINGS
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: nlgldbm.m,v 1.4 2004/01/02 09:55:59 pavel Exp $
+
+function w = nlgldbm(a,arg2)
+
+	% No arguments given: return untrained mapping.
+		
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename);
+		w = setname(w,'Best Bases mapping');
+		return
+	end
+
+	if (~exist('arg2','var'))     % Second argument is not a mapping: training.
+
+		isdataset(a);           % Assert that A is a dataset.
+
+		[m,k,c] = getsize(a); M = classsizes(a);
+
+		% counter with ten steps
+		t=floor(m/10); 
+		counts=t*ones(1,10);
+		counts(1:mod(m,10))=counts(1:mod(m,10))+1;
+		counts=cumsum(counts);
+		
+		m=0;              % level
+		
+		if mod(size(a,2),2)==0
+			t=size(a,2);
+		else
+			t=size(a,2)-1;
+		end
+		l=1:2:t; % lower bounds of group-bands
+		u=2:2:t; % upper bounds of group-bands
+		u(end)=size(a,2); % asure that we use all bands
+		Nm=length(l);
+
+		% compute crit for each single band group:
+		I=crit_eval(l,u,a);
+
+		while 1
+			% make possible merges:
+			pl=l(1:Nm-1);
+			pu=u(2:Nm);
+			
+			% eval criterium
+			crit=crit_eval(pl,pu,a);
+			[maxval,ind]=max(crit);
+			while length(crit)>0
+				% if the merge candidate with the
+                                % highest crit.value yields smaller
+                                % criterium then maximum of the original
+                                % groups, choose 2nd best (3rd,... until
+                                % the end
+				if maxval<max(I([ind ind+1]))
+					crit(ind)=[];
+					[maxval,ind]=max(crit);
+				else
+					break
+				end
+			end
+			if length(crit)==0
+				% no merge candidate left, return what
+                                % we have at the moment.
+				[crit,clf]=crit_eval(l,u,a);
+
+				% parameters
+				pars.clf=clf; pars.l=l; pars.u=u; pars.info_iter=m;
+				
+				% get the output feature size from the clf
+				featcount=0; for i=1:length(pars.clf), featcount=featcount + size(pars.clf(i).w,2); end
+				w = mapping(mfilename,'trained',pars,getlablist(a),k,featcount);
+				w = setname(w,'Best Bases mapping');
+				
+				return
+			end
+			
+			% update crit vector
+			I(ind)=maxval;
+			I(ind+1)=[];
+
+			u(ind)=u(ind+1);
+			u(ind+1)=[];
+			l(ind+1)=[];
+			
+			m=m+1;
+			Nm=Nm-1;
+			fprintf('.');
+% $$$ 			if m==counts(1)
+% $$$ 				counts(1)=[];
+% $$$ 				fprintf('.');
+% $$$ 			end
+
+			if Nm==1
+				% all the features were lumped together
+				[crit,clf]=crit_eval(l,u,a);
+				% parameters
+				pars.clf=clf; pars.l=l; pars.u=u; pars.info_iter=m;
+				% get the output feature size from the clf
+				featcount=0; for i=1:length(pars.clf), featcount=featcount + size(pars.clf(i).w,2); end
+				w = mapping(mfilename,'trained',pars,getlablist(a),k,featcount);
+				w = setname(w,'Best Bases mapping');
+				return; 
+			end
+		end
+
+	else                      % Second argument is a a mapping: testing.
+
+		w = arg2;
+		pars = getdata(w);		 	% Unpack the mapping.
+		[m,k] = getsize(a); 
+
+		% create an output dataset
+		out=[];
+		for i=1:length(pars.clf)
+			% get the subset of bands...
+			t=+a(:,pars.l(i):pars.u(i));
+			% ... and project it to 1D Fisher subspace
+			out=[out t*pars.clf(i).w];
+		end
+	
+		w = setdat(a,out);
+	end
+
+return
+
+
+function [I,clf]=crit_eval(l,u,data)
+
+	I=zeros(1,length(l));
+
+	prior=getprior(data);
+	clf=[];
+	[m,k,c]=getsize(data);
+	for k=1:length(l)
+
+		Q=corrcoef(+data(:,l(k):u(k)));
+		% correlation
+		C=min(min( Q ));
+		
+		% turn within-class scatter into identity matrix
+		w = klms(data(:,l(k):u(k)));
+		b = data(:,l(k):u(k))*w;
+		U = +meancov(b);
+		d = +distm(U);
+		
+		% Compute the weights E to be used in the modified between-scatter matrix G
+		% E should diminish the influence of large distances D.
+		e = 0.5*erf(sqrt(d)/(2*sqrt(2))); 
+		B = zeros(size(b,2));
+		for j = 1:c
+			for i=j+1:c
+				% Marco-Loog Mapping
+				B = B + prior(i)*prior(j)*e(i,j)*(U(j,:)-U(i,:))'*(U(j,:)-U(i,:))/(d(i,j)+eps); 
+				B = (B + B')/2;		% Avoid a numerical inaccuracy: cov. matrix should be symmetric!
+			end
+		end
+		
+		fc=min(size(b,2),c)-1; % maximal number of features
+		% criterion for the k-th feature group
+		err_flag=0;
+		try
+			[F,V] = eig(B);
+		catch
+			fprintf('x');
+			I(k)=-1; % skip this group
+			clf(k).w=ones(1,fc);
+			err_flag=1;
+		end
+		if err_flag==0
+			[V,ind] = sort(-diag(V)); 
+			clf(k).w=F(:,ind(1:fc)); % projection matrix:
+			I(k)=C*sum(-V(1:fc)); % criterion is a sum of eigenvalues
+		end
+	end
Index: /hypertools/hypertools/opa.m
===================================================================
--- /hypertools/hypertools/opa.m	(revision 3)
+++ /hypertools/hypertools/opa.m	(revision 3)
@@ -0,0 +1,167 @@
+%OPA orthogonal projection approach to the selection of "pure" objects (key set of objects)
+%
+%  [Y,SEL_OBJ_IND,SEL_OBJ_DIS,DIS,ERR] = OPS(X,OPT)
+%
+% INPUT 
+%   X             [M -by- K] double matrix  
+%
+%   OPT.   
+%    MAX_NUM      the max number of objects to select, INF means selecting as many objects as possible,
+%                 until the rank of dataset is exausted; at least one variable will be always selected; by delault = INF
+%    EPS          stopping criteion; algorithm stops ERR < EPS, such objects are not included into the set; by default = 1e-2
+%    VERBOSE      force/disable messages; if PRPROGRESS is available: PRPROGRESS(VERBOSE,['%s\n'],MSG) will be run, 
+%                 if PRPROGRESS is not available: VERBOSE == [] or 0 -- no messages, VERBOSE ~= 0 runs DISP(MSG); 
+%                 by default = []
+%
+%
+% OUTPUT 
+%   Y              [M_SEL -by- K] dataset containing selected object
+%   SEL_OBJ_IND    [M_SEL -by- 1] vector of selected objects indices 
+%   SEL_OBJ_DIS    [M_SEL -by- 2] two vectors of selected objects dissimilarities; 
+%                  in the first column are absolute dissims, and in the second are relative dissim
+%   DIS            [M -by- M_SEL -by- 2] two matrices which columns are dissimilarities profiles; 
+%                  each column contains dissimilarities of all objects at particular selection step;
+%                  the first matrix contains abs dissim, the second one containes relative dissim
+%   ERR            [M_SEL -by- 1] relative squared error of the data projection to the subspace spanned by the select objects
+%
+% DESRIPTION
+% Low level routine.
+% Implementation of the OPA algorithm as described in
+% "Orthogonal Projection Approach Applied to Peak Purity Asessment"  
+%  by F. C. Snachez, J. Toft, B. van den Bogaert, D. L. Massart, Anla. Chem. 68, 1, 79-85, 1996 
+%
+% Absolute dissim measure  abs_diss_(n+1) = ||dx||^2*det(Y_n Y_n^T)
+% Relative dissim measure  rel_diss_(n+1) = ||dx||^2
+%
+% Here, Y_n is the set of n selected objects (rows), which are normalized to have a unit length, dx is the part of 
+% an object x which is (part) orthogonal to span(Y). If n=0 (diss(1)) then the dissimilarity to the mean object is measured.
+%
+% SEE ALSO
+% OPAM, OPAPS, SIMPLISMA, VARIMAX, ALS
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+
+% $Id: opa.m,v 1.9 2006/03/15 12:17:15 serguei Exp $
+
+function [Y, sel_obj_ind, sel_obj_dis, dis, err] = opa(X,Options)
+
+if nargin < 2
+  Options = [];
+end
+
+DefOptions.max_num    = inf;
+DefOptions.eps        = 1e-2;
+DefOptions.verbose    = [];
+Options = updstruct(DefOptions, Options);
+
+%----------------
+prprog = exist('prprogress');
+if ~prprog & isempty(Options.verbose)
+  Options.verbose = 0;
+end
+%----------------
+
+
+[N, d] = size(X);
+Options.max_num = min([Options.max_num, N, d]);
+
+Y_m = mean(X,1);
+O = Y_m/sqrt(Y_m*Y_m');
+
+X_ss = sum(X.*X,2); 
+SS = sum(X_ss);
+
+dis = X_ss - (X*O').^2;
+%err0 = sum(dis)/SS;
+dis = cat(3,dis,dis);
+[sel_obj_dis, ind] = max(dis(:,1,2));
+sel_obj_dis = [sel_obj_dis, sel_obj_dis];
+
+O = X(ind,:)/sqrt(X_ss(ind));
+
+Y = X(ind,:);
+X(ind,:)    = [];
+X_ss(ind,:) = [];
+dX_ss = X_ss;
+
+sel_obj_ind = ind;
+obj_ind = [1:N]';
+obj_ind(ind) = [];
+
+Det_factor = 1;
+Det = Det_factor;
+
+dX_ss = dX_ss - (X*O(end,:)').^2;
+err = sum(dX_ss)/SS;
+
+Msg = ['step 1; max dissim to the mean sample is dis(' num2str(ind) ')=' num2str(sel_obj_dis(1)) ... 
+       '; err=' num2str(err)];
+if prprog
+  prprogress(Options.verbose,['%s\n'],Msg);
+elseif Options.verbose
+  disp(['opa: ' Msg]);
+end  
+
+for i=2:Options.max_num
+  if err(i-1) < Options.eps
+    break;
+  end
+
+  dis(obj_ind,i,2) = dX_ss;  
+  [sel_obj_dis(i,2), ind] = max(dis(obj_ind,i,2));
+  Det_factor = sel_obj_dis(i,2)/X_ss(ind);
+
+  dis(obj_ind,i,1) = dis(obj_ind,i,2)*Det;
+  sel_obj_dis(i,1) = sel_obj_dis(i,2)*Det;
+  Det = Det_factor*Det;
+  
+  O = [O; (X(ind,:) - (X(ind,:)*O')*O)/sqrt(dX_ss(ind))];
+  Y = [Y; X(ind,:)];
+  X(ind,:)     = [];
+  X_ss(ind,:)  = [];
+  dX_ss(ind)   = [];
+  
+  sel_obj_ind  = [sel_obj_ind; obj_ind(ind)];
+  obj_ind(ind) = [];
+  
+  dX_ss = dX_ss - (X*O(end,:)').^2;
+  err(i,1) = sum(dX_ss)/SS;
+  
+  Msg = ['step ' num2str(i) ...
+         '; max dissim to the current set of sample(s) are' ...
+         ' abs diss(' num2str(sel_obj_ind(i)) ')=' num2str(sel_obj_dis(i,1)) ...
+         ' rel diss(' num2str(sel_obj_ind(i)) ')=' num2str(sel_obj_dis(i,2)) ...
+         '; err=' num2str(err(i))];
+ 
+  if prprog
+    prprogress(Options.verbose,['%s\n'],Msg);
+  elseif Options.verbose
+    disp(['opa: ' Msg]);
+  end  
+end
+
+return
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /hypertools/hypertools/opam.m
===================================================================
--- /hypertools/hypertools/opam.m	(revision 3)
+++ /hypertools/hypertools/opam.m	(revision 3)
@@ -0,0 +1,118 @@
+%OPAM Orthogonal projection approach: selects "pure" features
+%  
+%
+%  U = OPAM
+%  U = OPAM([], OPT)
+%
+%  W = A*U
+%  [W, SEL_VAR_DIS, DIS] = MAP(A, U)
+%  [W, SEL_VAR_DIS, DIS] = OPAM(A, OPT)
+%
+%  C = B*W
+%  C = MAP(B, W)
+%  C = OPAM(B, W)
+%
+%
+% INPUT 
+%   A             [M -by- K] training dataset
+%   B             [N -by- K] test dataset
+%
+%   U             [K -by- ?] untrained OPAM mapping
+%   W             [K -by- K_SEL] trained OPAM feature selection mapping;
+%                 indices of selected variables stored in W.DATA.IND  
+%
+%   OPT.          optional OPA settings
+%    MAX_NUM      the max number of variables to select, INF means selecting as many variables as possible,a
+%                 until the rank of dataset is exausted; at least one variable will be always selected; by delault = INF
+%    EPS          stopping criteion; algorithm stops ERR < EPS, such features are not included into the set; by default = 1e-2 
+%    VERBOSE      force/disable messages: PRPROGRESS(VERBOSE,['%s\n'],MSG) will be run;
+%                 by default = []
+%
+% OUTPUT 
+%   U               [K -by- ?] untrained OPAM mapping
+%   W               [K -by- K_SEL] trained OPAM feature selection mapping;
+%                   indices of selected variables stored in W.DATA.IND  
+%   SEL_VAR_IND     [K_SEL -by- 1] vector of selected variables indices 
+%   SEL_VAR_DIS     [K_SEL -by- 2] two vectors of selected variables disssimilarities 
+%                   in the first column are absolute dissims, and in the second are relative dissim
+%   DIS             [K_SEL -by- K -by- 2] two matrices which rows are dissimmilarity spectra; 
+%                   each row contains dissim of all variables at particular selection step;
+%                   the first matrix contains abs dissim, the second one containes relative dissim
+%   ERR             [K_SEL -by- 1] relative squared error of the data projection to the subspace spanned by the select features
+%   C               [N -by- K_SEL] dataset, result of mapping execution on dataset B
+%
+% DESRIPTION
+% Implementation of the OPA algorithm as described in
+% "Orthogonal Projection Approach Applied to Peak Purity Asessment"  
+%  by F. C. Snachez, J. Toft, B. van den Bogaert, D. L. Massart, Anla. Chem. 68, 1, 79-85, 1996 
+% (applied to the transposed data matrix)
+%
+% Absolute dissim measure  abs_diss_(n+1) = ||dx||^2*det(Y_n^T Y_n)
+% Relative dissim measure  rel_diss_(n+1) = ||dx||^2
+%
+% Here, Y_n is the set of n selected features (columns), which are normalized to have a unit length, dx is the part of 
+% a feature x which is (part) orthogonal to span(Y). If n=0 (diss(1)) the dissimilarity to the mean feature is measured.
+%
+% SEE ALSO
+% SIMPLISMAM, VARIMAXFM, SIMLISMAPS, OPAPS, VARIMAXOM, ALS, OPA
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: opam.m,v 1.7 2007/01/31 21:52:19 serguei Exp $
+
+function [w, sel_var_dis, dis, err] = opam(a,w)
+
+% No dataset given: return untrained mapping.
+if (nargin < 1) | (isempty(a))
+  if nargin < 2
+    w = [];
+  end  
+  w = mapping(mfilename,'untrained',{w});
+  w = setname(w,'OPA Mapping');
+  return
+end
+
+isdataset(a);           % Assert that A is a dataset.
+
+% training
+if nargin < 2 | ~isa(w,'mapping') 
+  if nargin < 2
+    w = [];  
+  end  
+
+  [m,k] = getsize(a);
+  
+  [z, sel_var_ind, sel_var_dis, dis, err] = opa((+a)',w);
+  dis = permute(dis,[2 1 3]);
+
+  w_data.ind = sel_var_ind;
+
+  %labels = [num2str([1:length(sel_var_ind)]','%-1d'),  num2str(sel_var_ind(:),'(%-1d)')];
+  labels = a.featlab(sel_var_ind,:);
+  
+  % Save all useful data
+  w = mapping(mfilename,'trained',w_data,labels,size(a,2),length(sel_var_ind));
+  w = setname(w,'OPA Feature Selection');
+  
+% applying
+else 
+  w_data = +w; % Unpack the mapping.
+  %w = a*cmapm(w.size_in,w_data.ind);
+  a = a(:,w_data.ind);
+  %a.featlab = w.labels;
+  units = specunits(a);
+  a = remove_spectra_info(a);
+  if units
+    user = a.user;
+    user.type = 'spectra';
+    user.units = units;
+    a.user = user;
+  end  
+  a.name = [a.name ': selected channels'];
+  w = a;
+end
+
+return
+
Index: /hypertools/hypertools/opaps.m
===================================================================
--- /hypertools/hypertools/opaps.m	(revision 3)
+++ /hypertools/hypertools/opaps.m	(revision 3)
@@ -0,0 +1,56 @@
+%OPAPS Orthogonal projection approach: selects "pure" objects
+%  
+%
+%  [B, SEL_OBJ_IND, SEL_OBJ_DIS, DIS, ERR] = OPAPS(A)
+%  [B, SEL_OBJ_IND, SEL_OBJ_DIS, DIS, ERR] = OPAPS(A, OPT)
+%
+%
+% INPUT 
+%   A             [M -by- K] training dataset
+%
+%   OPT.   
+%    MAX_NUM      the max number of objects to select, INF means selecting as many objects as possible,
+%                 until the rank of dataset is exausted; at least one variable will be always selected; by delault = INF
+%    EPS          stopping criteion; algorithm stops ERR < EPS, such objects are not included into the set; by default = 1e-2
+%    VERBOSE      force/disable messages: PRPROGRESS(VERBOSE,['%s\n'],MSG) will be run; 
+%                 by default = []
+%
+% OUTPUT 
+%   B              [M_SEL -by- K] dataset containing selected object
+%   SEL_OBJ_IND    [M_SEL -by- 1] vector of selected objects indices 
+%   SEL_OBJ_DIS    [M_SEL -by- 2] two vectors of selected objects dissimilarities 
+%                  in the first column are absolute dissims, and in the second are relative dissim
+%   DIS            [M -by- M_SEL -by- 2] two matrices which columns are dissimilarities profiles; 
+%                  each columns contains dissimilarities of all objects at particular selection step;
+%                  the first matrix contains abs dissim, the second one containes relative dissim
+%   ERR            [M_SEL -by- 1] relative squared error of the data projection to the subspace spanned by the select objects
+%
+% DESRIPTION
+% Implementation of the OPA algorithm as described in
+% "Orthogonal Projection Approach Applied to Peak Purity Asessment"  
+%  by F. C. Snachez, J. Toft, B. van den Bogaert, D. L. Massart, Anla. Chem. 68, 1, 79-85, 1996 
+%
+% Absolute dissim measure  abs_diss_(n+1) = ||dx||^2*det(Y_n Y_n^T)
+% Relative dissim measure  rel_diss_(n+1) = ||dx||^2
+%
+% Here, Y_n is the set of n selected objects (rows), which are normalized to have a unit length, dx is the part of 
+% an object x which is (part) orthogonal to span(Y). If n=0 (diss(1)) the dissimilarity to the mean object is measured.
+%
+% SEE ALSO
+% SIMPLISMAPS, VARIMAXOM, SIPMLISMAM, OPAM, VARIMAXOM, ALS, OPA
+
+
+
+function [b, sel_obj_ind, sel_obj_dis, dis, err] = opaps(a, Opt)
+
+if nargin < 2
+  Opt = [];
+end
+
+[y, sel_obj_ind, sel_obj_dis, dis, err] = opa(+a,Opt);
+
+b = a(sel_obj_ind,:);
+b.name = [b.name ': selected spectra'];
+
+return
+
Index: /hypertools/hypertools/pca_apply.m
===================================================================
--- /hypertools/hypertools/pca_apply.m	(revision 3)
+++ /hypertools/hypertools/pca_apply.m	(revision 3)
@@ -0,0 +1,31 @@
+%pca_apply apply PCA model to the new (test) data
+%
+% T = pca_apply(X,P,Options)
+%
+% INPUT 
+%   X         [N -by- d] data matrix, N samples, d variables
+%   P         matrix returned by pca_train
+%   Options.  structure returned by pca_train
+%
+% OUTPUT
+%   T        scores  
+%
+% DESCRIPTION
+%
+% SEE ALSO
+% pca_train
+
+% Copyright: S. Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: pca_apply.m,v 1.2 2004/01/20 10:51:41 serguei Exp $
+
+
+function T = pca_apply(X,P,Options)
+
+X = prepro(X, Options.X_centering, Options.X_scaling);
+T = X*P;
+
+return;
+
Index: /hypertools/hypertools/pca_crit.m
===================================================================
--- /hypertools/hypertools/pca_crit.m	(revision 3)
+++ /hypertools/hypertools/pca_crit.m	(revision 3)
@@ -0,0 +1,178 @@
+%pca_crit Calculation of critical levels for PCA
+%
+%  CritLevel = pca_crit(conf_level,lambda,nPC_model,Options)
+%  CritLevel = pca_crit(conf_level,lambda,nPC_model,Options,Stat,ecv_only)
+%
+% INPUT 
+%   conf_level  confidence level(s) (1-alpha error) (conf_level=0.95 by default);
+%               conf_level van be row, vector or matrix
+%   lambda      [1 -by- nPC]  first nPC largest eigenvalues 
+%   nPC_model   the number of PC's in the model for which crit levels will be calculated,
+%               nPC_model <= length(lambda)
+%   Options     structure returned by pca_train
+%   Stat        structure returned by pca_stat; it is used to calculate empirical critical levels
+%   ecv_only    calculate only empirical critical values; by default = 0
+%
+%
+%   mean_centering was (mean_centering=1) or was not (mean_centering=0) data mean centered
+%                    in the feature space (mean_centering=1 by default)
+% OUTPUT
+%   CritLevel.            structure containig critical levels calculated
+%    conf_level            confidence level(s) used for calculations
+%    nPC_model             number of the scores retained in the model 
+%    nPC                   total number of the availabel PCs
+%                          PC(nPC_model+1) ... PC(nPC) were used to calculate  T^2_rest
+%    Q, Q_alt, Q_emp       critical levels for Euclidian distance to the model plane
+%    T2, T2_emp            critical levels for Mahalanobis distance in the model plane
+%    T2_rest, T2_rest_emp  critical levels for (partial) Mahalanobis distance to the model plane
+%   
+%
+% DESCRIPTION
+%   
+% 
+% SEE ALSO
+% pca_apply
+
+% Copyright: S. Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: pca_crit.m,v 1.7 2005/05/05 14:35:55 serguei Exp $
+
+
+
+function CritLevel = pca_crit(conf_level,lambda,nPC_model,Options,Stat,ecv_only)
+
+if nargin < 5
+  Stat = [];
+end
+
+if nargin < 6
+  ecv_only = 0;
+end
+
+N   = Options.N;
+M   = Options.M;
+nPC = Options.nPC;
+a   = Options.rank;
+
+if nPC_model > nPC
+  error('The number of availabel PC''s is smaller than the number of the PS''s retaind in the model');
+end
+
+%--- Q-statistics critical level
+if nPC_model == a
+  if ~ecv_only
+    CritLevel.Q=zeros(size(conf_level));
+    CritLevel.Q_alt = zeros(size(conf_level));
+  end
+  
+  if ~isempty(Stat) & isfield(Stat,'Q')
+    CritLevel.Q_emp = zeros(size(conf_level));  
+  end  
+  
+else
+  if ~ecv_only
+    lambda_model = lambda(1:nPC_model);
+    Th1 = Options.Tr1 - sum(lambda_model);
+    Th2 = Options.Tr2 - sum(lambda_model.^2);
+    Th3 = Options.Tr3 - sum(lambda_model.^3);
+    
+    c  = sqrt(2)*erfinv(2*conf_level - 1); % == norminv(conf_level);
+    h0 = 1 - 2*Th1*Th3/(3*Th2*Th2);
+    CritLevel.Q = Th1*( c*(h0*sqrt(2*Th2)/Th1) + (1 + Th2*h0*(h0-1)/(Th1*Th1)) ).^(1/h0);
+    
+    try
+      c = finv(conf_level,a-nPC_model,(a-nPC_model)*(N-nPC_model-1));
+      %% PP!!
+      %  if (N-nPC_model-1)==0, keyboard; end
+      CritLevel.Q_alt = (M*Th1/(N-nPC_model-1))*c;
+    catch
+      WarnMsg = sprintf(['CritLevel.Q_alt cannot be calculated, set to nan:\n' lasterr]);
+      if exist('prwarning')
+        prwarning(2, WarnMsg);
+      else
+        warning(WarnMsg);
+      end
+      CritLevel.Q_alt = repmat(nan,size(conf_level));  
+    end
+  end
+  if ~isempty(Stat) & isfield(Stat,'Q')
+    %CritLevel.Q_emp = prctile(Stat.Q,100*conf_level(:));
+    CritLevel.Q_emp = get_percentile(Stat.Q,conf_level(:));
+    CritLevel.Q_emp = reshape(CritLevel.Q_emp,size(conf_level));  
+  end  
+end
+
+%--- T2-statistics critical level
+if ~ecv_only
+  try
+    c = finv(conf_level,nPC_model,N-nPC_model);
+    CritLevel.T2 = (M*nPC_model/(N-nPC_model))*c;
+    
+  catch
+    WarnMsg = sprintf(['CritLevel.T2 cannot be calculated, set to nan:\n' lasterr]);
+    if exist('prwarning')
+      prwarning(2, WarnMsg);
+    else
+      warning(WarnMsg);
+    end
+    CritLevel.T2 = repmat(nan,size(conf_level));  
+  end
+end
+
+if ~isempty(Stat) & isfield(Stat,'T2')
+  %CritLevel.T2_emp = prctile(Stat.T2,100*conf_level(:));
+  CritLevel.T2_emp = get_percentile(Stat.T2,conf_level(:));
+  CritLevel.T2_emp = reshape(CritLevel.T2_emp,size(conf_level));  
+end        
+
+%------ T2_rest-statistics critical level
+if nPC_model < nPC
+  if ~ecv_only
+    try
+      c = finv(alpha_level,nPC-nPC_model,N-nPC+nPC_model);
+      CritLevel.T2_rest = (M*(nPC-nPC_model)/(N-nPC+nPC_model))*c;
+      
+    catch
+      WarnMsg = sprintf(['CritLevel.T2_rest cannot be calculated, set to nan:\n' lasterr]);
+      if exist('prwarning')
+        prwarning(2, WarnMsg);
+      else
+        warning(WarnMsg);
+      end
+      CritLevel.T2_rest = repmat(nan,size(conf_level));  
+    end
+  end  
+  
+  if ~isempty(Stat)  & isfield(Stat,'T2_rest')
+    %CritLevel.T2_rest_emp = prctile(Stat.T2_rest,100*conf_level(:));
+    CritLevel.T2_rest_emp = get_percentile(Stat.T2_rest,conf_level(:));
+    CritLevel.T2_rest_emp = reshape(CritLevel.T2_rest_emp,size(conf_level));  
+  end
+else
+  if ~ecv_only
+    WarnMsg = sprintf(['The number of PC''s availabel is equal to the nubmer of the PC''s in model.\n'...
+        'CritLevel.T2_rest cannot be calculated, set to nan\n']);
+    if exist('prwarning')
+      prwarning(2, WarnMsg);
+    else
+      warning(WarnMsg);
+    end
+    CritLevel.T2_rest = repmat(nan,size(conf_level));  
+  end
+  
+  if ~isempty(Stat) & isfield(Stat,'T2_rest')  
+    WarnMsg = sprintf(['The number of PC''s availabel is equal to the nubmer of the PC''s in model.\n'...
+        'CritLevel.T2_rest_emp cannot be calculated, set to nan\n']);
+    if exist('prwarning')
+      prwarning(2, WarnMsg);
+    else
+      warning(WarnMsg);
+    end
+    CritLevel.T2_rest_emp = repmat(nan,size(conf_level));  
+  end  
+end
+
+return;
+
Index: /hypertools/hypertools/pca_npc.m
===================================================================
--- /hypertools/hypertools/pca_npc.m	(revision 3)
+++ /hypertools/hypertools/pca_npc.m	(revision 3)
@@ -0,0 +1,185 @@
+%pca_npc Estimation of the significant number of PCs
+%
+%  [Out,T,P,lambda,PCAOptions] = pca_npc(X,Options)
+%
+% INPUT 
+%  X             [N -by- d] training input data matrix, N samples, d variables
+%
+%  Options.
+%   M            scatter matrix normalization: C = X'*X/M
+%                by default M = N-1 (so if columns of X were mean-centered, C is the unbiased estimation
+%                of the covariance matrix)
+%   X_centering  do nothing (==[] or 0), do mean centering (==nan), center around some vaue v (==v); by default  ==[]
+%   X_scaling    do nothing (==[] or 1), divide each col by std (=nan), divide by some v (=v); by default =[]
+%
+%   nPC_em       nPC esimation method: 'PEV', 'MI', 'F', 'KG' , 'PRESS' or
+%                cell array containing any combination  of this strings; 
+%                'ALL' is the shortcut for {'PEV', 'MI', 'F', 'KG', 'PRESS'}; 
+%                'NOPRESS' is the shortcut for the {'PEV', 'MI', 'F', 'KG'};
+%                by default 'NOPRESS'
+%   PEV          part of explained varince; according to this criteria nPC
+%                is the minimum number of PC such that the portion of explained variance is >= pev; 
+%                by default 0.95; if mean centering was not performed then pev defines the level 
+%                not for the explained variance but for the explained sum of squares; 
+%   F_cl         the confidence level for Malinowski F-test
+%
+%
+% OUTPUT
+%  Out. structure containing the results
+%    max_nPC    maximum possible number of PCs
+%    PEV        [1 -by- max_nPC] PEV(i) is the part of variance explained by i PCs
+%    nPC_PEV    number of PC according to PEV citerion
+%    MI         [1 -by- max_nPC] MI(i) is the Malinowski indicator for the model with i PCs
+%    nPC_MI     number of PC according to MI 
+%    F          [1 -by- max_nPC] F(i) is the Malinowski F-ratio for the model with i PCs
+%    nPC_F      number of PC according to F
+%    KG         Kaiser-Guttman criterion (lambda/sum(lambda))
+%    nPC_KG     number of PC according to KG : largets i such KG(i) > 1
+%    PRESS      predicted error sum of squares (leave-one-out)
+%    nPC_PRESS  ...
+%
+% DESCRIPTION
+%
+% SEE ALSO
+% pca_apply
+
+% Copyright: S. Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: pca_npc.m,v 1.5 2005/05/05 14:35:55 serguei Exp $
+
+
+function [Out,T,P,lambda,PCAOptions] = pca_npc(X,Options)
+
+if nargin < 2
+  Options  = [];
+end
+
+
+DefaultOptions.nPC_em = 'NOPRESS';
+DefaultOptions.PEV = 0.95;
+DefaultOptions.F_cl = 0.95;
+
+Options = updstruct(DefaultOptions, Options);
+
+
+if ischar(Options.nPC_em)
+  switch upper(Options.nPC_em)
+  case 'ALL'
+    Options.nPC_em = {'PEV', 'MI', 'F', 'KG', 'PRESS'};
+  case 'NOPRESS'
+    Options.nPC_em = {'PEV', 'MI', 'F', 'KG'};
+  otherwise
+
+  end
+end
+
+DoPEV   = any(strcmpi('PEV',Options.nPC_em));
+DoMI    = any(strcmpi('MI',Options.nPC_em));
+DoF     = any(strcmpi('F',Options.nPC_em));
+DoKG    = any(strcmpi('KG',Options.nPC_em));
+DoPRESS = any(strcmpi('PRESS',Options.nPC_em));
+
+[N,d] = size(X);
+
+Options.nPC = inf;
+
+% Out = [];
+%if DoPEV | DoMI | DoF | DoKG
+[T,P,lambda,PCAOptions] = pca_train(X,Options);
+Out.nPC_max = PCAOptions.nPC;
+%end  
+
+
+% PEV 
+if DoPEV
+  Out.PEV = PCAOptions.PEV;
+  Out.nPC_PEV = min(find(PCAOptions.PEV >= Options.PEV));
+end
+
+% MI
+if DoMI
+  d1 = max(N,d);
+  d2 = min(N,d);
+  %d1 = min(N,d);
+  %d2 = max(N,d);
+  
+  if Out.nPC_max == d2
+    max_ind = Out.nPC_max-1;
+    RE(Out.nPC_max) = 0;
+    Out.MI(Out.nPC_max) = 0;
+  else
+    max_ind = Out.nPC_max;
+  end
+  RE(1:max_ind) = sqrt((PCAOptions.Tr1 - cumsum(lambda(1:max_ind)))./((d1-1).*(d2-(1:max_ind))));
+  Out.MI(1:max_ind) = RE(1:max_ind)./((d2-(1:max_ind)).^2);
+  if Out.nPC_max == PCAOptions.rank
+    max_ind = Out.nPC_max-1;
+  else
+    max_ind = Out.nPC_max;
+  end
+  [MI_val, Out.nPC_MI] = min(Out.MI(1:max_ind));
+end  
+
+% F
+if DoF
+  REV = lambda./((d-(1:Out.nPC_max)+1) .* (N-(1:Out.nPC_max)+1));
+  %avr_REV = fliplr(cumsum(fliplr(REV(2:end))));
+  avr_REV = fliplr(cumsum(fliplr(REV(2:end))))./(Out.nPC_max-(1:(Out.nPC_max-1)));
+  F_crit = finv(Options.F_cl,1,[(Out.nPC_max-(1:(Out.nPC_max-1)))]);
+  Out.F = (REV(1:(end-1)) ./ avr_REV) ./ F_crit;
+  Out.nPC_F = min(find(Out.F <= 1))-1;
+end
+
+%KG
+if DoKG
+  Out.KG = lambda(1:Out.nPC_max)/(PCAOptions.Tr1/d);
+  Out.nPC_KG = min(find(Out.KG <= 1)) - 1;
+end  
+
+if DoPRESS
+  if ~isempty(Out) & isfield(Out,'nPC_max')  
+    nPC = Out.nPC_max; 
+  else  
+    nPC = min(N,d); 
+  end
+
+  Out.PRESS = zeros(N,nPC);  
+  ind_test = 1:N;
+  for i=1:N
+    X_train = X;
+    X_train(ind_test(i),:) = [];
+    X_test = X(ind_test(i),:);
+ 
+    [T_train,P_PRESS,lambda_PRESS,PCAOptions_PRESS] = pca_train(X_train,Options);
+    T_test = pca_apply(X_test,P_PRESS,PCAOptions_PRESS);  
+    X_test = prepro(X_test,PCAOptions_PRESS.X_centering,PCAOptions_PRESS.X_scaling);
+
+    for j=1:PCAOptions_PRESS.nPC
+      X_test = X_test - T_test(:,j)*P_PRESS(:,j)';
+      Out.PRESS(ind_test(i),j) = X_test*X_test';
+    end
+    %Out.PRESS(ind_test(i),:) = cumsum((T_test(:,1:PCAOptions_PRESS.nPC).^2)./lambda_PRESS(1:PCAOptions_PRESS.nPC));
+
+    nPC = min(PCAOptions_PRESS.nPC,nPC);
+  end
+
+  if ~isfield(Out,'nPC_max')  
+    Out.nPC_max = nPC; 
+  end
+
+  Out.PRESS = sum(Out.PRESS,1);
+  Out.PRESS = Out.PRESS(1,1:nPC);
+  [PRESS_val, Out.nPC_PRESS] = min(Out.PRESS);
+  %keyboard
+
+%else
+%  Out.PRESS = repmat(nan,[1, Out.nPC_max]);
+%  Out.nPC_PRESS = nan;
+end
+
+
+
+return;
+
Index: /hypertools/hypertools/pca_stat.m
===================================================================
--- /hypertools/hypertools/pca_stat.m	(revision 3)
+++ /hypertools/hypertools/pca_stat.m	(revision 3)
@@ -0,0 +1,61 @@
+%pca_stat Calculation statistics on the results of PCA
+%
+%  Stat = pca_stat(X,T,P,lambda,nPC_model,Options)
+%
+% INPUT 
+%   X         [N -by- d]   data matrix, N samples, d variables
+%   T         [N -by- nPC] scores of X (returned by pca_apply or by pca_train)
+%   P         [N -by- nPC] loadings (returned by pca_train)
+%   lambda    [1 -by- nPC]  first nPC largest eigenvalues 
+%   nPC_model the number of PCs in the model for which statistics will be calculated
+%             (nPC_model <= nPC)
+%   Options   structure returned by pca_train
+%
+% OUTPUT
+%  Stat.   the structure containig statistical information calculated
+%    Q       [N -by- 1] Euclidian distances to the model plane
+%    T2      [N -by- 1] Mahalanobis distances in the model plane
+%    T2_rest [N -by- 1] Mahalanobis distances out the model plane
+%
+% DESCRIPTION
+%
+% SEE ALSO
+% pca_apply
+
+% Copyright: S. Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: pca_stat.m,v 1.3 2005/05/05 14:35:55 serguei Exp $
+
+
+
+function Stat = pca_stat(X,T,P,lambda,nPC_model,Options)
+
+if nPC_model > length(lambda)
+  error('The number of PCs in the model is large than the number of PC availabel (nPC_model > length(lambda))');
+end
+
+[N,d] = size(X);
+
+X = prepro(X,Options.X_centering,Options.X_scaling);
+
+Stat.Q  = sum((X-T(:,1:nPC_model)*P(:,1:nPC_model)').^2,2);
+Stat.T2 = sum((T(:,1:nPC_model).^2)./ repmat(lambda(1:nPC_model), [N 1]),2);
+
+if nPC_model < Options.nPC
+  Stat.T_rest2 = sum((T(:,(nPC_model+1):end).^2)./ repmat(lambda((nPC_model+1):end), [N 1]),2);
+
+else
+  WarnMsg = sprintf(['The number of PC''s availabel is equal to the nubmer of the PC''s in model.\n'...
+                     'Stat.T2_rest cannot be calculated, set to nan\n']);
+  if exist('prwarning')
+    prwarning(2, WarnMsg);
+  else
+    warning(WarnMsg);
+  end
+  Stat.T2_rest = repmat(nan,[N,1]);  
+end
+
+return;
+
Index: /hypertools/hypertools/pca_train.m
===================================================================
--- /hypertools/hypertools/pca_train.m	(revision 3)
+++ /hypertools/hypertools/pca_train.m	(revision 3)
@@ -0,0 +1,194 @@
+%pca_train Principal Component Analysis (training)
+%  
+%  [T, P, lambda, Options] = pca_train(X)
+%  [T, P, lambda, Options] = pca_train(X,Options)
+%
+% INPUT 
+%  X             [N -by- d] training input data matrix, N samples, d variables
+%
+%  Options.
+%   M            scatter matrix normalization: C = X'*X/M
+%                by default M = N-1 (so if columns of X were mean-centered, C is the unbiased estimation
+%                of the covariance matrix)
+%   X_centering  do nothing (==[] or 0), do mean centering (==nan), center around some vaue v (==v); by default  ==[]
+%   X_scaling    do nothing (==[] or 1), divide each col by std (=nan), divide by some v (=v); by default =[]
+%   nPC          the number of principal components to return; by default inf;
+%                nPC==inf means nPC==rank(preprocessed X);
+%                nPC==nan means autodetection according to nPC_em
+%   nPC_em       nPC esimation method: 'PEV', 'MI', 'F', 'KG', 'PRESS'; by default 'PEV'     
+%   PEV          part of explained varince; if nPC==nan  and nPC_em is 'PEV' then the number of 
+%                principal components to return is the minimum number of PC such that the portion
+%                of explained variance is >= PEV; by default 0.95
+%                if mean centering was not performed then PEV defines the level 
+%                not for the explained variance but for the explained sum of squares; 
+%   F_cl         confidence level  for Malinowski F-test, if nPC==nan  and nPC_em is 'F'  
+%                then the F-test with such a conf. level will be used to estimate the number of PCs 
+%  
+% OUTPUT
+%  T       [N -by- nPC]  scores   (transformed (preprocessed) X)
+%  P       [X -by- n]    loadings (new axis in old coordinats)
+%  lambda  [1 -by- nPC]  first nPC largest eigenvalues of X'*X/M (covariance matrix) of (preprocessed) X
+%
+% Options. contains
+%   1) the same fields as in the input, but the values can be changed 
+%      (e.g. after mean centering X_centering = mean(X,1); nPC==the number of retained components;
+%      PEV==the portion of explained variance)
+%   2) N, d are the sizes of the training set X
+%   3) rank is the rank of the training set X
+%   4) Tr1 = sum(lambda), Tr2 = sum(lambda.^2), Tr3 = sum(lambda.^3), 
+%      where sum goes over all nonzero lambdas (not only over the first nPC ones) 
+%
+%
+% DESCRIPTION
+% Performs PCA. 
+%
+% Relations between matrices (X is assumed to be preprocessed):
+%
+% [X'*X/M]*P = P*diag(lambda)
+% [X*X'/M]*T = T*diag(lambda)
+% P'*P = eye(nPC)
+% T'*T/M = diag(lambda)
+% X = T*P' + Err
+% T = X*P
+% P*diag(lambda)*M = X'*T;
+% explvar = sum(lambda)/trace(X'*X/M)
+%  
+%
+% SEE ALSO
+% pca_apply
+
+% Copyright: S. Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: pca_train.m,v 1.9 2005/05/05 14:35:55 serguei Exp $
+
+function [T, P, lambda, Options] = pca_train(X,Options)
+
+if nargin < 2
+  Options  = [];
+end
+
+[N, d] = size(X);
+
+Options.N = N;
+Options.d = d;
+
+DefaultOptions.M = N-1;
+DefaultOptions.X_centering = [];
+DefaultOptions.X_scaling = [];
+DefaultOptions.nPC = inf;
+DefaultOptions.nPC_em = 'PEV';
+DefaultOptions.PEV = 0.95;
+DefaultOptions.F_cl = 0.95;
+
+Options = updstruct(DefaultOptions, Options);
+max_nPC = min(N,d);
+
+if max_nPC == 0
+  error('The maximum possible PC number is 0.');  
+end
+
+if ~isnan(Options.nPC)
+  [X, Options.X_centering, Options.X_scaling] = prepro(X, Options.X_centering, Options.X_scaling);
+
+  Options.nPC_em = '';
+  %if isinf(Options.nPC)
+  %  Options.nPC = max_nPC; 
+  %end
+
+  %if max_nPC < Options.nPC
+  %  WarnMsg = sprintf(['The ordered number of PC''s (%d) is greater than\n' ... 
+  %                   'the maximum possible number of PC''s corresponding\n' ...
+  %                  ' to the non-zero eigenvalues(%d).\n' ... 
+  %                   'Options.nPC set to %d'],Options.nPC,max_nPC,max_nPC);
+  %  if exist('prwarning')
+  %    prwarning(1, WarnMsg);
+  %  else
+  %    warning(WarnMsg);
+  %  end
+  %  Options.nPC = max_nPC;
+  %end  
+
+
+  if N >= d
+    [P,lambda,P] = svd(X'*X);
+    lambda = diag(lambda)';    
+    %Options.rank = nnz(lambda);
+    Options.rank = nnz(lambda > N*lambda(1)*1e-16);
+    lambda(Options.rank+1:end) = 0;
+    PEV = cumsum(lambda);
+    PEV = PEV/PEV(end);    
+    nPC = min(Options.rank, Options.nPC);
+    P = P(:,1:nPC);
+    T = X*P;
+
+  else
+    [T,lambda,T] = svd(X*X');
+    lambda = diag(lambda)';  
+    %Options.rank = nnz(lambda);
+    Options.rank = nnz(lambda > d*lambda(1)*1e-16);
+    lambda(Options.rank+1:end) = 0;
+    PEV = cumsum(lambda);
+    PEV = PEV/PEV(end);    
+    nPC = min(Options.rank, Options.nPC);
+    T = T(:,1:nPC).*repmat(sqrt(lambda(1:nPC)),[N, 1]);
+    P = (X'*T)./repmat(lambda(1:nPC),[d, 1]);
+  end
+
+  if nPC < Options.nPC
+    if ~isinf(Options.nPC)
+      WarnMsg = sprintf(['The ordered number of PC(%d) is greater than the number of PC\n' ... 
+                         'corresponding to the non-zero eigenvalues(%d).\n' ... 
+                         'Options.nPC set to %d'],Options.nPC,nPC,nPC);
+      if exist('prwarning')
+        prwarning(1, WarnMsg);
+      else
+        warning(WarnMsg);
+      end
+    end  
+    Options.nPC = nPC;
+  end
+
+  Options.PEV = PEV(1:Options.nPC);    
+  lambda      = lambda/Options.M;    
+  Options.Tr1 = sum(lambda);
+  Options.Tr2 = sum(lambda.^2);
+  Options.Tr3 = sum(lambda.^3);
+  lambda      = lambda(1:Options.nPC);    
+
+else  
+  nPC_em = Options.nPC_em;
+  [Out,T,P,lambda,Options] = pca_npc(X,Options);
+  Options.nPC = eval(['Out.nPC_' nPC_em]);
+  T = T(:,1:Options.nPC);
+  P = P(:,1:Options.nPC);
+  Options.PEV = Options.PEV(1:Options.nPC);    
+  lambda      = lambda(1:Options.nPC);    
+  
+%  if N >= d
+%    [P,lambda] = svd(X'*X);
+%    lambda = diag(lambda)';    
+%    PEV = cumsum(lambda);
+%    PEV = PEV/PEV(end);    
+%    Options.rank = nnz(lambda);
+%    Options.nPC = min(find(PEV >= Options.PEV));
+%    P = P(:,1:Options.nPC);
+%    T = X*P;
+%
+%  else
+%    [T,lambda] = svd(X*X');
+%    lambda = diag(lambda)';  
+%    PEV = cumsum(lambda);
+%    PEV = PEV/PEV(end);    
+%    Options.rank = nnz(lambda);
+%    Options.nPC = min(find(PEV >= Options.PEV));
+%    T = T(:,1:Options.nPC).*repmat(sqrt(lambda(1:Options.nPC)),[N, 1]);
+%    P = (X'*T)./repmat(lambda(1:Options.nPC),[d, 1]);
+%  end
+%end  
+
+end
+
+
+return;
Index: /hypertools/hypertools/pcaclust.m
===================================================================
--- /hypertools/hypertools/pcaclust.m	(revision 3)
+++ /hypertools/hypertools/pcaclust.m	(revision 3)
@@ -0,0 +1,340 @@
+function clustlist = pcaclust(varargin)
+%
+% PCA Clustering
+%
+%   [clust,f_idx] = pcaclust(X)
+%   [clust,f_idx] = pcaclust(X, Options)
+%   [clust,f_idx] = pcaclust(X, Y)
+%   [clust,f_idx] = pcaclust(X, Y, Options)
+% 
+% X         [N -by- d_X]  data matrix, N samples, d_X variables 
+% Y         [N -by- d_Y]  (soft) labels matrix, N samples, d_Y variables 
+%           if Y is not supplied then unsupervised clustering will be applied
+% Options.
+%   lambda      supervision  level; ==0 -- no supervision, == 1 -- full supervision; 1 by default
+%   perc        percentage of variables which will be shaved at each step; 5 by dehault
+%   nclust      the maximal number of clusters to discover, routine can return less clusters
+%               then nclust (e.g. if the rank of X is less then nclust); 5 by default
+%   sclust      sizes of clusters, scalar or [1- by -nclust] row; 
+%               nan means auto selection; nan by default  
+
+%   X_centering do nothing (==[] or 0), do mean centering (==nan), center around some vaue v (==v); by default  =[]
+%   Y_centering do nothing (==[] or 0), do mean centering (==nan), center around some vaue v (==v); by default  =[]
+%   X_scaling   do nothing (==[] or 1), divide each col by std (==nan), divide by some v (==v); by default =[]
+%               selecting X_scaling == nan is equivalent to target == 'cor'   
+%   Y_scaling   do nothing (=[] or 1), divide each col by std (=nan), divide by some v (=v); by default =[]
+%               Y_scaling does not influence result and was added due to symmetry/compatibility reasons
+%
+%   target      maximization target: 'cov' for covariation, 'cor' for correlation, 
+%               if 'cor' selected then AFTER all preprocessings columns of X will be divided 
+%               by their lengthes; 'cov' by default
+%             
+%
+%   output    ~=0 enables control output, ==0 disables it; 0 by default 
+%
+%
+% 
+% clustlist.    (structure array) 
+%   size    the number of vars in the clust
+%   varind  indices of the vars in the cluster
+%   varsgn  signs of the vars (+1/-1 means that var is correlated/anticorrelated with the first PC)
+%   sgnmean signed mean over vars of the cluster 
+%   corPC   (abs) correlations between the var and the first PC
+%   corSM   (abs) correlations between the var and smean
+%   V_b     variance between vars
+%   V_w     variance within vars
+% 
+%
+
+% Copyright: S.Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+DefaultOptions.lambda = 1;
+DefaultOptions.perc = 5;
+DefaultOptions.nclust = 5;
+DefaultOptions.sclust = nan;
+DefaultOptions.X_centering = [];
+DefaultOptions.Y_centering = [];
+DefaultOptions.X_scaling = [];
+DefaultOptions.Y_scaling = [];
+DefaultOptions.target = 'cov';
+DefaultOptions.output = 0;
+
+[X, Y, Options] = CheckInput(DefaultOptions, varargin{:});
+
+[N, d_X] = size(X);
+[X, Options.X_centering, Options.X_scaling] = prepro(X, Options.X_centering, Options.X_scaling);
+
+if strcmpi(Options.target,'cor')
+  X = X ./repmat(sqrt(sum(X.*X,1)), [size(X,1) 1]);  
+  %X = X ./repmat(std(X,1), [size(X,1) 1]);
+  %X = X ./repmat(std(X,0,1), [N 1]);
+end
+
+if ~isempty(Y) 
+  [Y, Options.Y_centering, Options.Y_scaling] = prepro(Y, Options.Y_centering, []);
+  Q = orth(Y);
+  %Q = Y./repmat(sqrt(sum(Y.*Y,1)), [N 1]);
+  %if Options.lambda < 1;
+  %R = null(Q');
+  %Q = [Q, sqrt(1-Options.lambda)*R];
+  %end  
+else
+  Q = [];
+end
+
+
+clustlist.size    = [];
+clustlist.varind  = [];
+clustlist.varsgn  = [];
+clustlist.sgnmean = [];
+clustlist.corPC   = [];
+clustlist.corSM   = [];
+clustlist.V_b     = [];
+clustlist.V_w     = [];
+clustlist         = clustlist(2:1);
+
+X0 = X; 
+varind = [1:d_X];
+
+for c=1:Options.nclust
+  if Options.output==1
+    disp(['cluster #',num2str(c)]);
+  end
+
+  local_clustlist = Shave(X, Options.perc, Q, Options.lambda, Options.output, c);
+  
+  if isempty(local_clustlist)
+    break;
+  end
+
+
+  clust_size = [local_clustlist(:).size];
+
+  if isnan(Options.sclust(c))
+    X_rnd = X;
+    for j=1:d_X
+      X_rnd(:,j) = X_rnd(randperm(N)',j);
+    end
+ 
+    if Options.output==1
+      disp(['cluster #',num2str(c),' (randomized)']);
+    end
+
+    local_clustlist_rnd = Shave(X_rnd, Options.perc, Q, Options.lambda, Options.output, c);  
+    clust_size_rnd = [local_clustlist_rnd(:).size];
+
+    if ~isequal(length(clust_size),length(clust_size_rnd))
+      error('bug: cluster sizes are not equal for original and randomized datasets');
+    end
+    
+    R = [local_clustlist(:).V_b]./([local_clustlist(:).V_b] + [local_clustlist(:).V_w]);
+    R_rnd = [local_clustlist_rnd(:).V_b]./([local_clustlist_rnd(:).V_b] + [local_clustlist_rnd(:).V_w]);
+
+    [max_gap,ind] = max(R-R_rnd);
+
+  else
+    ind = find(clust_size <= Options.sclust(c));
+    ind = ind(1);
+  end
+
+  if Options.output==1
+    disp(['size of cluster #',num2str(c),': ' num2str(local_clustlist(ind).size)]);
+  end
+  
+  clustlist(c) = local_clustlist(ind);
+
+  local_varind = clustlist(c).varind;
+  clustlist(c).varind = varind(local_varind);
+
+  sgnX0 = X0(:,clustlist(c).varind).*repmat(clustlist(c).varsgn,[N 1]);
+  clustlist(c).sgnmean = mean(sgnX0, 2);
+  clustlist(c).corSM = clustlist(c).sgnmean' * sgnX0;
+  clustlist(c).corSM = clustlist(c).corSM./sqrt(sum(clustlist(c).sgnmean.^2,1) * sum(sgnX0.^2,1));
+  clustlist(c).V_b = var(clustlist(c).sgnmean,1);
+  clustlist(c).V_w = mean(var(sgnX0',1)',1);
+
+  varind(local_varind) = [];
+  d_X = length(varind);
+  if isempty(varind) 
+    break;
+  end
+  
+  sgnmeanX = mean(X(:,local_varind).*repmat(clustlist(c).varsgn,[N 1]),2);
+  X(:,local_varind) = [];
+  %X = X - (clustlist(c).sgnmean*(clustlist(c).sgnmean'*X))/(clustlist(c).sgnmean'*clustlist(c).sgnmean); 
+  X = X - (sgnmeanX*(sgnmeanX'*X))/(sgnmeanX'*sgnmeanX); 
+end
+
+return;
+
+
+%------------------------------------------------------- Shave ---
+function clustlist = Shave(X,perc,Q,lambda,output,cur_clust_num)
+[N,d] = size(X);
+
+X0 = X;
+N0 = N;
+d0 = d;
+varind = [1:d];
+
+if ~isempty(Q)
+  if lambda == 1
+    X = Q'*X;
+    N = size(Q,2);
+  
+  else  
+    X = (1-lambda)*X + lambda*Q*(Q'*X);
+  end
+end
+
+clustlist.size    = [];
+clustlist.varind  = [];
+clustlist.varsgn  = [];
+clustlist.sgnmean = [];
+clustlist.corPC   = [];
+clustlist.corSM   = [];
+clustlist.V_b     = [];
+clustlist.V_w     = [];
+clustlist = clustlist(2:1);
+
+c = 1;
+while 1
+  if length(varind)==1
+    break
+  end
+
+  if N >= d
+    [v,lambda,v] = svds(X'*X,1);
+    lambda = sqrt(lambda);
+    v = sqrt(lambda)*v';
+  else
+    [u,lambda,u] = svds(X*X',1);
+    v = u'*X;
+  end
+
+  varsgn = sign(v);
+  varsgn(varsgn == 0) = 1;
+
+  v = abs(v);
+  corPC = v./sqrt(sum(X.^2,1));
+  
+  [tmp, sortind] = sort(v);
+  ind = sortind(ceil(length(sortind)*perc/100)+1:end);
+  if isempty(ind)
+    ind = sortind(end);
+  end
+
+  d = length(ind);
+  X = X(:,ind);     
+  varind = varind(ind);
+  varsgn = varsgn(ind);
+  corPC  = corPC(ind);
+
+  clustlist(c).size    = d;
+  clustlist(c).varind  = varind;
+  clustlist(c).varsgn  = varsgn;
+  clustlist(c).sgnmean = [];
+  clustlist(c).corPC   = corPC;
+  clustlist(c).corSM   = [];
+  
+  sgnX = X0(:,varind).*repmat(varsgn,[N0 1]);
+  %sgnX = X.*repmat(varsgn,[N 1]);
+  clustlist(c).V_b = var(mean(sgnX,2),1);
+  clustlist(c).V_w = mean(var(sgnX',1)',1);
+
+  if output==1
+    disp(['Looking for the cluster ', num2str(cur_clust_num),'; step ', num2str(c), '; current cluster size: ', num2str(length(varind))]);
+  end
+
+  c = c+1;
+end
+
+return;
+
+
+%-------------------------------------------------- CheckInput ---
+function [X, Y, Options] = CheckInput(DefaultOptions, varargin)
+
+switch nargin
+case 2
+  X = varargin{1};
+  Y = [];
+  Options = [];
+
+case 3
+  X = varargin{1};
+  if isa(varargin{2}, 'struct')  
+    Y = [];
+    Options = varargin{2};
+  else  
+    Y = varargin{2};
+    Options = [];
+  end
+
+case 4
+  X = varargin{1};
+  Y = varargin{2};
+  Options = varargin{3};
+
+otherwise
+  error('Invalid number of the input arguments');
+end
+
+Options = updstruct(DefaultOptions, Options);
+
+if isempty(X)
+  error('Input matrix X is empty');
+end
+
+[N_X, d_X] = size(X);
+
+if ~isempty(Y) & Options.lambda ~= 0
+  [N_Y,d_Y] = size(Y);
+  if N_Y ~= N_X
+    error('size(X,1) must be equal to size(Y,1)');  
+  end
+else
+  Y = [];
+  Options.lambda = 0;
+end
+
+N = N_X;
+
+if Options.perc <= 0 | Options.perc >= 100
+  error('Options.perc must be >0, <100');  
+end
+
+if floor(Options.nclust) ~= Options.nclust| Options.nclust < 1 
+  error('Options.nclust must be integer, >=1');  
+end
+
+if length(Options.sclust(:)) ~= 1 & length(Options.sclust(:)) ~= Options.nclust
+  error('length(Options.nclust) must be =1 or =Options.nclust');  
+end
+
+if any((floor(Options.sclust) ~= Options.sclust | Options.sclust < 1) & ~isnan(Options.sclust)) 
+  error('Options.sclust must be integer, >=1 or nan');  
+end
+
+if length(Options.sclust) == 1;
+  Options.sclust = repmat(Options.sclust,[1, Options.nclust]);
+else
+  Options.sclust = Options.sclust(:).';
+end
+
+
+if ~strcmpi(Options.target,'cov') & ~strcmpi(Options.target,'cor')
+  error('Options.target must be ''cov'' or ''cor''');  
+end
+
+if length(Options.output) ~= 1 
+  error('Options.output must be scalar');  
+end
+
+
+return
+
+
+
Index: /hypertools/hypertools/pcashave.m
===================================================================
--- /hypertools/hypertools/pcashave.m	(revision 3)
+++ /hypertools/hypertools/pcashave.m	(revision 3)
@@ -0,0 +1,346 @@
+%pcashave PCA shaving algorithm
+%
+%  [clust,f_idx] = pcaclust(X)
+%  [clust,f_idx] = pcaclust(X, Options)
+%  [clust,f_idx] = pcaclust(X, Y)
+%  [clust,f_idx] = pcaclust(X, Y, Options)
+% 
+% INPUT
+%  X         [N -by- d_X]  data matrix, N samples, d_X variables 
+%  Y         [N -by- d_Y]  (soft) labels matrix, N samples, d_Y variables 
+%           if Y is not supplied then unsupervised clustering will be applied
+%  Options.
+%   lambda      supervision  level; ==0 -- no supervision, == 1 -- full supervision; 1 by default
+%   perc        percentage of variables which will be shaved at each step; 5 by dehault
+%   nclust      the maximal number of clusters to discover, routine can return less clusters
+%               then nclust (e.g. if the rank of X is less then nclust); 5 by default
+%   sclust      sizes of clusters, scalar or [1- by -nclust] row; 
+%               nan means auto selection; nan by default  
+%
+%   X_centering do nothing (==[] or 0), do mean centering (==nan), center around some vaue v (==v); by default  =[]
+%   Y_centering do nothing (==[] or 0), do mean centering (==nan), center around some vaue v (==v); by default  =[]
+%   X_scaling   do nothing (==[] or 1), divide each col by std (==nan), divide by some v (==v); by default =[]
+%               selecting X_scaling == nan is equivalent to target == 'cor'   
+%   Y_scaling   do nothing (=[] or 1), divide each col by std (=nan), divide by some v (=v); by default =[]
+%               Y_scaling does not influence result and was added due to symmetry/compatibility reasons
+%
+%   target      maximization target: 'cov' for covariation, 'cor' for correlation, 
+%               if 'cor' selected then AFTER all preprocessings columns of X will be divided 
+%               by their lengthes; 'cov' by default
+%             
+%
+%   output    ~=0 enables control output, ==0 disables it; 0 by default 
+%
+% OUTPUT
+%  clustlist.    (structure array) 
+%   size    the number of vars in the clust
+%   varind  indices of the vars in the cluster
+%   varsgn  signs of the vars (+1/-1 means that var is correlated/anticorrelated with the first PC)
+%   sgnmean signed mean over vars of the cluster 
+%   corPC   (abs) correlations between the var and the first PC
+%   corSM   (abs) correlations between the var and smean
+%   V_b     variance between vars
+%   V_w     variance within vars
+%
+% DESCRIPTION
+% Performes backword elimination procedures to find the goups (clusters) of correlated/covariated
+% variables. Elimination is based on the variables ranking according their participation in the
+% the first PC loading. 
+
+
+% Copyright: S.Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: pcashave.m,v 1.2 2003/12/09 13:05:35 pavel Exp $
+
+function clustlist = pcashave(varargin)
+
+	DefaultOptions.lambda = 1;
+	DefaultOptions.perc = 5;
+	DefaultOptions.nclust = 5;
+	DefaultOptions.sclust = nan;
+	DefaultOptions.X_centering = [];
+	DefaultOptions.Y_centering = [];
+	DefaultOptions.X_scaling = [];
+	DefaultOptions.Y_scaling = [];
+	DefaultOptions.target = 'cov';
+	DefaultOptions.output = 0;
+
+	[X, Y, Options] = CheckInput(DefaultOptions, varargin{:});
+
+	[N, d_X] = size(X);
+	[X, Options.X_centering, Options.X_scaling] = prepro(X, Options.X_centering, Options.X_scaling);
+
+	if strcmpi(Options.target,'cor')
+		X = X ./repmat(sqrt(sum(X.*X,1)), [size(X,1) 1]);  
+		%X = X ./repmat(std(X,1), [size(X,1) 1]);
+		%X = X ./repmat(std(X,0,1), [N 1]);
+	end
+
+	if ~isempty(Y) 
+		[Y, Options.Y_centering, Options.Y_scaling] = prepro(Y, Options.Y_centering, []);
+		Q = orth(Y);
+		%Q = Y./repmat(sqrt(sum(Y.*Y,1)), [N 1]);
+		%if Options.lambda < 1;
+		%R = null(Q');
+		%Q = [Q, sqrt(1-Options.lambda)*R];
+		%end  
+	else
+		Q = [];
+	end
+
+
+	clustlist.size    = [];
+	clustlist.varind  = [];
+	clustlist.varsgn  = [];
+	clustlist.sgnmean = [];
+	clustlist.corPC   = [];
+	clustlist.corSM   = [];
+	clustlist.V_b     = [];
+	clustlist.V_w     = [];
+	clustlist         = clustlist(2:1);
+
+	X0 = X; 
+	varind = [1:d_X];
+
+	for c=1:Options.nclust
+		if Options.output==1
+			disp(['cluster #',num2str(c)]);
+		end
+
+		local_clustlist = Shave(X, Options.perc, Q, Options.lambda, Options.output, c);
+		
+		if isempty(local_clustlist)
+			break;
+		end
+
+
+		clust_size = [local_clustlist(:).size];
+
+		if isnan(Options.sclust(c))
+			X_rnd = X;
+			for j=1:d_X
+				X_rnd(:,j) = X_rnd(randperm(N)',j);
+			end
+			
+			if Options.output==1
+				disp(['cluster #',num2str(c),' (randomized)']);
+			end
+
+			local_clustlist_rnd = Shave(X_rnd, Options.perc, Q, Options.lambda, Options.output, c);  
+			clust_size_rnd = [local_clustlist_rnd(:).size];
+
+			if ~isequal(length(clust_size),length(clust_size_rnd))
+				error('bug: cluster sizes are not equal for original and randomized datasets');
+			end
+			
+			R = [local_clustlist(:).V_b]./([local_clustlist(:).V_b] + [local_clustlist(:).V_w]);
+			R_rnd = [local_clustlist_rnd(:).V_b]./([local_clustlist_rnd(:).V_b] + [local_clustlist_rnd(:).V_w]);
+
+			[max_gap,ind] = max(R-R_rnd);
+
+		else
+			ind = find(clust_size <= Options.sclust(c));
+			ind = ind(1);
+		end
+
+		if Options.output==1
+			disp(['size of cluster #',num2str(c),': ' num2str(local_clustlist(ind).size)]);
+		end
+		
+		clustlist(c) = local_clustlist(ind);
+
+		local_varind = clustlist(c).varind;
+		clustlist(c).varind = varind(local_varind);
+
+		sgnX0 = X0(:,clustlist(c).varind).*repmat(clustlist(c).varsgn,[N 1]);
+		clustlist(c).sgnmean = mean(sgnX0, 2);
+		clustlist(c).corSM = clustlist(c).sgnmean' * sgnX0;
+		clustlist(c).corSM = clustlist(c).corSM./sqrt(sum(clustlist(c).sgnmean.^2,1) * sum(sgnX0.^2,1));
+		clustlist(c).V_b = var(clustlist(c).sgnmean,1);
+		clustlist(c).V_w = mean(var(sgnX0',1)',1);
+
+		varind(local_varind) = [];
+		d_X = length(varind);
+		if isempty(varind) 
+			break;
+		end
+		
+		sgnmeanX = mean(X(:,local_varind).*repmat(clustlist(c).varsgn,[N 1]),2);
+		X(:,local_varind) = [];
+		%X = X - (clustlist(c).sgnmean*(clustlist(c).sgnmean'*X))/(clustlist(c).sgnmean'*clustlist(c).sgnmean); 
+		X = X - (sgnmeanX*(sgnmeanX'*X))/(sgnmeanX'*sgnmeanX); 
+	end
+
+	return;
+
+
+%------------------------------------------------------- Shave ---
+function clustlist = Shave(X,perc,Q,lambda,output,cur_clust_num)
+	[N,d] = size(X);
+
+	X0 = X;
+	N0 = N;
+	d0 = d;
+	varind = [1:d];
+
+	if ~isempty(Q)
+		if lambda == 1
+			X = Q'*X;
+			N = size(Q,2);
+			
+		else  
+			X = (1-lambda)*X + lambda*Q*(Q'*X);
+		end
+	end
+
+	clustlist.size    = [];
+	clustlist.varind  = [];
+	clustlist.varsgn  = [];
+	clustlist.sgnmean = [];
+	clustlist.corPC   = [];
+	clustlist.corSM   = [];
+	clustlist.V_b     = [];
+	clustlist.V_w     = [];
+	clustlist = clustlist(2:1);
+
+	c = 1;
+	while 1
+		if length(varind)==1
+			break
+		end
+
+		if N >= d
+			[v,lambda,v] = svds(X'*X,1);
+			lambda = sqrt(lambda);
+			v = sqrt(lambda)*v';
+		else
+			[u,lambda,u] = svds(X*X',1);
+			v = u'*X;
+		end
+
+		varsgn = sign(v);
+		varsgn(varsgn == 0) = 1;
+
+		v = abs(v);
+		corPC = v./sqrt(sum(X.^2,1));
+		
+		[tmp, sortind] = sort(v);
+		ind = sortind(ceil(length(sortind)*perc/100)+1:end);
+		if isempty(ind)
+			ind = sortind(end);
+		end
+
+		d = length(ind);
+		X = X(:,ind);     
+		varind = varind(ind);
+		varsgn = varsgn(ind);
+		corPC  = corPC(ind);
+
+		clustlist(c).size    = d;
+		clustlist(c).varind  = varind;
+		clustlist(c).varsgn  = varsgn;
+		clustlist(c).sgnmean = [];
+		clustlist(c).corPC   = corPC;
+		clustlist(c).corSM   = [];
+		
+		sgnX = X0(:,varind).*repmat(varsgn,[N0 1]);
+		%sgnX = X.*repmat(varsgn,[N 1]);
+		clustlist(c).V_b = var(mean(sgnX,2),1);
+		clustlist(c).V_w = mean(var(sgnX',1)',1);
+
+		if output==1
+			disp(['Looking for the cluster ', num2str(cur_clust_num),'; step ', num2str(c), '; current cluster size: ', num2str(length(varind))]);
+		end
+
+		c = c+1;
+	end
+
+	return;
+
+
+%-------------------------------------------------- CheckInput ---
+function [X, Y, Options] = CheckInput(DefaultOptions, varargin)
+
+	switch nargin
+	 case 2
+	  X = varargin{1};
+	  Y = [];
+	  Options = [];
+
+	 case 3
+	  X = varargin{1};
+	  if isa(varargin{2}, 'struct')  
+		  Y = [];
+		  Options = varargin{2};
+	  else  
+		  Y = varargin{2};
+		  Options = [];
+	  end
+
+	 case 4
+	  X = varargin{1};
+	  Y = varargin{2};
+	  Options = varargin{3};
+
+	 otherwise
+	  error('Invalid number of the input arguments');
+	end
+
+	Options = updstruct(DefaultOptions, Options);
+
+	if isempty(X)
+		error('Input matrix X is empty');
+	end
+
+	[N_X, d_X] = size(X);
+
+	if ~isempty(Y) & Options.lambda ~= 0
+		[N_Y,d_Y] = size(Y);
+		if N_Y ~= N_X
+			error('size(X,1) must be equal to size(Y,1)');  
+		end
+	else
+		Y = [];
+		Options.lambda = 0;
+	end
+
+	N = N_X;
+
+	if Options.perc <= 0 | Options.perc >= 100
+		error('Options.perc must be >0, <100');  
+	end
+
+	if floor(Options.nclust) ~= Options.nclust| Options.nclust < 1 
+		error('Options.nclust must be integer, >=1');  
+	end
+
+	if length(Options.sclust(:)) ~= 1 & length(Options.sclust(:)) ~= Options.nclust
+		error('length(Options.nclust) must be =1 or =Options.nclust');  
+	end
+
+	if any((floor(Options.sclust) ~= Options.sclust | Options.sclust < 1) & ~isnan(Options.sclust)) 
+		error('Options.sclust must be integer, >=1 or nan');  
+	end
+
+	if length(Options.sclust) == 1;
+		Options.sclust = repmat(Options.sclust,[1, Options.nclust]);
+	else
+		Options.sclust = Options.sclust(:).';
+	end
+
+
+	if ~strcmpi(Options.target,'cov') & ~strcmpi(Options.target,'cor')
+		error('Options.target must be ''cov'' or ''cor''');  
+	end
+
+	if length(Options.output) ~= 1 
+		error('Options.output must be scalar');  
+	end
+
+
+	return
+
+
+
Index: /hypertools/hypertools/plot_cca.m
===================================================================
--- /hypertools/hypertools/plot_cca.m	(revision 3)
+++ /hypertools/hypertools/plot_cca.m	(revision 3)
@@ -0,0 +1,46 @@
+% PLOT_CCA Superimpose training and test data projected by CCA
+%
+%    PLOT_CCA(TR,TS)
+%
+% INPUT
+%   TR    training set
+%   TS    test set
+%
+% DESCRIPTION
+% This routine visualises differences between training and test sets.
+% Canonical correlation mapping is computed on the training dataset.  Both
+% training and testing dataset are projected into the factor space by the
+% trained mapping and the scatter plots are displayed. Examples in the
+% training set are drawn with darker and thicker markers than in the test.
+
+% $Id: plot_cca.m,v 1.3 2005/11/02 12:35:09 pavel Exp $
+
+% Copyright: P. Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function plot_cca(tr,ts)
+	
+	% compute the cca mapping
+	w=ccam(tr);
+	
+	% plot the test data projected in the factor space
+	fh=scatterdui(ts*w);
+
+	hh=findobj(fh,'type','axes');
+	hts_classes=findobj(hh,'type','line');
+	
+	hold on
+	
+	% plot the projected training data
+	fh=scatterd(tr*w);
+	htr_classes=findobj(fh,'type','line');
+	for i=1:length(htr_classes)
+	    col=get(htr_classes(i),'color');
+	    set(htr_classes(i),'color',0.6*col); % darken
+	end
+	set(htr_classes,'markersize',10,'linewidth',3);
+
+	
+	return
+	
Index: /hypertools/hypertools/plot_gldb_groups.m
===================================================================
--- /hypertools/hypertools/plot_gldb_groups.m	(revision 3)
+++ /hypertools/hypertools/plot_gldb_groups.m	(revision 3)
@@ -0,0 +1,62 @@
+% PLOT_GLDB_GROUPS Plot groups selected by GLDB
+%
+%   PLOT_GLDB_GROUPS(A,W)
+%   plot_gldb_groups(a,L,H)
+%
+% INPUT
+%   A   - spectral dataset
+%   W   - trained GLDB mapping
+%   L,H - vectors with lower-upper indices of bands forming groups
+%
+% DESCRIPTION
+% This routine plots the first spectrum from the supplied dataset A
+% and highlights all groups of bands, defined by the G:DB mapping W.
+% Successive groups are denoted by changing color.
+%
+% SEE ALSO
+% GLDB, GLDBM_MULTI NLGLDBM
+
+function plot_gldb_groups(a,par1,par2,par3)
+
+   if isa(par1,'mapping')
+      l=par1.data.l;
+      u=par1.data.u;
+      if exist('par2','var')
+	 t=par2+abs(min(par2));
+	 crit=t./sum(t);
+	 %      colormap(colmap);
+      end
+   else
+      l=par1; u=par2;
+      if exist('par3','var')
+	 t=par3+abs(min(par3));
+	 crit=t./sum(t);
+	 %      colormap(colmap);
+      end
+   end
+   clf
+   colmap=colormap; % default map
+   
+   col='g';
+   for i=1:length(l)
+      
+      bands=l(i):u(i);
+      values=+a(1,bands);
+      bands=[l(i)-0.5 bands u(i)+0.5];
+      values=[values(1) values values(length(values))];
+      h=patch([max(bands) min(bands) sort(bands)],[0 0 values],col);
+
+      if exist('crit','var')
+	 ind=min(find(crit>=crit(i)));
+	 set(h,'FaceColor',colmap(end-ind,:));
+      else
+	 if strcmp(col,'g')
+	    col='k';
+	 else
+	    col='g';
+	 end
+      end
+   end
+   
+   return
+   
Index: /hypertools/hypertools/plots.m
===================================================================
--- /hypertools/hypertools/plots.m	(revision 3)
+++ /hypertools/hypertools/plots.m	(revision 3)
@@ -0,0 +1,51 @@
+% PLOTS Plot spectra
+%
+%  PLOTS(A,COL)
+% 
+% INPUT
+%  A    dataset
+%  COL  linecolor-symbol-linestyle (e.g. 'r:--')
+% 
+% DESCRIPTION
+% This routine plots spectra from dataset A. It uses information from
+% A.USER field to put correct values on the X (wavelengths/wavenumbers)
+% axis.  If COL parameter is not supplied then automatically selected
+% linecolor-symbol-linestyle will be used to plot spectra of each class (in
+% the case of labelled dataset)
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: plots.m,v 1.12 2005/11/02 14:56:31 pavel Exp $
+
+function plots(a,col)
+
+    colors={'b','r','k','g','m','b--','r--','k--','g--','m--','b-.','r-.', ...
+	    'k-.','g-.','m-.','b:','r:','k:','g:','m:','b+','r+','k+','g+','m+','bo','ro','ko','go','mo'};
+
+    if isa(a,'dataset')
+	lab=renumlab(getlab(a));
+	cls=unique(lab);
+	if length(cls)==1 & cls(1)==0
+	    lab=ones(1,size(a,1));
+	    cls=1;
+	end
+    else
+	lab=ones(1,size(a,1));
+	cls=1;
+    end
+
+    a=+a;
+    hold on
+    if exist('col','var')
+	for i=1:size(a,1)
+	    plot(a(i,:),col);
+	end
+    else
+	for i=1:size(a,1)
+	    plot(a(i,:),colors{lab(i)});
+	end
+    end
+
+    return
Index: /hypertools/hypertools/pls_apply.m
===================================================================
--- /hypertools/hypertools/pls_apply.m	(revision 3)
+++ /hypertools/hypertools/pls_apply.m	(revision 3)
@@ -0,0 +1,61 @@
+%pls_apply  Partial Least Squares (applying)
+%
+%  Y = pls_apply(X,B)
+%  Y = pls_apply(X,B,Options)
+%
+% INPUT
+%  X       [N -by- d_X]    the input  data matrix, N samples, d_X variables
+%  B       [d_X -by- d_Y]  regression matrix: Y_new = X_new*B
+%                         (X_new here after preprocessing, Y_new before un-preprocessing;
+%                         preprocessing and un-preprocessing could be done automatically
+%                         (than Options contains info about preprocessing) or manually)
+%  Options  structure returned by pls_train (if not supplied then will be no preprocessing performed)  
+%
+% OUTPUT
+%  Y [N -by- d_Y]    the output data matrix, N samples, d_Y variables
+%
+% DESCRIPTION
+% Applys PLS (Partial Least Squares) regression model
+%
+% SEE ALSO
+% pls_train
+
+% Copyright: S.Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: pls_apply.m,v 1.6 2003/11/28 14:50:12 serguei Exp $
+
+function Y = pls_apply(X,B,Options)
+
+if nargin < 3
+  Options  = [];
+end
+
+DefaultOptions.X_centering = [];
+DefaultOptions.Y_centering = [];
+DefaultOptions.X_scaling = [];
+DefaultOptions.Y_scaling = [];
+
+Options = updstruct(DefaultOptions, Options);
+
+[N, d_X]    = size(X);
+[d_XB, d_Y, M] = size(B);
+
+if d_X ~= d_XB
+  error('size(X,2) must be equal to size(B,1)');
+end
+
+X = prepro(X, Options.X_centering, Options.X_scaling);
+Y = zeros(N,d_Y,M);
+for i=1:M
+  Y(:,:,i) = prepro(X*B(:,:,i), Options.Y_centering, Options.Y_scaling, -1);
+end
+
+return;
+
+
+
+
+
+
Index: /hypertools/hypertools/pls_example.m
===================================================================
--- /hypertools/hypertools/pls_example.m	(revision 3)
+++ /hypertools/hypertools/pls_example.m	(revision 3)
@@ -0,0 +1,99 @@
+% loading dataset
+data_train = load('mfeat-pix');
+data_train = data_train.a;
+data_train.prior = [ones(1,getsize(data_train,3))/getsize(data_train,3)];
+[data_train, data_test] = gendat(data_train,0.75);
+
+
+%------------------------------------------ low-level routines
+% preparation
+% create membership matrix
+Y_train = zeros(size(data_train,1),size(getlablist(data_train),1));
+Y_train(sub2ind(size(Y_train),(1:size(Y_train,1))',data_train.nlab)) = 1; 
+% extract data
+X_train = +data_train;
+
+% training
+% nan means: auto-centering
+Options.X_centering = nan; 
+Options.Y_centering = nan; 
+
+% inf means: as many as possible
+Options.maxLV = inf;
+
+% SIMPLS by default
+%Options.method = 'NIPALS';
+
+[B,XRes,YRes,Options] = pls_train(X_train,Y_train,Options);
+
+% mapping matrix
+R = XRes.R; 
+
+% mapped training dataset (feature extraction)
+T_train = XRes.T; % transformed X
+data_train_pls_fe = setdata(data_train,T_train);
+
+% mapped test dataset (feature extraction)
+X_test = +data_test;
+T_test = pls_trans(X_test,R,Options);
+data_test_pls_fe = setdata(data_test,T_test);
+
+
+
+% how many latent variables use for regression
+n = 20;
+
+% regression on training dataset
+Y_train_est = pls_apply(X_train,B(:,:,n),Options);
+data_train_pls_reg = setdata(data_train,Y_train_est);
+
+
+% regression on test dataset
+X_test = +data_test;
+Y_test_est = pls_apply(X_test,B(:,:,n),Options);
+data_test_pls_reg = setdata(data_test,Y_test_est);
+
+
+%------------------------------------------ mappings
+%w_sc = scalem(data_train,'mean');
+w_sc = scalem(data_train);
+
+% inf means: as many as possible
+maxLV = inf;
+% SIMPLS by default
+%method = 'NIPALS';
+
+w_plsm = plsm([],maxLV);
+%w_plsm = plsm([],maxLV,method);
+w_plsm = data_train*w_sc*w_plsm;
+data_train_pls_fe2  = data_train*w_sc*w_plsm;
+data_test_pls_fe2   = data_test*w_sc*w_plsm;
+
+w_plsr = plsr([],maxLV)
+%w_plsr = plsr([],maxLV,method);
+w_plsr = data_train*w_sc*w_plsr;
+
+% how to change the number of latent variables for regression
+d = w_plsr.data;
+d.n = 20;
+w_plsr.data = d;
+
+data_train_pls_reg2  = data_train*w_sc*w_plsr;
+data_test_pls_reg2   = data_test*w_sc*w_plsr;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /hypertools/hypertools/pls_train.m
===================================================================
--- /hypertools/hypertools/pls_train.m	(revision 3)
+++ /hypertools/hypertools/pls_train.m	(revision 3)
@@ -0,0 +1,352 @@
+%pls_train Partial Least Squares (training)
+%
+%  [B,XRes,YRes,Options] = pls_train(X,Y)
+%  [B,XRes,YRes,Options] = pls_train(X,Y,Options)
+%
+% INPUT
+%  X       [N -by- d_X]  the training (input)  data matrix, N samples, d_X variables
+%  Y       [N -by- d_Y]  the training (output) data matrix, N samples, d_Y variables
+%
+%  Options.
+%   maxLV        maximal number of latent variables (will be corrected if > rank(X)); 
+%                maxLV=inf means maxLV=min(N,d_X) -- theoretical maximum number of LV; 
+%                by default =inf
+%   method       'NIPALS' or 'SIMPLS'; by default ='SIMPLS'
+%
+%   X_centering  do nothing (=[] or 0), do mean centering (=nan), center around some vaue v (=v); 
+%                by default  =[]
+%   Y_centering  do nothing (=[] or 0), do mean centering (=nan), center around some vaue v (=v); 
+%                by default  =[]
+%   X_scaling    do nothing (=[] or 1), divide each col by std (=nan), divide by some v (=v); 
+%                by default =[]
+%   Y_scaling    do nothing (=[] or 1), divide each col by std (=nan), divide by some v (=v); 
+%                by default =[]
+%
+% OUTPUT
+%  B      [d_X -by- d_Y -by- nLV]  collection of regression matrices: Y_new = X_new*B(:,:,n)
+%         represents regression on the first n latent variables
+%         (X_new here after preprocessing, Y_new before un-preprocessing)
+%  XRes.
+%   ssq  [1 -by- nLV]    the part of explaind sum of squares of (preprocessed) X matrix
+%   T    [N -by- nLV]    scores   (transformed (preprocessed) X)
+%   R    [d_X -by- nLV]  weights  (transformation matrix)
+%   P    [d_X -by- nLV]  loadings (back-transformation matrix)
+%                        P(:,k) are the regression coef of (preprocessed) X on T(:,k)
+%   W    [d_X -by- nLV]  local weights (local transformation matrix); ONLY FOR NIPALS
+%   V    [d_X -by- nLV]  first k columns of this matrix are the orthornormal basis of the
+%                        space spanned by k first columns of P; ONLY FOR SIMPLS
+%  YRes.
+%   ssq  [1 -by- nLV]    the part of explained sum of squares of (preprocessed) Y matrix
+%   U    [N -by- nLV]    scores   (transformed (preprocessed) Y)
+%   Q    [d_Y -by- nLV]  weights  (transformation matrix)
+%   C    [d_Y -by- nLV]  C(:,k) are the regression coeff of (preprocessed) Y on T(:,k)
+%   bin  [1 -by- nLV]    bin(k) is the regression coeff of U(:,k) on T(:,k)
+%
+%  Options. contains the same fields as in input, but the values can be changed 
+%           (e.g. after mean centering X_centering = mean(X,1))
+%
+%
+% DESCRIPTION
+% Trains PLS (Partial Least Squares) regression model
+%
+% Relations between matrices (X end Y are assumed to be preprocessed):
+% NIPALS:
+% T = X*R (columns of T are orthogonal)
+% R = W*inv(P'*W)
+% P = X'*T*inv(T'*T)
+% U = Y*Q - T*(C'*Q-tril(C'*Q))
+% C = Y'*T*inv(T'*T) = Q*diag(bin)
+% bin = sqrt(diag(T'*Y*Y'*T))'*inv(T'*T))
+% B = R*C' = W*inv(P'*W)*C'
+%
+% SIMPLS:
+% T = X*R (columns of T are orthonormal)
+% P = X'*T
+% U = Y*Q
+% C = Y'*T = Q*diag(bin)
+% bin = sqrt(diag(T'*Y*Y'*T))'
+% B = R*C'
+%
+% BOTH:
+% T_new = X_new*R
+% Y_new = X_new*B
+%  
+% SEE ALSO
+% pls_apply, pls_trans
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: pls_train.m,v 1.10 2006/08/11 09:50:56 serguei Exp $
+
+function [B, XRes, YRes, Options] = pls_train(X,Y,Options)
+
+[N_X, d_X] = size(X);
+[N_Y, d_Y] = size(Y);
+
+if N_X ~= N_Y
+  error('size(X,1) must be equal to size(Y,1)');
+else
+  N = N_X;
+end
+
+if nargin < 3
+  Options  = [];
+end
+
+DefaultOptions.X_centering = [];
+DefaultOptions.Y_centering = [];
+DefaultOptions.X_scaling = [];
+DefaultOptions.Y_scaling = [];
+DefaultOptions.maxLV = inf;
+DefaultOptions.method = 'SIMPLS';
+
+Options = updstruct(DefaultOptions, Options);
+
+if isinf(Options.maxLV)
+  Options.maxLV = min(N,d_X);
+elseif Options.maxLV > min(N,d_X)
+  error('PLS: The number of LV(s) cannot be greater then min(N,d_X)');
+end
+
+[X, Options.X_centering, Options.X_scaling] = prepro(X, Options.X_centering, Options.X_scaling);
+[Y, Options.Y_centering, Options.Y_scaling] = prepro(Y, Options.Y_centering, Options.Y_scaling);
+
+ssq_X = sum(X(:).^2);
+ssq_Y = sum(Y(:).^2);
+
+B = zeros(d_X,d_Y,Options.maxLV);
+XRes.ssq = zeros(1,Options.maxLV);
+XRes.T   = zeros(N,Options.maxLV);
+XRes.R   = zeros(d_X,Options.maxLV);
+XRes.P   = zeros(d_X,Options.maxLV);
+XRes.W   = [];
+XRes.V   = [];
+
+YRes.ssq = zeros(1,Options.maxLV);  
+YRes.U   = zeros(N,Options.maxLV);  
+YRes.Q   = zeros(d_Y,Options.maxLV);
+YRes.C   = zeros(d_Y,Options.maxLV);
+YRes.bin = zeros(1,Options.maxLV);  
+
+ev = zeros(1,Options.maxLV);
+nLV = Options.maxLV;
+opts.disp   = 0;
+opts.issym  = 1;
+opts.isreal = 1;
+
+switch upper(Options.method)
+case 'NIPALS'
+  XRes.W = zeros(d_X,Options.maxLV);
+  for LV = 1:Options.maxLV
+    S = X'*Y;
+    if d_X <= d_Y
+      if d_X > 1
+        [w, ev(LV)] = eigs(S*S',1,'LA',opts);
+      else
+        w = 1;
+        ev(LV) = S*S';
+      end
+      
+      t = X*w;
+  	  t2 = (t'*t);
+      proj = t/t2;
+  	  p = X'*proj;
+
+      c = Y'*proj;
+      bin = norm(c);  %bin = sqrt(ev)/t2:
+      q = c/bin;
+      u = Y*q;
+
+    else
+      if d_Y > 1
+        [q, ev(LV)] = eigs(S'*S,1,'LA',opts);
+      else
+        q = 1;
+        ev(LV) = S'*S;
+      end
+      u = Y*q;
+
+      w = X'*u;
+  	  w = w/norm(w);
+  	  t = X*w;
+   	  t2 = (t'*t);
+      proj = t/t2;
+  	  p = X'*proj;
+      
+      bin = u'*proj;  %bin = sqrt(ev)/t2:
+      c = q*bin;
+  	end
+
+	  if LV == 1 
+      if ev(LV) == 0
+        error('PLS: Rank of the covariation matrix X''*Y is zero.');
+      end  
+	  elseif ev(LV) <= 1e-16*ev(1)
+      nLV = LV-1;
+      WarnMsg = sprintf(['\nPLS: Rank of the covariation matrix X''*Y is exausted ' ...
+                         'after removing %d Latent Variable(s).\n'...
+                         'Results only for the %d LV(s) will be returned'],nLV,nLV);
+      if exist('prwarning')
+        prwarning(1, WarnMsg);
+      else
+        warning(WarnMsg);
+      end
+      break;
+	  end
+
+    %R = W*inv(P'*W)
+    %the next portion of the code makes use of the fact taht P'*W is the upper triangle matrix:
+    % 
+    %if LV == 1
+    %  InvPTW(1,1) = 1/(p'*w);
+    %  r = w*InvPTW(1,1);
+    %else
+    %  InvPTW(1:LV,LV) = [(-InvPTW(1:LV-1,1:LV-1)*(XRes.P(:,1:LV-1)'*w)); 1]/(p'*w);
+    %  r = [XRes.W(:,1:LV-1), w] * InvPTW(1:LV,LV);
+    %end  
+    % 
+    %some optimization of the above code (notice that ones(m,0)*ones(0,n) == zeros(m,n)):
+    %
+    r = (w - (XRes.R(:,1:LV-1)*(XRes.P(:,1:LV-1)'*w)))/(p'*w);
+
+    B(:,:,LV) = r*c';
+
+  	XRes.ssq(:,LV) = t2*(p'*p)/ssq_X;
+  	XRes.T(:,LV)   = t;
+	  XRes.R(:,LV)   = r;
+  	XRes.P(:,LV)   = p;
+  	XRes.W(:,LV)   = w;
+         
+	  YRes.ssq(:,LV) = t2*(bin.^2)/ssq_Y;
+  	YRes.U(:,LV)   = u;
+  	YRes.Q(:,LV)   = q;
+  	YRes.C(:,LV)   = c;
+  	YRes.bin(:,LV) = bin;
+	  
+  	X = X - t*p';
+  	Y = Y - t*c';
+  end
+
+  if nLV < Options.maxLV
+    XRes.W = XRes.W(:,1:nLV);
+  end
+
+case 'SIMPLS'
+  XRes.V = zeros(d_X,Options.maxLV);
+  S = X'*Y;
+  for LV = 1:Options.maxLV
+	  if d_X <= d_Y
+		  if d_X > 1
+        [r, ev(LV)] = eigs(S*S',1,'LA',opts);
+      else
+        r = 1;
+        ev(LV) = S*S';
+      end
+		  
+      t = X*r;
+		  norm_t = norm(t);
+		  r = r/norm_t;
+		  t = t/norm_t;
+		  p = X'*t;
+
+		  c = Y'*t;      %c = S'*r;
+		  bin = norm(c); %bin = sqrt(ev)/norm_t:
+		  q = c/bin;
+		  u = Y*q;
+
+    else
+      if d_Y > 1
+        [q, ev(LV)] = eigs(S'*S,1,'LA',opts);
+      else
+        q = 1;
+        ev(LV) = S'*S;
+      end
+      r = S*q;
+		  t = X*r;
+		  norm_t = norm(t);
+		  r = r/norm_t;
+		  t = t/norm_t;
+		  p = X'*t;
+
+			u = Y*q;
+		  bin = u'*t;    %bin = ev/norm_t:
+		  c = q*bin;
+	  end
+
+	  if LV == 1
+		  if ev(LV) == 0
+        error('PLS: Rank of the covariation matrix X''*Y is zero.');
+      else
+        v = p;
+      end  
+	  elseif ev(LV) <= 1e-16*ev(1)
+      nLV = LV-1;
+      WarnMsg = sprintf(['\nPLS: Rank of the covariation matrix X''*Y is exausted ' ...
+                         'after removing %d Latent Variable(s).\n'...
+                         'Results only for the %d LV(s) will be returned'],nLV,nLV);
+      if exist('prwarning')
+        prwarning(1, WarnMsg);
+      else
+        warning(WarnMsg);
+      end
+      break;
+    else
+  	  v = p - XRes.V(:,1:LV-1)*(XRes.V(:,1:LV-1)'*p);
+	  end
+
+	  v = v/norm(v);
+
+    B(:,:,LV) = r*c';	  
+
+    XRes.ssq(:,LV) = (p'*p)/ssq_X;
+	  XRes.T(:,LV)   = t;
+	  XRes.R(:,LV)   = r;
+	  XRes.P(:,LV)   = p;
+	  XRes.V(:,LV)   = v;
+
+	  YRes.ssq(:,LV) = (bin.^2)/ssq_Y;
+	  YRes.U(:,LV)   = u;
+	  YRes.Q(:,LV)   = q;
+	  YRes.C(:,LV)   = c;
+	  YRes.bin(:,LV) = bin;
+	  
+	  S = S - v*(v'*S);
+  end
+
+  if nLV < Options.maxLV
+    XRes.V = XRes.V(:,1:nLV);
+  end
+end
+
+if nLV < Options.maxLV
+  B = B(:,:,1:nLV);
+
+  XRes.ssq = XRes.ssq(:,1:nLV);
+  XRes.T   = XRes.T(:,1:nLV);  
+  XRes.R   = XRes.R(:,1:nLV);    
+  XRes.P   = XRes.P(:,1:nLV);  
+
+  YRes.ssq = YRes.ssq(:,1:nLV);
+  YRes.U   = YRes.U(:,1:nLV);  
+  YRes.Q   = YRes.Q(:,1:nLV);  
+  YRes.C   = YRes.C(:,1:nLV);  
+  YRes.bin = YRes.bin(:,1:nLV);
+ 
+  Options.maxLV = nLV;
+end
+
+B = cumsum(B,3);
+
+return;
+
+
+
+function A = MakeSym(A)
+A = 0.5*(A+A');
+%A = max(A,A');
+
+return
+
+
Index: /hypertools/hypertools/pls_trans.m
===================================================================
--- /hypertools/hypertools/pls_trans.m	(revision 3)
+++ /hypertools/hypertools/pls_trans.m	(revision 3)
@@ -0,0 +1,59 @@
+%pls_trans  Partial Least Squares (transformation)
+%
+%  T = pls_trans(X,R)
+%  T = pls_trans(X,R,Options)
+%
+% INPUT
+%  X       [N -by- d_X]    the input  data matrix, N samples, d_X variables
+%  R       [d_X -by- nLV]  the transformation matrix: T_new = X_new*R
+%          (X_new here after preprocessing, preprocessing and un-preprocessing 
+%          could be done automatically (than Options contains info about 
+%          preprocessing) or manually); normally, R as a field of XRes output parameter of 
+%          pls_train routine
+%
+%  Options structure returned by pls_train (if not supplied then will be no preprocessing performed)  
+%
+% OUTPUT
+%  T [N -by- nLV]   scores -- transformed data
+%
+% DESCRIPTION
+% Applys PLS (Partial Least Squares) regression model
+%
+% SEE ALSO
+% pls_train, pls_apply
+
+% Copyright: S.Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: pls_trans.m,v 1.2 2005/10/19 20:45:15 serguei Exp $
+
+function T = pls_trans(X,R,Options)
+
+if nargin < 3
+  Options  = [];
+end
+
+DefaultOptions.X_centering = [];
+DefaultOptions.Y_centering = [];
+DefaultOptions.X_scaling = [];
+DefaultOptions.Y_scaling = [];
+
+Options = updstruct(DefaultOptions, Options);
+
+[N, d_X]    = size(X);
+[d_XR, nLv] = size(R);
+
+if d_X ~= d_XR
+  error('size(X,2) must be equal to size(R,1)');
+end
+
+T = prepro(X, Options.X_centering, Options.X_scaling)*R;
+
+return;
+
+
+
+
+
+
Index: /hypertools/hypertools/plsm.m
===================================================================
--- /hypertools/hypertools/plsm.m	(revision 3)
+++ /hypertools/hypertools/plsm.m	(revision 3)
@@ -0,0 +1,109 @@
+% PLSM Partial Least Squares Feature Extraction
+%
+%  W = PLSM
+%  W = PLSM([],MAXLV,METHOD)
+%
+%  [W, INFORM] = PLSM(A,MAXLV,METHOD)
+%
+% INPUT 
+%   A             training dataset
+%   MAXLV         maximal number of latent variables (will be corrected if > rank(A)); 
+%                 MAXLV=inf means MAXLV=min(size(A)) -- theoretical maximum number of LV; 
+%                 by default = inf
+%   METHOD       'NIPALS' or 'SIMPLS'; by default = 'SIMPLS'
+%
+% OUTPUT 
+%   W             PLS feature extraction mapping 
+%   INFORM        extra algorithm output
+%
+% DESRIPTION
+% PRTools Adaptation of PLS_TRAIN/PLS_TRANS routines
+% No preprocessing is done inside this mapping. It is the 
+% user responsibility to train preprocessing on training data 
+% and apply it to the test data.
+%
+% Crisp labels will be converted into soft labels which 
+% will be used as a target matrix.
+%
+% SEE ALSO
+% PLS_TRAIN, PLS_TRANS, PLS_APPLY
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: plsm.m,v 1.4 2006/07/10 11:55:24 serguei Exp $
+%
+
+function [w,inform]=plsm(par1,par2,par3)
+	
+% No dataset given: return untrained mapping.
+if (nargin < 1) | (isempty(par1))
+  if nargin < 2
+    par2 = inf;
+  end  
+  if nargin < 3
+    par3 = 'SIMPLS';
+  end  
+  data = {par2,par3};
+  w = mapping(mfilename,'untrained',data);
+	w = setname(w,'Partial Least Squares Mapping (FE)');
+	return
+end
+
+
+isdataset(par1);           % Assert that A is a dataset.
+
+% training
+if nargin < 2 | ~isa(par2,'mapping') 
+  % a*w when w is untrained or 
+  if nargin < 2
+    par2 = inf;
+  end  
+  if nargin < 3
+    par3 = 'SIMPLS';
+  end  
+  maxLV  = par2;
+  method = par3;
+ 
+	if strcmp(par1.labtype,'crisp')
+	  y=gettargets(setlabtype(par1,'soft'));
+	else
+  	y=gettargets(par1);
+  end
+
+	% options
+  Options.maxLV  = maxLV;
+  Options.method = method;
+	Options.X_centering=[];
+  Options.Y_centering=[];
+	Options.X_scaling=[];
+  Options.Y_scaling=[];
+
+	[B,XRes,YRes,Options]=pls_train(+par1,y,Options);
+	
+  clear B
+
+  data.n=Options.maxLV;
+  data.R=XRes.R;
+  data.Options=Options;
+	
+	% Save all useful data.
+	w = mapping(mfilename,'trained',data,[],size(XRes.R,1),size(XRes.R,2));
+	w = setname(w,'Partial Least Squares Mapping');
+
+	if nargout > 1
+	 inform.XRes=XRes;
+	 inform.YRes=YRes;
+	end
+	
+% execution
+else 
+	wdata = getdata(par2); % Unpack the mapping.
+  T = prepro(+par1,wdata.Options.X_centering,wdata.Options.X_scaling)*wdata.R(:,1:wdata.n);
+  w = setdat(par1,T,par2);
+end
+
+return
+
+	
Index: /hypertools/hypertools/plsr.m
===================================================================
--- /hypertools/hypertools/plsr.m	(revision 3)
+++ /hypertools/hypertools/plsr.m	(revision 3)
@@ -0,0 +1,122 @@
+% PLSR Partial Least Squares Regression
+%
+%  W = PLSR
+%  W = PLSR([],MAXLV,METHOD)
+%
+%  [W, INFORM] = PLSR(A,MAXLV,METHOD)
+%
+% INPUT 
+%   A             training dataset
+%   MAXLV         maximal number of latent variables (will be corrected if > rank(A)); 
+%                 MAXLV=inf means MAXLV=min(size(A)) -- theoretical maximum number of LV; 
+%                 by default = inf
+%   METHOD       'NIPALS' or 'SIMPLS'; by default = 'SIMPLS'
+%
+% OUTPUT 
+%   W             PLS feature extraction mapping 
+%   INFORM        extra algorithm output
+%
+% DESRIPTION
+% PRTools Adaptation of PLS_TRAIN/PLS_APPLY routines
+% No preprocessing is done inside this mapping. It is the 
+% user responsibility to train preprocessing on training data 
+% and apply it to the test data.
+%
+% Crisp labels will be converted into soft labels which 
+% will be used as a target matrix.
+%
+% In order to do regression with the smaller number of latent variables than 
+% the number of LV's selected during trainig do
+% d = w.data;
+% d.n = new_n;
+% w.data = d;
+%
+% SEE ALSO
+% PLS_TRAIN, PLS_TRANS, PLS_APPLY
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: plsr.m,v 1.1 2005/10/19 20:45:42 serguei Exp $
+%
+
+function [w,inform]=plsm(par1,par2,par3)
+	
+% No dataset given: return untrained mapping.
+if (nargin < 1) | (isempty(par1))
+  if nargin < 2
+    par2 = inf;
+  end  
+  if nargin < 3
+    par3 = 'SIMPLS';
+  end  
+  data = {par2,par3};
+  w = mapping(mfilename,'untrained',data);
+	w = setname(w,'Partial Least Squares Regression');
+	return
+end
+
+
+isdataset(par1);           % Assert that A is a dataset.
+
+% training
+if nargin < 2 | ~isa(par2,'mapping') 
+  % a*w when w is untrained or 
+  if nargin < 2
+    par2 = inf;
+  end  
+  if nargin < 3
+    par3 = 'SIMPLS';
+  end  
+  maxLV  = par2;
+  method = par3;
+ 
+	if strcmp(par1.labtype,'crisp')
+	  y=gettargets(setlabtype(par1,'soft'));
+	else
+  	y=gettargets(par1);
+  end
+
+	% options
+  Options.maxLV  = maxLV;
+  Options.method = method;
+	Options.X_centering=[];
+  Options.Y_centering=[];
+	Options.X_scaling=[];
+  Options.Y_scaling=[];
+
+	[B,XRes,YRes,Options]=pls_train(+par1,y,Options);
+	
+  clear B
+
+  data.n=Options.maxLV;
+  data.R=XRes.R;
+  data.C=YRes.C;
+  data.Options=Options;
+	
+	% Save all useful data.
+	w = mapping(mfilename,'trained',data,[],size(XRes.R,1),size(YRes.C,1));
+	w = setname(w,'Partial Least Squares Mapping');
+
+	if nargout > 1
+	 inform.XRes=XRes;
+	 inform.YRes=YRes;
+	end
+	
+% execution
+else 
+	data = getdata(par2); % Unpack the mapping.
+    if data.n > size(data.R,2)
+    ErrMsg = sprintf(['PLS: The nubmer of LV(s) asked (%d) is greater than\n'...
+                      'the number of LV(s) available (%d)'],data.n,size(data.R,2));
+    error(ErrMsg);
+  end
+
+  Y = pls_apply(+par1,data.R(:,1:data.n)*data.C(:,1:data.n)',data.Options);
+  w = setdat(par1,Y,par2);
+end
+
+return
+
+	
Index: /hypertools/hypertools/private/dipfig_getcurpos.m
===================================================================
--- /hypertools/hypertools/private/dipfig_getcurpos.m	(revision 3)
+++ /hypertools/hypertools/private/dipfig_getcurpos.m	(revision 3)
@@ -0,0 +1,55 @@
+%PT = DIPFIG_GETCURPOS(AX)
+%    Returns the coordinates of the mouse over the image in axes AX.
+%    PT is [x,y], so that indexing into the dip_image object is done
+%    by (pt(1),pt(2)).
+%
+%    If the mouse is outside the window, returns the closest coordinates
+%    within the window.
+%
+%    The axes 'units' are expected to be 'pixels'.
+%
+%    PT = DIPFIG_GETCURPOS(AX,CROP) is the same thing if CROP is non-zero.
+%    For CROP==0, the coordinates are not compared to the axis limits, so
+%    the returned value can be outside the window, and outside the image.
+
+% (C) Copyright 1999-2002               Pattern Recognition Group
+%     All rights reserved               Faculty of Applied Physics
+%                                       Delft University of Technology
+%                                       Lorentzweg 1
+%                                       2628 CJ Delft
+%                                       The Netherlands
+%
+% Cris Luengo, July 2001.
+% 24 August 2001: The bug we are correcting for is not there in MATLAB 6.
+% 25 August 2001: Removed the FIG parameter, which wasn't being used.
+% 29 April 2002:  Added the CROP parameter.
+
+% The offset for the Y axis is a fix for the fact that the position
+% reported by MATLAB trough 'CurrentPoint' is one pixel off in the Y-axis.
+% This is screen pixels, not axes coordinates.
+% This bug has been corrected in MATLAB 6.
+
+function pt = dipfig_getcurpos(ax,crop)
+pt = get(ax,'CurrentPoint');
+pt = [pt(1,1),pt(1,2)];
+curylim = get(ax,'YLim');
+curxlim = get(ax,'XLim');
+v = version;
+if v(1)=='5'
+   axpos = get(ax,'Position');
+   curyrange = diff(curylim);
+   pt(2) = pt(2) - curyrange/axpos(4);
+end
+pt = round(pt);
+if nargin==1 | crop
+   if pt(1) < curxlim(1)
+      pt(1) = ceil(curxlim(1));
+   elseif pt(1) > curxlim(2)
+      pt(1) = floor(curxlim(2));
+   end
+   if pt(2) < curylim(1)
+      pt(2) = ceil(curylim(1));
+   elseif pt(2) > curylim(2)
+      pt(2) = floor(curylim(2));
+   end
+end
Index: /hypertools/hypertools/private/dipfig_set_action_check.m
===================================================================
--- /hypertools/hypertools/private/dipfig_set_action_check.m	(revision 3)
+++ /hypertools/hypertools/private/dipfig_set_action_check.m	(revision 3)
@@ -0,0 +1,26 @@
+%DIPFIG_SET_ACTION_CHECK(FIG,STATE)
+%    Set the checkmark to the current mouse action.
+
+% (C) Copyright 1999-2001               Pattern Recognition Group
+%     All rights reserved               Faculty of Applied Physics
+%                                       Delft University of Technology
+%                                       Lorentzweg 1
+%                                       2628 CJ Delft
+%                                       The Netherlands
+%
+% Cris Luengo, July 2000.
+% July 2001: only clear the old checked box
+% 16-26 August 2001: Changed DIPSHOW. This function changes accordingly.
+
+function dipfig_set_action_check(fig,state)
+m = get(findobj(get(fig,'Children'),'Tag','actions'),'Children');
+tags = get(m,'Tag');
+I = strncmp(tags,'mouse_',6);
+m = m(I);
+set(m,'Checked','off');
+if ~isempty(state)
+   I = find(strcmp(tags(I),['mouse_',state]));
+   if ~isempty(I)
+      set(m(I),'Checked','on');
+   end
+end
Index: /hypertools/hypertools/private/prepro.m
===================================================================
--- /hypertools/hypertools/private/prepro.m	(revision 3)
+++ /hypertools/hypertools/private/prepro.m	(revision 3)
@@ -0,0 +1,71 @@
+function [X,centering,scaling] = prepro(X,centering,scaling, flag)
+
+% Copyright: S.Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+if nargin<4
+  flag = 1;
+end
+
+[N,d] = size(X);
+
+centering = centering(:).';
+scaling = scaling(:).';
+
+if flag >= 0
+  if length(centering) == 1
+    if isnan(centering)
+      centering = mean(X,1);
+      X = X - repmat(centering, [N,1]);
+    else
+      X = X - centering;
+    end
+
+  elseif length(centering) == d
+    idx = find(isnan(centering));
+    centering(idx) = mean(X(:,idx),1);
+    X = X - repmat(centering, [N,1]);
+  end
+
+
+  if length(scaling) == 1
+    if isnan(scaling)
+      scaling = std(X,0,1);
+      idx0 = find(scaling == 0);
+      scaling(idx0) = 1;
+      warning(['features ' num2str(idx(:)) ' have std = 0 and are not scaled']);
+      X = X ./ repmat(scaling, [N,1]);
+    else
+      X = X / scaling;
+    end
+
+  elseif length(scaling) == d
+    idx = find(isnan(scaling));
+    scaling(idx) = std(X(:,idx),0,1);
+    idx0 = find(scaling(idx) == 0);
+    scaling(idx(idx0)) = 1;  
+    warning(['features ' num2str(idx(idx0(:))) ' have std = 0 and are not scaled']);
+    X = X ./ repmat(scaling, [N,1]);
+  end
+
+else
+  if length(centering) > 0 & all(~isnan(centering))
+    if length(centering) == 1 
+      X = X + centering;
+    elseif length(centering) == d 
+      X = X + repmat(centering, [N,1]);
+    end
+  end
+
+  if length(scaling) > 0 & all(~isnan(scaling))
+    if length(scaling) == 1
+      X = X * scaling;
+    elseif length(scaling) == d
+      X = X .* repmat(scaling, [N,1]);
+    end
+  end
+end
+
+return
+
Index: /hypertools/hypertools/private/updstruct.m
===================================================================
--- /hypertools/hypertools/private/updstruct.m	(revision 3)
+++ /hypertools/hypertools/private/updstruct.m	(revision 3)
@@ -0,0 +1,43 @@
+function UpdStructure = updstruct(OldStructure, NewStructure, SkipEmptyUpdatesOfTheExistingFields)
+%
+% Structure update
+%
+%   UpdStructure = updstruct(OldStructure, NewStructure)
+%   
+% In the result UpdStructure all new filed from NewStructure will be added, 
+% coinciding fields will be replaced, fields which do not exist in the NewStruct
+% will be preserved
+
+% Copyright: S.Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+UpdStructure = OldStructure;
+
+if nargin < 3 | isempty(SkipEmptyUpdatesOfTheExistingFields)
+  SkipEmptyUpdatesOfTheExistingFields = 0;
+end
+
+if nargin < 2 | isempty(NewStructure) | ~isstruct(NewStructure)
+  return;
+end
+
+fn = fieldnames(NewStructure);
+for i=1:length(fn)
+
+  v = getfield(NewStructure,fn{i});
+
+  if ~(SkipEmptyUpdatesOfTheExistingFields & isfield(UpdStructure, fn{i}) & isempty(v))
+    if isa(v,'struct') & length(v) == 1
+      if isfield(UpdStructure, fn{i}) 
+        w = getfield(UpdStructure, fn{i});  
+        if isa(w,'struct') 
+          v = updstruct(w,v); 
+        end  
+      end
+    end 
+    UpdStructure = setfield(UpdStructure,fn{i},v);
+  end
+end
+
+return;
Index: /hypertools/hypertools/prlseed.m
===================================================================
--- /hypertools/hypertools/prlseed.m	(revision 3)
+++ /hypertools/hypertools/prlseed.m	(revision 3)
@@ -0,0 +1,9 @@
+% prlseed.m - set up random generator state
+%   prlseed(state)
+%
+% prl - $Id: prlseed.m,v 1.1.1.1 2003/07/14 10:59:12 pavel Exp $
+
+function out=prlseed(state)
+
+%fprintf('(seed=%d)',state);
+rand('state',state);
Index: /hypertools/hypertools/protoselm.m
===================================================================
--- /hypertools/hypertools/protoselm.m	(revision 3)
+++ /hypertools/hypertools/protoselm.m	(revision 3)
@@ -0,0 +1,68 @@
+% PROTOSELM Prototype selection mapping
+%
+%   W=PROTOSELM(A,TYPE,PAR)
+%
+% DESCRIPTION
+% This function implements traineble prototype selection mapping.  It is
+% applied to a dataset with dissimilaritites. Once trained, it acts
+% as simple feature selection mapping.
+% 
+% types:
+%  rand - random selection of PAR prototypes from all data samples
+%  randcls - random selection using PAR samples per class
+%  
+
+% $Id: protoselm.m,v 1.2 2005/02/10 15:24:07 pavel Exp $
+
+function w=protoselm(a,type,par)
+
+	if (nargin == 0)
+		w = mapping(mfilename,{'rand',1});
+		w = setname(w,['Prototype selection mapping']);
+		return
+	end
+	
+	% allow simple construction of untrained mapping:
+	if nargin==1 & ischar(a), type=a; a=[]; end 
+	if isempty(a) & ischar(type)
+		if ~exist('par','var'), par=1; end
+		w = mapping(mfilename,{type,par});
+		w = setname(w,['Prototype selection mapping ''' type '''']);
+	end
+	
+	if isdataset(a) & ~ismapping(type)
+		% train the dissimilarity mapping
+		[m,k,c] = getsize(a);
+		if ~exist('par','var'), par=[]; end
+
+		% for each method, set proto to indices of prototypes
+		switch type
+			
+		 case {'rand', 'random'}
+		  % randomly select prototypes
+		  % par: number of prototypes
+		  ind=randperm(size(a,2));
+		  proto=ind(1:par);
+		  
+		 case 'randcls'
+		  % select prototypes randomly from each class
+		  % par: number of prototypes per class
+		  [temp,temp2,proto]=gendat(a,par*ones(1,c));
+		  
+		 otherwise
+		  error('unknown type');
+		  
+		end
+		w = mapping(mfilename,'trained',{type,par,proto},a.lablist,k,length(proto));
+		w = setname(w,'Prototype selection mapping');
+	end
+	
+	if isdataset(a) & ismapping(type)
+		% execute the mapping
+		par=type{2};
+		proto=type{3};
+		w=setdat(a,a(:,proto));
+	end
+
+	return
+	
Index: /hypertools/hypertools/rainbow.m
===================================================================
--- /hypertools/hypertools/rainbow.m	(revision 3)
+++ /hypertools/hypertools/rainbow.m	(revision 3)
@@ -0,0 +1,26 @@
+% rainbow colormap
+function r = rainbow(m)
+
+if nargin  == 0 | isempty(m)
+  m = size(get(gcf,'colormap'),1);
+end
+
+m = ceil(m);
+
+r0 = [0 0 1; ...
+      0 1 1; ...           
+      0 1 0; ...    
+      1 1 0; ...    
+      1 0 0];
+
+r  = zeros(m,3);   
+
+x0 = linspace(1,m,5)';
+
+x  = (1:m)';
+ 
+for i=1:3
+  r(:,i) = interp1(x0,r0(:,i),x,'linear');
+end
+ 
+return
Index: /hypertools/hypertools/randfeatselm.m
===================================================================
--- /hypertools/hypertools/randfeatselm.m	(revision 3)
+++ /hypertools/hypertools/randfeatselm.m	(revision 3)
@@ -0,0 +1,84 @@
+% RANDFEATSELM Random feature selection with validation
+%
+%      [W,P,E]=RANDFEATSELM(DATA,N,D,WIN)
+%
+% INPUT
+%   DATA   input dataset
+%   N      number of randomly generated feature subsets
+%   D      requested dimensioanlity
+%   WIN    untrained mapping
+%
+% OUTPUT
+%   W      feature selection mapping with the best subset found
+%   P      the final population (uint8 matrix, each row is a
+%          binary-encoded feature subset)
+%   E      error rate for each feature subset
+%
+% DESCRIPTION
+% This function generates randomly N feature subsets of dimensionality D.
+% For each subset a mapping WIN is traned and an apparent error rate is
+% used as criterion. Subsets are sorted according to the error and the
+% feature selection mapping with the best subset is returned as W.
+% Feature selection mappings for subset i may be retrieved using:
+%   w2=cmapm(size(data,2),find(P(i)==1))
+
+% $Id: randfeatselm.m,v 1.3 2005/02/10 15:24:07 pavel Exp $
+
+function [w,P,e]=randfeatselm(data,N,D,win)
+	
+	fc=size(data,2);
+	
+	P=create_init_pop(N,fc,D);
+	e=get_err(data,P,win); % population errors
+
+	[s,ind]=sort(e);
+	e=e(ind);
+	P=P(ind,:);
+	
+	w=cmapm(fc,find(P(1,:)==1));	
+	
+	return
+	
+% N - number of individuals to create
+% d - number of dimensions (features) we search in
+% dim - how many dimensions should be switched on
+%       Dim may be a vector specifying lower and upper bound)
+function P=create_init_pop(N,d,dim)
+
+	% population matrix
+	P=repmat(uint8(0),N,d);
+
+	[ignore,ind]=sort(rand(N,d),2);
+	clear ignore
+	
+	% feature count per individual:
+	if length(dim)==1
+		% constant number of switched on-dimensions
+		fc=dim*ones(N,1);
+	else
+		fc=dim(1)+floor(rand(N,1)*dim(2));
+	end
+
+	for i=1:N
+		try
+			P(i,ind(i,1:fc(i)))=1;
+		catch
+			keyboard
+		end
+	end
+	
+	return
+	
+% measure the error for each feature setup (chromosome) in P
+% on data using user-defined mapping w
+function e=get_err(data,P,win)
+	
+	e=zeros(size(P,1),1);
+	for i=1:size(P,1)
+		ind=find(P(i,:)>0);
+                w2=data(:,ind)*win;
+		e(i)=data(:,ind)*w2*testc;
+	end
+	
+	return
+	
Index: /hypertools/hypertools/readme.txt
===================================================================
--- /hypertools/hypertools/readme.txt	(revision 3)
+++ /hypertools/hypertools/readme.txt	(revision 3)
@@ -0,0 +1,35 @@
+Hypertools toolbox 2.2 [November 2005]
+==================================================
+ Pavel Paclik, Serguei Verzakov, Robert P.W.Duin
+ Information and Communication Theory Group, TU Delft
+
+Hypertools is a Matlab toolbox for analysis of hyperspectral images. It is
+built on top of PRTools, the pattern recognition toolbox (http://www.prtools.org)
+
+Hypertools is intended for academic use only.
+Please read the Hypertools license file license.txt for conditions of use.
+
+Requirements
+------------
+
+- the toolbox was tested with:
+	- Matlab 6.5
+	- prtools 4 or higher
+	- dipimage 1.4.1 or higher
+
+Installation
+------------
+
+- you can download prtools from http://www.prtools.org
+
+- install prtools
+
+- extract hypertools:
+   $ tar xvfz hypertools2.2.tar.gz
+
+- dipimage can be downloaded from its home page: http://www.ph.tn.tudelft.nl/DIPlib/
+
+- install dipimage according to it's documentation
+
+- add path to prtools and hypertools in Matlab
+
Index: /hypertools/hypertools/samc.m
===================================================================
--- /hypertools/hypertools/samc.m	(revision 3)
+++ /hypertools/hypertools/samc.m	(revision 3)
@@ -0,0 +1,80 @@
+%SAMC Spectral Angle Mapper classifier
+% 
+%   W = SAMC(A)
+% 
+% INPUT  
+%   A    Training dataset
+%
+% OUTPUT
+%   W    Spectral Angle Mapper mapping
+%
+% DESCRIPTION
+% Classifier based on SAM similarity measure. A mean spectrum of each
+% class is considered a prototype. In order to use more prototypes per
+% class,
+%
+% SEE ALSO
+% DATASETS, MAPPINGS
+
+% $Id: samc.m,v 1.2 2005/02/10 10:00:54 pavel Exp $
+
+function w = samc(a,arg2)
+
+	% No arguments given: return untrained mapping.
+
+	if (nargin < 1) | (isempty(a))
+		w = mapping(mfilename,{arg2});
+		w = setname(w,'Spectral Angle Mapper classifier');
+		return
+	end
+
+	if (~exist('arg2','var'))     % Second argument is not a mapping: training.
+
+		isdataset(a);           % Assert that A is a dataset.
+
+		[m,k,c] = getsize(a); M = classsizes(a);
+
+		% class means
+		pars.means=meancov(a);
+		
+		% Save all useful data.
+
+		w = mapping(mfilename,'trained',pars,getlablist(a),k,c);
+		w = setname(w,'Spectral Angle Mapper classifier');
+
+	else                      % Second argument is a a mapping: testing.
+
+		w = arg2;
+		pars = getdata(w);		 	% Unpack the mapping.
+		[m,k] = getsize(a); 
+
+		c = size( pars.means, 1 );
+
+		% computing x'x
+		t=+a;
+		X=zeros(size(t,1),1);
+		for i=1:size(t,1)
+			X(i)=t(i,:) * t(i,:)';
+		end
+
+		% class means
+		means=+pars.means;
+		M=zeros(size(pars.means,1),1);
+		for i=1:c
+			M(i)=means(i,:) * means(i,:)';
+		end
+		
+		X= sqrt(X) * sqrt(M)';
+		
+		% we output the goodness to fitt the class = the higher, the
+                % better
+		out=(pi/2)-acos( (t * means')./X );
+
+		w = setdat(a,out,w);
+
+	end
+
+return
+
+
+
Index: /hypertools/hypertools/segment_comb.m
===================================================================
--- /hypertools/hypertools/segment_comb.m	(revision 3)
+++ /hypertools/hypertools/segment_comb.m	(revision 3)
@@ -0,0 +1,109 @@
+% SEGMENT_COMB Segmentation combining spatial and spectral domains
+%
+%    [SEG,ALLSEG]=SEGMENT_COMB(A,CC,WSPEC,SIGMA,MAXIT)
+%
+% INPUT
+%   A       dataset with multi-band image data
+%   CC      requested number of classes (may be read from labeled A)
+%   WPEC    untrained spectral classifier (optional, default: nmc)
+%   SIGMA   smoothing parameter (optional, default: 1.0)
+%   MAXIT   maximum number of iterations (optional, default: 20)
+%
+% OUTPUT
+%   SEG     segmentation result as a dip_image
+%   ALLSEG  all steps of the segmentation process
+%
+% DESCRIPTION
+%
+% Multi-band image is segmented using the combined classifier segmentation
+% algorithm. Initial labeling is needed. If it is not supplied in the input
+% dataset, it is estimated via kmeans algorithm. Then, spectral (WSPEC) and
+% spatial (Parzen classifierimplemented as convolution with Gaussian kernel
+% and smoothing SIGMA). The process is iterated until a stable solution is
+% found or a maximum number of iterations is reached.
+%
+% $Id: segment_comb.m,v 1.4 2005/02/10 15:24:07 pavel Exp $
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function [seg,allseg]=segment_comb(a,cc,wspec,sigma,maxit)
+ 
+	[sc,fc,tcc]=getsize(a);
+
+	if ~exist('cc','var') 
+		error('number of classes must be specified!');
+	end
+	
+	if tcc<=1
+		[lab,b]=kmeans(a,cc);
+	else
+		prwarning(2,'using labels supplied in the dataset');
+		b=a;
+		cc=tcc;
+	end
+
+	if ~exist('wspec','var')
+		prwarning(2,'spectral classifier not specified, using wspec=nmc');
+		wspec=nmc;
+	end
+	
+	if ~exist('sigma','var')
+		prwarning(2,'smoothing sigma not specified, using sigma=1.0');
+		sigma=1;
+	end
+	
+	if ~exist('maxit','var')
+		maxit=20;
+	end
+	
+	b.objsize=a.objsize;
+   
+	seg=b.nlab;
+	allseg=seg;
+	
+	lastseg=zeros(size(seg));
+	
+	it=1;
+	err=sum(sum( abs( seg-lastseg ) ));
+	while it<=maxit
+		
+		fprintf('[%d',it);
+		bspec=b*(b*wspec); % traing and applying the spectral classifier
+		
+		% spatial classifier
+		bspat=spatm(bspec,sigma);
+		bspat=bspat(:,cc+1:end);
+		
+		% combining
+		if size(bspec)==size(bspat)
+
+			b=bspec.*bspat;
+			
+			% new labelling
+			lastseg=seg;
+			seg=b*classd;
+			
+			allseg=[allseg seg];
+
+			err=sum(sum( abs( seg-lastseg ) ));      
+			
+			fprintf(' err=%d] ',err);
+			it=it+1;
+		else
+			prwarning(1,'maximum number of %d iterations reached, returning the last result', maxit);
+			it=maxit+1;
+		end
+		
+		% in case of stable classification, finish
+		if err==0
+			it=maxit+1;
+		end
+		
+	end
+	
+	seg=getli(int8(seg),a);
+	allseg=getli(int8(allseg),a);
+   
+   return
Index: /hypertools/hypertools/setli.m
===================================================================
--- /hypertools/hypertools/setli.m	(revision 3)
+++ /hypertools/hypertools/setli.m	(revision 3)
@@ -0,0 +1,28 @@
+% SETLI Set labels in the dataset from the label image
+%
+%     A = SETLI(A,LI)
+%
+% INPUT 
+%   A      spectral dataset
+%   LI     image with labels (dip_image)
+%
+% OUTPUT
+%   A      output dataset
+%
+
+% $Id: setli.m,v 1.3 2005/02/10 15:24:07 pavel Exp $
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function a=setli(a,li)
+	
+	isdataset(a);
+	
+	objsize=size(li);
+	
+	lab=reshape(double(li),prod(objsize),1);
+	a=setlabels(a,lab);
+	
+	return
Index: /hypertools/hypertools/sg.m
===================================================================
--- /hypertools/hypertools/sg.m	(revision 3)
+++ /hypertools/hypertools/sg.m	(revision 3)
@@ -0,0 +1,234 @@
+function varargout = sg(varargin)
+% 
+%
+%   Filter creating:
+%   CM = sg(w, p, m)  
+%
+%   Filter applying:
+%   Y_hat = sg(CM, Y) 
+%   Y_hat = sg(CM, Y, dim) 
+%
+%   Filter creating & applying:
+%   [Y_hat, CM] = sg(w, p, m, Y)
+%   [Y_hat, CM] = sg(w, p, m, Y, dim)
+%
+%
+% w     window size in points; w must be:  (odd & 3 <= w < d) or (w == d); 
+%       (d is the size of the dimension of the input matrix Y along which it should be filtered,
+%       if Y is not supplied, it is assumed that d == inf)
+%
+% p     polynom order p=0,1,2,...
+%
+% m     derivative order m=0,1,2...
+%
+% Y     matrix which should be smoothed/differinate; 
+%       by default (i.e. if the parameter dim is not supplied) 
+%       filtering will be applied to the first non-singleton dimension; 
+%
+% dim   selects the dimension along which Y should be filtered
+%
+%
+% CM    coefficient matrix (filter) 
+% Y_hat result matrix
+%
+
+% Copyright: S.Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: sg.m,v 1.9 2007/03/15 16:10:24 serguei Exp $
+
+	if nargout > 0
+		varargout(1:nargout) = {[]};
+	end
+	
+	Y_hat  = [];
+	CM     = [];
+
+	w   = [];
+	p   = [];
+	m   = [];
+	Y   = [];
+	dim = [];
+
+	d   = [];
+
+	create_filter = 0;
+	apply_filter  = 0;
+
+	switch length(varargin)
+	 case 2
+	  %Y_hat = sg(CM, Y) 
+	  apply_filter  = 1;
+	  CM  = varargin{1};
+	  Y   = varargin{2};
+
+	 case 3
+	  %CM = sg(w, p, m)  
+	  if all(size(varargin{1}) == 1)
+		  create_filter  = 1;
+		  w  = varargin{1};
+		  p  = varargin{2};
+		  m  = varargin{3};
+
+		  %Y_hat = sg(CM, Y, dim) 
+	  else
+		  apply_filter  = 1;
+		  CM  = varargin{1};
+		  Y   = varargin{2};
+		  dim = varargin{3};
+	  end  
+
+	 case 4
+	  %[Y_hat, CM] = sg(w, p, m, Y)
+	  create_filter = 1;
+	  apply_filter  = 1;
+	  w  = varargin{1};
+	  p  = varargin{2};
+	  m  = varargin{3};
+	  Y  = varargin{4};
+
+	 case 5
+	  %[Y_hat, CM] = sg(w, p, m, Y, dim)
+	  create_filter = 1;
+	  apply_filter  = 1;
+	  w   = varargin{1};
+	  p   = varargin{2};
+	  m   = varargin{3};
+	  Y   = varargin{4};
+	  dim = varargin{5};
+
+	 otherwise
+	  error('Invalid number of input parameters');
+	end
+
+
+	if apply_filter
+		if ~isempty(dim) 
+			if floor(dim) ~= dim | dim < 1 | dim > length(size(Y)) 
+				error('dim must be integer, >=1, <=length(size(Y))');
+			end  
+		else 
+			dim = size(Y);
+			dim = find(dim > 1);
+
+			if isempty(dim)
+				error('Filter cannot be applied to the scalar Y');
+			end
+
+			dim = dim(1);
+		end
+
+		d = size(Y,dim);
+
+		if d < 3
+			error('size(Y,dim) must be >= 3');
+		end
+	end
+
+
+	if create_filter
+		if ~isempty(d) 
+			if floor(w) ~= w | mod(w,2) == 0 | w < 3 
+				error('w must be odd integer >=3');
+			end
+		else
+			if (floor(w) ~= w | mod(w,2) == 0 | w < 3 | w > d) & w ~= d
+				error('w must be (odd integer >=3, <=size(Y,dim)) or ==size(Y,dim)');
+			end
+		end  
+		
+		M = floor(w/2);
+
+		if floor(p) ~= p | p < 0
+			error('p must be 0,1,2...');
+		end
+
+		if floor(m) ~= m | m < 0
+			error('m must be 0,1,2...');
+		end
+
+		if m > p
+			Y_hat = zeros(size(Y));
+			CM = zeros(3);
+
+			WarnMsg = 'Derivative order is greater than order of approximating polinomial';
+			if exist('prwarning')
+				prwarning(1, WarnMsg);
+			else
+				warning(WarnMsg);
+			end
+			
+		else
+			X = repmat([(-M):(w-M-1)]',[1 p]);
+			X = [fliplr(cumprod(X,2)) ones(w,1)];
+
+			CM = (X'*X)\X';
+			%CM = X\eye(w);
+			CM = CM(1:p-m+1,:);
+
+			if m == 0
+				CM = X*CM;
+			else
+				factors = zeros(1,p-m+1);
+				for i=m:p
+					factors(p-i+1) = prod([1 (i-m+1):i]);
+				end
+				CM = [X(:,(m+1):(p+1))].*repmat(factors,[w 1])*CM;
+			end
+		end
+	end
+
+
+	if apply_filter & isempty(Y_hat)
+		cms = size(CM);
+
+		if cms(1) ~= cms(2) 
+			error('size(CM,1) must be equal size(CM,2)');
+		elseif (mod(cms(2),2) == 0 | cms(2) < 3 | cms(2) > d) & cms(2) ~= d
+			error('size(CM,2) must be (odd, >=3, <=size(Y,dim)) or == size(Y,dim)');
+		end
+
+		w = cms(2);
+		M = floor(w/2);
+
+		ys = size(Y);
+		order = [1:length(ys)];
+		order(1) = dim;
+		order(dim) = 1;
+		Y = permute(Y,order);
+		ysn = size(Y);
+
+		CM_b = CM(1:M,:);
+		CM_m = CM((M+1):(end-M),:);
+		CM_e = CM((end-M+1):end,:);
+
+		Y_b = reshape(CM_b * Y(1:w,:), [M ysn(2:end)]);
+
+		if isempty(CM_m)
+			Y_m = [];
+		else
+			Y_m = filter(fliplr(CM_m), 1, Y);
+      Y_m = reshape(Y_m(w:end,:),[(ysn(1)-2*M) ysn(2:end)]);
+    end
+
+		Y_e = reshape(CM_e * Y((end-w+1):end,:), [M ysn(2:end)]);
+    clear Y;
+
+    Y_hat = permute([Y_b; Y_m; Y_e], order);
+		clear Y_b Y_m Y_e;
+	end
+
+
+	if create_filter & apply_filter 
+		varargout(1:2) = {Y_hat, CM};
+
+	elseif create_filter
+		varargout(1) = {CM};
+
+	elseif apply_filter 
+		varargout(1) = {Y_hat};
+	end
+
+	varargout = varargout(1:nargout);
+	return;
Index: /hypertools/hypertools/sgxmp.m
===================================================================
--- /hypertools/hypertools/sgxmp.m	(revision 3)
+++ /hypertools/hypertools/sgxmp.m	(revision 3)
@@ -0,0 +1,52 @@
+dx = 0.005;
+w = 75;
+p = 3;
+
+
+x = [0:dx:2*pi];
+y = [sin(x); cos(x)];
+y = y + 0.01*randn(size(y));
+
+cm0 = sg(w,p,0);
+y0 = sg(cm0,y,2);
+
+cm1 = sg(w,p,1);
+y1 = sg(cm1,y,2);
+
+[y2, cm2] = sg(w,p,2,y,2); 
+
+figure;
+subplot(2,2,1)
+plot(x,y); box on; grid on;
+
+subplot(2,2,2)
+plot(x,y0); box on; grid on;
+
+subplot(2,2,3)
+plot(x,y1/dx); box on; grid on;
+
+subplot(2,2,4)
+plot(x,y2/dx.^2); box on; grid on;
+
+
+x = [0:dx:1];
+y = [x.^2; x.^3; x.^4];
+y = y + 0.01*randn(size(y));
+
+y0 = sg(cm0,y,2);
+y1 = sg(cm1,y,2);
+y2 = sg(cm2,y,2); 
+
+figure;
+subplot(2,2,1)
+plot(x,y); box on; grid on;
+
+subplot(2,2,2)
+plot(x,y0); box on; grid on;
+
+subplot(2,2,3)
+plot(x,y1/dx); box on; grid on;
+
+subplot(2,2,4)
+plot(x,y2/dx.^2); box on; grid on;
+
Index: /hypertools/hypertools/showsi.m
===================================================================
--- /hypertools/hypertools/showsi.m	(revision 3)
+++ /hypertools/hypertools/showsi.m	(revision 3)
@@ -0,0 +1,278 @@
+% SHOWSI Show spectral image
+%
+%   H=SHOWSI(DATA,FORMAT)
+%
+% INPUT
+%    DATA     spectral image as a dip_image object
+%    FORMAT   optional data format for conversion to dip_image
+%             (def: 'double') for info, see dip_image
+%
+% OUTPUT
+%    H        handle of the spectral visualization tool
+%
+% DESCRIPTION
+% 1. Visualization mode (default)
+% Input dataset or a dip_image with spectral data is visualized in two
+% windows: 2D spatial image and spectral plot.  Moving over the spatial
+% image, the spectrum at a given spot is rendered in the spectral plot.  By
+% clicking, points may be emphasized in the spatial image. Their spectra
+% get drawn in the spectral figure. Three different colors may be used to
+% distinguish the points/spectra. The set of points may be retrieved as a
+% dataset using the si_get_spectra command. The band, shown in the
+% spatial image may be interactively changed by clicking and dragging a
+% line in the spectral figure.
+%
+% 2. Area measurement mode
+% Area mode, invoked from the Actions menu in the spatial image, allows the
+% user to define line in the spectrum used for measuring the area.  First,
+% the desired spectrum is selected by moving the mouse pointer over the
+% spatial image. By clicking, the spectrum is fixed and the two points may
+% be selected in the spectral figure forming a line. An image is generated
+% with color reflecting the area between the spectrum and the line.  Right
+% mouse button cancels the last step.
+%
+% Additional images depicting the same object may be attached to the
+% specral image. Dragging the mouse over the image shows corresponding
+% spectrum from the spectral image.
+%
+% SEE ALSO
+% SI_ATTACH_DISPLAY, SI_DETTACH_DISPLAY, SI_GET_SPECTRA, SI_SET_YLIM
+
+% $Id: showsi.m,v 1.18 2007/03/01 14:11:07 serguei Exp $
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function h=showsi(data,format)
+
+	if isa(data,'dataset')
+		%XXX
+    % copy of all the user's data
+	  user=data.user;
+		
+    if ~isempty(user) & isfield(user, 'type') & strcmp(user.type,'spectra') ...
+    %& isfield(data.user, 'format') & (strcmp(data.user.format,'FTIR converted from bio-rad') | strcmp(data.user.format,'FTIR converted from Varian'))
+      if isfield(user,'start_wavelength') & ~isempty(user.start_wavelength) & isfield(user,'step') & ~isempty(user.step)
+			% set of bands
+			  bands=user.start_wavelength:user.step:user.start_wavelength+(size(data,2)-1)*user.step;
+      else
+        bands = data.featlab;
+        if ischar(bands)
+          bands = str2num(bands);
+          if isempty(bands)
+            clear bands;  
+          end
+        end
+      end
+      
+      % band axis units
+			if isfield(user,'units') & ~isempty(user.units)
+        units=user.units;
+      else
+        units = '';
+      end
+    end
+
+    if ~exist('format','var'), format='double'; end
+		data=data2dip(data,format);
+	end
+	
+	if ~isa(data,'dip_image')
+		error('dip_image required')
+	end
+	
+	if length(size(data))~=3
+		error('spectral image (3D array) is required');
+	end
+	
+	% generate default set of bands?
+	if ~exist('bands','var')
+		bands=1:size(data,3);
+		units='1';
+		user=[];
+	end
+	
+	% primary image (pim): spectral image as a dipimage
+	hpim=dipshow(data,'percentile','notruesize');
+	udpim=get(hpim,'UserData');
+	udpim.si_type='primary image'; % this is the primary image display
+	updim.si_ax=gca;
+	
+	% spec: spectral domain figure
+	hspec=figure;
+	%XXX
+  t = get(hspec,'position');
+  t([2,4]) = t([2,4])+[-0.1,+0.1]*t(4);
+  set(hspec,'position',t);
+
+  udspec=get(hspec,'UserData');	
+	udspec.si_type='spectral plot'; % this is the spectral plot
+	udspec.si_ax=gca;
+	set(udspec.si_ax,'units','normalized');
+  %XXX
+  t = get(udspec.si_ax,'position');  
+  t([2,4]) = t([2,4])+[0.1,-0.1]*t(4);;
+  set(udspec.si_ax,'position',t);
+
+	% link from one objects to another
+	udpim.hspec=hspec;
+	udpim.hpim=hpim; % handle to itself
+	udspec.hpim=hpim;
+	udspec.hspec=hspec; % handle to itself
+
+	udspec.si_bands=bands; % set of spectral bands
+	udpim.si_bands=bands; % used often -> stored in both
+	
+	udspec.si_units=units;
+	udpim.si_points=[]; % coordinates of selected points ( [x,y,label] )
+	udpim.si_user=user; % user data defining spectral dataset
+
+	udpim.si_attached_displays=[]; % handle to attached displays
+	udpim.si_attached_scatters=[]; % handle to attached scatterd
+	
+	set(hspec,'busyaction','cancel','DoubleBuffer','on')
+
+	% plot the spectral curve which will be used for fast updates
+	udspec.si_templine=plot(bands,zeros(size(data,3),1),'-','color',[0.5 0.5 0.5]);
+	if strcmp(units,'cm^-1')
+		set(udspec.si_ax,'XDir','reverse')
+	end
+	hold on
+
+	set(udspec.si_ax,'xlim',[min(bands) max(bands)])
+	t=max(max(data));
+	set(udspec.si_ax,'ylim',[0 t])
+	
+	udspec.si_cursliceline=plot([bands(udpim.curslice+1) bands(udpim.curslice+1)],...
+				    [0 t],...
+				    '-','color',[1 0 0]);
+	udspec.si_movement=0; % the band movement is switched off in
+			      % the beginning
+	set(hspec,'WindowButtonDownFcn','showsi_update(''down_spec'')');	
+
+	% radion buttons for classes
+	
+	% class color palette 
+	%udspec.si_classcolmap=[... 	
+  %       0         0    1.0000; ...
+  %       0    0.5000         0; ...
+  %  1.0000         0         0; ...
+  %       0    0.7500    0.7500; ...
+  %  0.7500         0    0.7500; ...
+  %  0.7500    0.7500         0; ...
+  %  0.2500    0.2500    0.2500];
+ 	%udspec.si_classcolnam={'blue'; 'green';'red';'cyan';'magenta';'yellow';'black'};
+	
+  udspec.si_classcolmap=get_spec_colormap;
+ 	% remove white
+  udspec.si_classcolmap(all(udspec.si_classcolmap == 1,2), :) = [];
+	% put black at the end
+  udspec.si_classcolmap(all(udspec.si_classcolmap == 0,2), :) = [];
+  udspec.si_classcolmap(end+1,:) = [0 0 0];
+  udspec.si_classcolnam=num2cell([repmat('class',[size(udspec.si_classcolmap,1) 1]), ...
+                        num2str((1:size(udspec.si_classcolmap,1))')], 2);
+	
+  udspec.si_class=1;
+  udpim.si_classcolmap=udspec.si_classcolmap; % colormap is stored in both pim and spec
+
+
+  % area mode: points in the spec figure (fast update)
+	udspec.si_area_line=plot([0 0],[0 0]);
+
+	set(udspec.si_area_line,'visible','off');
+	set(udspec.si_area_line, 'color', [0 0 1],'marker','.');
+
+	udspec.si_lst=uicontrol('style','listbox','value',1,...
+			       'string',udspec.si_classcolnam,...
+			       'units','normalized',...
+             'ButtonDownFcn','',...
+			       'callback','showsi_update(''lst'')');
+	%keyboard
+  t=get(udspec.si_ax,'position');
+	set(udspec.si_lst,'position',[t(1) 0.02 0.2 0.12]);
+	
+  plotcolor = udspec.si_classcolmap(udspec.si_class,:);
+  weights = [1; 1.5; 0.5]; 
+  if sum(plotcolor*weights/sum(weights)) >= 0.5
+    textcolor = [0 0 0];
+  else
+   textcolor = [1 1 1];
+  end
+  udspec.si_colindicator=uicontrol('style','text','backgroundcolor',udspec.si_classcolmap(1,:),...
+                                   'foregroundcolor',plotcolor,'string',{'class', 'color'}, ...
+                                   'fontweight', 'normal', 'fontangle','normal',...
+                                   'units','normalized','position',[t(1)-0.08 0.02 0.07 0.06]);
+  
+  
+  %set(udspec.si_lst,'position',[t(1) 0.02 0.2 0.05]);
+  
+  
+  
+  
+  if 0
+	% button 1
+	udspec.si_rb1=uicontrol('style','radio','value',1,...
+			       'string','blue',...
+			       'units','normalized',...
+				'ButtonDownFcn','',...
+			       'callback','showsi_update(''rb'',1)');
+	t=get(udspec.si_rb1,'extent');
+	set(udspec.si_rb1,'position',[0.1 0.02 1.5*t(3) 1.01*t(4)]);
+
+	% button 2
+	udspec.si_rb2=uicontrol('style','radio','value',0,...
+			       'string','red',...
+			       'units','normalized',...
+			       'callback','showsi_update(''rb'',2)');
+	t2=get(udspec.si_rb2,'extent');
+	set(udspec.si_rb2,'position',[0.25 0.02 1.5*t2(3) 1.01*t2(4)]);
+
+	% button 3
+	udspec.si_rb3=uicontrol('style','radio','value',0,...
+			       'string','green',...
+			       'units','normalized',...
+			       'callback','showsi_update(''rb'',3)');
+	t=get(udspec.si_rb3,'extent');
+	set(udspec.si_rb3,'position',[0.4 0.02 1.5*t(3) 1.01*t(4)]);
+	end
+	
+	% update window titles
+	set(hpim,'Name',sprintf('band: %f', bands(udpim.curslice+1)));
+	set(hspec,'Name',sprintf(' band: %f ',bands(udpim.curslice+1)));
+	
+	set(hpim,'WindowButtonDownFcn','showsi_update(''down_dip'')');
+	set(hpim,'WindowButtonMotionFcn','showsi_update(''motion_dip'')');	
+
+	% closing one window must close the other one:
+	set(hpim,'CloseRequestFcn','showsi_update(''close'')');
+	set(hspec,'CloseRequestFcn','showsi_update(''close'')');
+
+	% store the handles in both plots
+	set(hpim,'UserData',[]);
+	set(hpim,'UserData',udpim);
+	
+	set(hspec,'UserData',[]);
+	set(hspec,'UserData',udspec);
+	
+	% adjust the pim figure menu bar
+	h = findobj(hpim,'Type','uimenu','tag','actions');
+	% visualization mode selector
+	uimenu(h,'Label','spectra visualisation','Tag', ...
+	       'mouse_si_visualisation','Callback','si_setvismode(gcbf);');
+	% put the menu item to the first position:
+	h2=get(h,'children');
+	set(h,'children',[h2(2:end);h2(1)]);
+	si_setvismode(hpim);	
+
+	% area mode
+	uimenu(h,'Label','spectra area','Tag', ...
+	       'mouse_si_area','Callback','si_setareamode(gcbf);');
+	% put the menu item to the first position:
+	h2=get(h,'children');
+	set(h,'children',[h2(2:end-1);h2(1);h2(end)]);
+	
+	
+	h=hpim;
+	
+	return
Index: /hypertools/hypertools/showsi_update.m
===================================================================
--- /hypertools/hypertools/showsi_update.m	(revision 3)
+++ /hypertools/hypertools/showsi_update.m	(revision 3)
@@ -0,0 +1,470 @@
+% SHOWSI_UPDATE - callback functions for showsi
+%
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function showsi_update(arg1,arg2)
+
+ fig=gcbf;
+
+ 
+ switch lower(arg1)
+
+  case 'down_dip_area1'
+   % area mode: 1st stage
+   % when clicked, we color the current spectrum and switch to the
+   % 2nd stage where range is defined in the spectral figure
+
+   if strncmp(get(fig,'Tag'),'DIP_Image',9)
+    img = get(fig,'CurrentObject');
+    if strcmp(get(img,'Type'),'image')
+
+     udim = get(fig,'UserData');
+     udpim = get(udim.hpim,'UserData');
+     udspec=get(udim.hspec,'UserData');
+
+     % by the left button, we draw the spectrum under the pointer
+     udim.si_ax = get(img,'Parent');
+     udim.oldAxesUnits = get(udim.si_ax,'Units');
+     udim.oldNumberTitle = get(fig,'NumberTitle');
+     set(udim.si_ax,'Units','pixels');
+
+     pt = dipfig_getcurpos(udim.si_ax);	
+
+     % get the spectrum from the primary image
+     data=double(squeeze(udpim.slices(pt(1),pt(2),:)));
+
+     % update the prepared line in the spec plot
+     set(udspec.si_templine,'ydata',data);
+     
+     % change the color to indicate the mode change
+     set(udspec.si_templine,'color',[0 0 1]);
+
+     % second mode, no motion tracked in pim window
+     set(fig,'WindowButtonDownFcn','showsi_update(''down_dip_area2'')');
+     set(fig,'WindowButtonMotionFcn','');	
+     % area2 mode for plotting points on the spectrum
+     set(udpim.hspec,'WindowButtonMotionFcn','showsi_update(''motion_spec_area2'')');	
+     set(udpim.hspec,'WindowButtonDownFcn','showsi_update(''down_spec_area2'')');	
+
+     % draw the first points
+     set(udspec.si_area_line,'visible','on');
+     %XXX
+     %set(udim.si_ax,'Units',udim.oldAxesUnits);
+     set(udim.si_ax,'Units','normalized');
+    end
+   end  
+   
+   
+  case 'down_dip_area2'
+   % area mode: 2nd stage
+   % when right-button is clicked, we return back to the 1st stage
+
+   if strncmp(get(fig,'Tag'),'DIP_Image',9)
+    img = get(fig,'CurrentObject');
+    if strcmp(get(img,'Type'),'image')
+
+     if strcmp(get(fig,'SelectionType'),'alt')
+     
+      % right button -> go back to the 1st stage
+      udim = get(fig,'UserData');
+      udpim = get(udim.hpim,'UserData');
+      udspec=get(udim.hspec,'UserData');
+
+      % change the color to indicate the mode change
+      set(udspec.si_templine,'color',[0.5 0.5 0.5]);
+      
+      set(fig,'WindowButtonDownFcn','showsi_update(''down_dip_area1'')');
+      set(fig,'WindowButtonMotionFcn','showsi_update(''motion_dip'')');	
+      % switch off area more
+      set(udpim.hspec,'WindowButtonMotionFcn','');	
+      set(udspec.si_area_line,'visible','off');
+      
+     end
+    end
+   end
+
+  case 'motion_spec_area2'
+   
+   % moving the first points along the spectral curve
+   
+   udspec = get(fig,'UserData');
+   udpim = get(udspec.hpim,'UserData');
+
+   set(udspec.si_ax,'Units','pixels');
+   pt = dipfig_getcurpos(udspec.si_ax);	
+
+   data=get(udspec.si_templine,'ydata');
+
+   [m,ind]=min(abs(udspec.si_bands-pt(1)));
+
+   set(udspec.si_area_line,'xdata',[pt(1) pt(1)]);
+   set(udspec.si_area_line,'ydata',[data(ind) data(ind)]);
+   
+   set(fig,'UserData',[]);
+   set(fig,'UserData',udspec);
+   
+   %XXX
+   set(udspec.si_ax,'Units','normalized');
+
+  case 'down_spec_area2'
+   % area mode: 2nd stage
+   % left button defines the first point and switches to the 3rd stage
+   % (definition of the second point)
+
+   if ~strcmp(get(fig,'SelectionType'),'alt')
+     
+      udspec=get(fig,'UserData');
+      udpim = get(udspec.hpim,'UserData');
+
+      set(udspec.si_area_line,'color',[1 0 0]);
+      
+      set(fig,'WindowButtonDownFcn','showsi_update(''down_spec_area3'')');
+      set(fig,'WindowButtonMotionFcn','showsi_update(''motion_spec_area3'')');	
+      
+   end
+
+  case 'motion_spec_area3'
+   
+   % moving the 2nd point and line
+   
+   udspec = get(fig,'UserData');
+   udpim = get(udspec.hpim,'UserData');
+
+   set(udspec.si_ax,'Units','pixels');
+   pt = dipfig_getcurpos(udspec.si_ax);	
+
+   data=get(udspec.si_templine,'ydata');
+
+   [m,ind]=min(abs(udspec.si_bands-pt(1)));
+
+   x=get(udspec.si_area_line,'xdata');
+   y=get(udspec.si_area_line,'ydata');
+   set(udspec.si_area_line,'xdata',[x(1) pt(1)]);
+   set(udspec.si_area_line,'ydata',[y(1) data(ind)]);
+   
+   set(fig,'UserData',[]);
+   set(fig,'UserData',udspec);
+
+   %XXX
+   set(udspec.si_ax,'Units','normalized');
+
+  case 'down_spec_area3'
+   % area mode: 3rd stage
+   % left button defines the second point 
+   % right button returns to the 2nd stage
+
+   udspec=get(fig,'UserData');
+   udpim = get(udspec.hpim,'UserData');
+   x=get(udspec.si_area_line,'xdata');
+   y=get(udspec.si_area_line,'ydata');
+   
+   if strcmp(get(fig,'SelectionType'),'alt')
+
+    set(udspec.si_area_line,'xdata',[x(1) x(1)]);
+    set(udspec.si_area_line,'ydata',[y(1) y(1)]);
+    
+    set(udspec.si_area_line,'color',[0 0 1]);
+      
+    set(udpim.hspec,'WindowButtonMotionFcn','showsi_update(''motion_spec_area2'')');	
+    set(udpim.hspec,'WindowButtonDownFcn','showsi_update(''down_spec_area2'')');	
+    
+   else
+    % left button defines second point
+    set(udspec.si_area_line,'color',[0 0 1]);
+    
+    set(fig,'WindowButtonDownFcn','showsi_update(''down_spec_area3'')');
+    set(fig,'WindowButtonMotionFcn','');
+
+    [m,ind1]=min(abs(udspec.si_bands-x(1)));
+    [m,ind2]=min(abs(udspec.si_bands-x(2)));    
+    % generate the area image
+    im=chemimage(udpim.slices,[ind1 ind2]);
+    imh=dipshow(figure,im,'percentile','notruesize');
+    % change the colormap
+    set(imh,'colormap',jet(256));
+%    si_attach_display(udpim.hpim,imh);
+   end
+   
+   
+  case 'down_dip'
+   % general dip visualization
+   if strncmp(get(fig,'Tag'),'DIP_Image',9)
+    img = get(fig,'CurrentObject');
+    if strcmp(get(img,'Type'),'image')
+
+     udim = get(fig,'UserData');
+     udpim = get(udim.hpim,'UserData');
+     udspec=get(udim.hspec,'UserData');
+
+     if strcmp(get(fig,'SelectionType'),'alt')
+      % by right button, we clear the axis from all tagged points
+      h=findobj(get(udspec.si_ax,'children'),'type','line','tag','spectra');
+      delete(h);
+      % delete the points in the primary one
+      h=findobj(get(udim.hpim,'children'),'type','line','tag','spectra');
+      delete(h);
+      
+      % delete the points from all the attached images
+      for i=1:length(udpim.si_attached_displays)
+       h=findobj(get(udpim.si_attached_displays(i),'children'),...
+		 'type','line','tag','spectra');
+       delete(h);
+      end
+
+      % delete stored point coordinates
+      udpim.si_points=[];
+     else
+      % by the left button, we draw the
+      % spectrum under the pointer
+      udim.si_ax = get(img,'Parent');
+      udim.oldAxesUnits = get(udim.si_ax,'Units');
+      udim.oldNumberTitle = get(fig,'NumberTitle');
+      set(udim.si_ax,'Units','pixels');
+
+      pt = dipfig_getcurpos(udim.si_ax);	
+
+      % get the spectrum from the primary image
+      data=double(squeeze(udpim.slices(pt(1),pt(2),:)));
+
+      % update the list of points
+      udpim.si_points=[udpim.si_points; pt(1), pt(2), udspec.si_class];
+      
+      % draw points also in the primary one
+      figure(udim.hpim);
+      h=line([pt(1) pt(1)],[pt(2),pt(2)]);
+      set(h, 'color', udspec.si_classcolmap(udspec.si_class,:),...
+	     'marker','.','tag','spectra');
+      
+      % draw the points in all attached images
+      for i=1:length(udpim.si_attached_displays)
+       figure(udpim.si_attached_displays(i));
+       h=line([pt(1) pt(1)],[pt(2),pt(2)]);
+       set(h, 'color', udspec.si_classcolmap(udspec.si_class,:),...
+	      'marker','.','tag','spectra');
+      end
+      
+      % draw the whole spectrum in the spec figure
+      figure(udim.hspec);
+      h=plot(udspec.si_bands,data,'color', udspec.si_classcolmap(udspec.si_class,:),...
+	     'tag','spectra');
+     
+      %XXX
+      %set(udim.si_ax,'Units',udim.oldAxesUnits);
+      set(udim.si_ax,'Units','normalized');
+     end
+
+     set(fig,'UserData',[]);
+     set(fig,'UserData',udim);
+
+     set(udim.hpim,'UserData',[]);
+     set(udim.hpim,'UserData',udpim);
+
+     set(udim.hspec,'UserData',[]);
+     set(udim.hspec,'UserData',udspec);
+    end
+   end
+
+  case 'motion_dip'
+
+   if strncmp(get(fig,'Tag'),'DIP_Image',9)
+    img = findobj(fig,'type','image');
+    if ~isempty(img)
+     udim = get(fig,'UserData');
+     udim.si_ax = get(img,'Parent');
+     udim.oldAxesUnits = get(udim.si_ax,'Units');
+     udim.oldNumberTitle = get(fig,'NumberTitle');
+     set(udim.si_ax,'Units','pixels');
+     pt = dipfig_getcurpos(udim.si_ax);	
+
+     % get spectrum from the primary image
+     udpim = get(udim.hpim,'UserData');
+     objsize=size(udpim.slices);
+     data=double(squeeze(udpim.slices(pt(1),pt(2),:)));
+     
+     % update the prepared line in the spec plot
+     udspec = get(udim.hspec,'UserData');			  
+     set(udspec.si_templine,'ydata',data);
+     
+     if fig ~= udim.hpim
+      if isfield(udim,'curslice') % only for higher dim images
+       % this image is an attached one
+       set(fig,'Name',sprintf('%d (%d,%d) value: %5.3f, band: %d',...
+			      objsize(2)*pt(1)+pt(2)+1,pt(1),pt(2), udim.curslice+1,data(udim.curslice+1) ));
+      end
+     else
+      % this picture is a primary image (pim)
+      set(fig,'Name',sprintf('%d (%d,%d) band:%d, val:%5.3f',...
+			     objsize(2)*pt(1)+pt(2)+1,pt(1),pt(2), udim.si_bands(udim.curslice+1),data(udim.curslice+1)));
+     end
+     
+     % possible scatterd updates
+     if ~isempty(udpim.si_attached_scatters)
+	     for i=1:length(udpim.si_attached_scatters)
+		     fig=udpim.si_attached_scatters(i);
+		     ud=get(fig,'userdata');
+
+		     data=+ud.a( pt(1)*objsize(2)+pt(2)+1, ...
+				 [ ud.xdim, ud.ydim ] );
+
+		     obj=findobj(fig,'tag','fastupdate');
+		     if isempty(obj)
+			     % create the point object
+			     figure(fig);
+			     ud.si_point = plot([data(1) data(1)],[data(2) data(2)],'o','color',[0 0 0]);
+			     set(ud.si_point,'markersize',9,'markerfacecolor',[1 1 0]);
+			     set(ud.si_point,'tag','fastupdate');
+		     else
+			     % the point exists
+			     set(obj,'visible','on','color',[0 0 0]);
+			     set(obj,'xdata',[data(1),data(1)]);
+			     set(obj,'ydata',[data(2),data(2)]);		     
+		     end
+	     
+		     set(fig, 'Name',sprintf('id %d', pt(1)*objsize(2)+pt(2)+1));
+
+		     set(fig,'UserData',[]);
+		     set(fig,'UserData',ud);
+	     end
+     end
+     %XXX
+     %set(udim.si_ax,'Units',udim.oldAxesUnits);
+     set(udim.si_ax,'Units','normalized');
+    end
+   end
+
+  case 'down_spec'
+   % visualization mode: move through bands
+   udspec = get(fig,'UserData');
+   udpim = get(udspec.hpim,'UserData');
+   if udspec.si_movement==0
+    udspec.si_movement=1;
+    set(fig,'WindowButtonMotionFcn', 'showsi_update(''motion_spec'')');	
+    set(udspec.si_ax,'Units','pixels');
+    pt = dipfig_getcurpos(udspec.si_ax);	
+    % points are in the range of bands, find corresponding index:
+    [m,ind]=min(abs(udspec.si_bands-pt(1)));
+    udpim.curslice=ind-1;	  
+    set(udspec.si_cursliceline,'xdata',[ind ind]);
+    dipmapping(udspec.hpim,'slice',udpim.curslice);
+
+    set(fig,'UserData',[]);
+    set(fig,'UserData',udspec);
+    set(udspec.hpim,'UserData',[]);
+    set(udspec.hpim,'UserData',udpim);
+    %XXX
+    set(udspec.si_ax,'Units','normalized');
+   else
+    udspec.si_movement=0;
+    set(fig,'WindowButtonMotionFcn','');
+    set(fig,'UserData',[]);
+    set(fig,'UserData',udspec);
+   end
+
+  case 'motion_spec'
+   
+   udspec = get(fig,'UserData');
+   udpim = get(udspec.hpim,'UserData');
+   set(udspec.si_ax,'Units','pixels');
+   pt = dipfig_getcurpos(udspec.si_ax);	% we copied the dip private function
+   set(udspec.si_cursliceline,'xdata',[pt(1) pt(1)]);
+   % points are in the range of bands, find corresponding index:
+   [m,ind]=min(abs(udspec.si_bands-pt(1)));
+   udpim.curslice=ind-1;	  
+   % update dip_image display
+   dipmapping(udspec.hpim,'slice',udpim.curslice);
+   set(fig,'Name',sprintf(' band: %5.3f ',udspec.si_bands(udpim.curslice+1)));
+
+   set(fig,'UserData',[]);
+   set(fig,'UserData',udspec);
+   set(udspec.hpim,'UserData',[]);
+   set(udspec.hpim,'UserData',udpim);
+
+   %XXX
+   set(udspec.si_ax,'Units','normalized');
+  
+  %case 'rb'
+   
+   %udspec = get(fig,'UserData');	  
+   %udspec.si_class=arg2;
+   %eval(sprintf('set(udspec.si_rb%d,''value'',%d);',arg2,1));
+   %others=setdiff(1:3,arg2);
+   %for i=1:length(others)	
+   % eval(sprintf('set(udspec.si_rb%d,''value'',%d);',others(i),0));
+   %end
+   
+   %set(fig,'UserData',[]);
+   %set(fig,'UserData',udspec);
+   
+  case 'lst'
+   udspec = get(fig,'UserData');	  
+   udspec.si_class=get(udspec.si_lst,'value');
+
+   plotcolor = udspec.si_classcolmap(udspec.si_class,:);
+   weights = [1; 1.5; 0.5]; 
+   if sum(plotcolor*weights/sum(weights)) >= 0.5
+     textcolor = [0 0 0];
+   else
+     textcolor = [1 1 1];
+   end
+
+   if 0
+   %textcolor = 1 - repmat(mean(plotcolor),[1 3]);
+   textcolor = rgb2hsv(1-plotcolor);
+   textcolor(2) = 0.5*textcolor(2);
+   textcolor = hsv2rgb(textcolor);
+   end
+
+   set(udspec.si_colindicator,'backgroundcolor',plotcolor,'foregroundcolor',textcolor);
+
+
+   %eval(sprintf('set(udspec.si_rb%d,''value'',%d);',arg2,1));
+   %others=setdiff(1:3,arg2);
+   %for i=1:length(others)	
+   % eval(sprintf('set(udspec.si_rb%d,''value'',%d);',others(i),0));
+   %end
+   
+   set(fig,'UserData',[]);
+   set(fig,'UserData',udspec);
+   
+
+
+  case 'close'
+   ud = get(fig,'UserData');
+   udpim = get(ud.hpim,'UserData');
+
+   % update closereq callbacks of attached displays and scatters
+   for i=1:length(udpim.si_attached_displays)
+	   si_dettach_display(ud.hpim,udpim.si_attached_displays(i));
+   end
+   for i=1:length(udpim.si_attached_scatters)
+	   si_dettach_display(ud.hpim,udpim.si_attached_scatters(i));
+   end
+   if fig==ud.hpim
+    delete(ud.hspec);
+   elseif fig==ud.hspec
+    delete(ud.hpim);
+   end
+   delete(fig)
+   
+  case 'close_attached_display'
+   ud = get(fig,'UserData');
+   % it's an attached image: remove its handle from the list
+   udpim = get(ud.hpim,'UserData');
+   udpim.si_attached_displays=setdiff(udpim.si_attached_displays,fig);
+   set(ud.hpim,'UserData',[]);
+   set(ud.hpim,'UserData',udpim);
+   delete(fig);
+
+  case 'close_attached_scatter'
+   ud = get(fig,'UserData');
+   % it's an attached scatter: remove its handle from the list
+   udpim = get(ud.hpim,'UserData');
+   udpim.si_attached_scatters=setdiff(udpim.si_attached_scatters,fig);
+   set(ud.hpim,'UserData',[]);
+   set(ud.hpim,'UserData',udpim);
+   delete(fig);
+   
+ end
Index: /hypertools/hypertools/si_attach_display.m
===================================================================
--- /hypertools/hypertools/si_attach_display.m	(revision 3)
+++ /hypertools/hypertools/si_attach_display.m	(revision 3)
@@ -0,0 +1,80 @@
+%SI_ATTACH_DISPLAY Attach an additional display to the spectral image
+%
+%  SI_ATTACH_DISPLAY(SIH,IMH)
+%
+% INPUT
+%   SIH    spectral image handle (see showsi)
+%   IMH    figure handle to be attached
+%
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function si_attach_display(sih,imh)
+	
+	udpim=get(sih,'userdata');
+	udim=get(imh,'userdata');
+
+	% fill in mandatory fields
+	udim.hpim=sih; % link to the primary image
+	udim.hspec=udpim.hspec; % link to the spectral figure
+	udim.si_ax = get(imh,'CurrentAxes'); % image's axes
+
+	% what figure we attach?
+	tag=get(imh,'tag');
+
+	if strcmp(tag,'scatterdui')
+	
+		% it is the scatterdui figure
+
+		% update the list of attached figures
+		udpim.si_attached_scatters=[udpim.si_attached_scatters imh];
+		
+		% create the point object
+		udim.si_point = plot([0 0],[0 0],'o','color',[0 0 0]);
+		set(udim.si_point,'markersize',9,'markerfacecolor',[1 1 0]);
+		set(udim.si_point,'visible','off');
+		set(udim.si_point,'tag','fastupdate');
+
+		set(imh,'CloseRequestFcn','showsi_update(''close_attached_scatter'')');		
+	else
+		
+		% it is the dip_image figure
+
+		% update the list of attached figures
+		udpim.si_attached_displays=[udpim.si_attached_displays imh];
+		
+		% display all points already shown in the primary image
+		t=udpim.si_points;
+		figure(imh);
+		for i=1:size(t,1)
+			h=line([t(i,1) t(i,1)],[t(i,2),t(i,2)]);
+			set(h, 'color', udpim.si_classcolmap(t(i,3),:),'marker','.');
+		end
+
+		% add menu items
+		h = findobj(imh,'Type','uimenu','tag','actions');
+		% visualization mode selector
+		uimenu(h,'Label','spectra visualisation','Tag', ...
+		       'mouse_si_visualisation','Callback','si_setvismodeatt(gcbf);');
+		% put the menu item to the first position:
+		h2=get(h,'children');
+		set(h,'children',[h2(2:end);h2(1)]);
+		si_setvismodeatt(imh);	
+		
+		% set the callbacks
+		set(imh,'WindowButtonMotionFcn','showsi_update(''motion_dip'')');	
+		set(imh,'WindowButtonDownFcn','showsi_update(''down_dip'')');
+		set(imh,'CloseRequestFcn','showsi_update(''close_attached_display'')');
+
+	end
+		
+	% store the handles in both plots
+	set(sih,'UserData',[]);
+	set(sih,'UserData',udpim);
+
+	set(imh,'UserData',[]);
+	set(imh,'UserData',udim);	
+
+	
Index: /hypertools/hypertools/si_dettach_display.m
===================================================================
--- /hypertools/hypertools/si_dettach_display.m	(revision 3)
+++ /hypertools/hypertools/si_dettach_display.m	(revision 3)
@@ -0,0 +1,71 @@
+%SI_DETTACH_DISPLAY Dettach an additional display to the spectral image
+%
+%  SI_DETTACH_DISPLAY(SIH,IMH)
+%
+% INPUT
+%   SIH    spectral image handle (see showsi)
+%   IMH    figure handle to be dettached
+%
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function si_dettach_display(sih,imh)
+ 
+	udpim=get(sih,'userdata');
+	udim=get(imh,'userdata');
+	
+	if udim.hpim ~= udpim.hpim
+		error('the display is attached to a different spectral image');
+	end
+	
+	% remove added fields
+	udim=rmfield(udim,{'hpim','hspec','si_ax'});
+
+	% what figure we attach?
+	tag=get(imh,'tag');
+
+	if strcmp(tag,'scatterdui')
+
+		% update callbacks
+		set(imh,'CloseRequestFcn','closereq');
+		
+		% remove the point
+		delete(udim.si_point);
+		udim=rmfield(udim,{'si_point'});
+		
+		% remove the link to this display from the list in pim
+		udpim.si_attached_scatters=setdiff(udpim.si_attached_scatters,imh);
+		
+	else
+		
+		% remove all the points from this figure
+		h=findobj(get(imh,'children'),'type','line');
+		delete(h);
+		
+		% remove spectral menus
+		h = findobj(imh,'Type','uimenu','tag','actions');
+		h = findobj(gcf,'Type','uimenu','tag','mouse_si_visualisation');
+		delete(h);
+		udim.state = 'none';
+		dipfig_set_action_check(imh,'none');
+		set(imh,'pointer','arrow') 
+		
+		% update callbacks
+		set(imh,'WindowButtonMotionFcn','');	
+		set(imh,'WindowButtonDownFcn','');
+		set(imh,'CloseRequestFcn','closereq');
+		
+		% remove the link to this display from the list in pim
+		udpim.si_attached_displays=setdiff(udpim.si_attached_displays,imh);
+		
+	end
+	% update user data
+	set(sih,'UserData',[]);
+	set(sih,'UserData',udpim);
+
+	set(imh,'UserData',[]);
+	set(imh,'UserData',udim);	
+	
+	return
Index: /hypertools/hypertools/si_get_spectra.m
===================================================================
--- /hypertools/hypertools/si_get_spectra.m	(revision 3)
+++ /hypertools/hypertools/si_get_spectra.m	(revision 3)
@@ -0,0 +1,35 @@
+% SI_GET_SPECTRA Get spectra marked in spectral image
+%
+%     A = SI_GET_SPECTRA(SIH)
+%
+% INPUT
+%  SIH    spectral image handle (see showsi)
+%
+% OUTPUT
+%  A      output dataset
+%
+
+% $Id: si_get_spectra.m,v 1.5 2005/02/10 15:24:07 pavel Exp $
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function a=si_get_spectra(sih)
+	
+	udpim=get(sih,'userdata');
+	
+	t=udpim.si_points;
+	
+	bandc=udpim.imsize(3);
+	a=zeros(size(t,1),bandc);
+	im=udpim.slices; % image data
+	for i=1:size(t,1)
+		a(i,:)=reshape(double(im(t(i,1),t(i,2),:)),1,bandc);
+	end
+	a=dataset(a,t(:,3));
+	a.user=udpim.si_user;
+	
+	% set the objects identifiers to linear image indices
+	objsize=size(im);
+	a.ident=[t(:,1)*objsize(2)+t(:,2)+1];
Index: /hypertools/hypertools/si_set_ylim.m
===================================================================
--- /hypertools/hypertools/si_set_ylim.m	(revision 3)
+++ /hypertools/hypertools/si_set_ylim.m	(revision 3)
@@ -0,0 +1,28 @@
+% SI_SET_YLIM Set the ylim of the spectral figure
+%
+%    SI_SET_YLIM(SIH,YLIM)
+%
+% INPUT
+%   SIH     spectral image handle
+%   YLIM    y axis limit (scalar value)
+%
+
+% $Id: si_set_ylim.m,v 1.5 2005/02/10 15:24:07 pavel Exp $
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+
+function si_set_ylim(sih,ylim)
+	
+	udpim=get(sih,'userdata');
+	udspec=get(udpim.hspec,'userdata');
+	
+	if length(ylim)==1
+		ylim=[0 ylim];
+	end
+	set(udspec.si_ax,'ylim',ylim);
+	set(udspec.si_cursliceline,'ydata',ylim);
+	
+	return
Index: /hypertools/hypertools/si_setareamode.m
===================================================================
--- /hypertools/hypertools/si_setareamode.m	(revision 3)
+++ /hypertools/hypertools/si_setareamode.m	(revision 3)
@@ -0,0 +1,23 @@
+% SI_SET_AREA_MODE classification of road signs using dissimilarities
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function si_setareamode(fig)
+ 
+  ud=get(fig,'userdata');
+  ud.state = 'si_area';
+  dipfig_set_action_check(fig,'si_area');
+  set(fig,'pointer','cross') 
+
+  udspec=get(ud.hspec,'userdata');
+  
+  % remove additional lines from spec
+  h=findobj(get(ud.hspec,'children'),'type','line',...
+	    'tag', 'spectra'); % remove only tagged objects
+  delete(h);
+  
+  set(fig,'WindowButtonDownFcn','showsi_update(''down_dip_area1'')');
+  set(fig,'WindowButtonMotionFcn','showsi_update(''motion_dip'')');	
+  set(fig,'CloseRequestFcn','showsi_update(''close'')');
Index: /hypertools/hypertools/si_setvismode.m
===================================================================
--- /hypertools/hypertools/si_setvismode.m	(revision 3)
+++ /hypertools/hypertools/si_setvismode.m	(revision 3)
@@ -0,0 +1,22 @@
+% SI_SETVISMODE internal routine for setting up spectra visualization mode
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function si_setvismode(fig)
+ 
+ ud=get(fig,'userdata');
+ ud.state = 'si_visualisation';
+ dipfig_set_action_check(fig,'si_visualisation');
+ set(fig,'pointer','cross') 
+
+ set(fig,'WindowButtonDownFcn','showsi_update(''down_dip'')');
+ set(fig,'WindowButtonMotionFcn','showsi_update(''motion_dip'')');	
+ set(fig,'CloseRequestFcn','showsi_update(''close'')');
+
+ udspec=get(ud.hspec,'userdata');
+ set(udspec.si_area_line,'visible','off');
+ set(udspec.si_templine,'color',[0.5 0.5 0.5]);
+ set(udspec.hspec,'WindowButtonDownFcn','showsi_update(''down_spec'')');
+ set(udspec.hspec,'WindowButtonMotionFcn','');
Index: /hypertools/hypertools/si_setvismodeatt.m
===================================================================
--- /hypertools/hypertools/si_setvismodeatt.m	(revision 3)
+++ /hypertools/hypertools/si_setvismodeatt.m	(revision 3)
@@ -0,0 +1,19 @@
+% SI_SETVISMODEATT internal routine for setting up spectra visualization mode
+% only for attached displays
+%
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function si_setvismodeatt(fig)
+ 
+ ud=get(fig,'userdata');
+ ud.state = 'si_visualisation';
+ dipfig_set_action_check(fig,'si_visualisation');
+ set(fig,'pointer','cross') 
+ 
+ set(fig,'WindowButtonDownFcn','showsi_update(''down_dip'')');
+ set(fig,'WindowButtonMotionFcn','showsi_update(''motion_dip'')');	
+ set(fig,'CloseRequestFcn','showsi_update(''close_attached_figure'')');
+ 
Index: /hypertools/hypertools/simca_apply.m
===================================================================
--- /hypertools/hypertools/simca_apply.m	(revision 3)
+++ /hypertools/hypertools/simca_apply.m	(revision 3)
@@ -0,0 +1,89 @@
+%simca_apply SIMCA (applying)
+%  
+%  [labels, is_outl, Q_red, T2_red] = simca_apply(X,SIMCAModel)
+%
+% INPUT 
+%   X             [N -by- d] data matrix (or dataset), N samples, d variables
+%   SIMCAModel    structure array returned by simca_train
+%
+% OUTPUT
+%   labels          classification (without outlier detection)       
+%   is_outl         outlier detection
+%   Q_red, T2_red  [N -by- number_of_classes]  statistics reduced by critical levels
+%
+%
+% DESCRIPTION
+% Similarity (distance) matrix = sqrt(Q_red.^2 + T2_red.^2)
+% Sample is outlier if (Q_red > 1) or (T2_red > 1)
+%
+% SEE ALSO
+% simca_train
+
+% Copyright: S. Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: simca_apply.m,v 1.8 2004/07/19 11:23:41 pavel Exp $
+
+function [labels, is_outl, Q_red, T2_red] = simca_apply(X,SIMCAModel)
+
+X = +X;
+
+[N, d] = size(X);
+number_of_classes = length(SIMCAModel);
+Q_red = zeros(N,number_of_classes);
+T2_red = zeros(N,number_of_classes);
+
+
+if exist('prwarning')
+  global PRWARNING
+  if isempty(PRWARNING)
+    prwarning;
+  end  
+  wl = PRWARNING;
+  prwarn = 1; 
+else
+  wl = warning;
+  prwarn = 0; 
+end
+
+for c=1:number_of_classes
+  T = pca_apply(X,SIMCAModel(c).P,SIMCAModel(c).Options);
+
+  if prwarn 
+    prwarning(1);
+  else
+    warning('off');
+  end 
+
+  Stat = pca_stat(X, T, SIMCAModel(c).P, SIMCAModel(c).lambda, ...
+    SIMCAModel(c).Options.nPC, SIMCAModel(c).Options);
+
+ if prwarn 
+   prwarning(wl);
+ else
+   warning(wl);
+ end 
+
+ if SIMCAModel(c).Crit.Q==0
+   Q_red(:,c) = 0;
+
+   WarnMsg = 'the model space is equal to the training data set space, Q distance will be set to zero';
+   if prwarn
+     prwarning(2,WarnMsg);
+   elseif Options.verbose
+    disp(['simca_apply: ' WarnMsg]);
+   end  
+
+  else
+    Q_red(:,c) = Stat.Q ./ SIMCAModel(c).Crit.Q;
+  end
+
+  T2_red(:,c) = Stat.T2 ./ SIMCAModel(c).Crit.T2; 
+end
+
+[d_2, labels] = min(Q_red.^2 + T2_red.^2,[],2);
+ind = sub2ind([N number_of_classes], [1:N]', labels);
+is_outl = Q_red(ind) > 1 | T2_red(ind) > 1;
+
+return;
Index: /hypertools/hypertools/simca_train.m
===================================================================
--- /hypertools/hypertools/simca_train.m	(revision 3)
+++ /hypertools/hypertools/simca_train.m	(revision 3)
@@ -0,0 +1,156 @@
+%simca_train SIMCA (training)
+%  
+%  SIMCAModel = simca_train(X,labels)
+%  SIMCAModel = simca_train(X,labels,Options)
+%  SIMCAModel = simca_train(D)
+%  SIMCAModel = simca_train(D,Options)
+%
+% INPUT 
+%  X             [N -by- d] training input data matrix, N samples, d variables
+%  labels        [N -by- 1] labels(i) is the number of class to which i-th sample belongs;
+%                lables should be integer numbers in the region [1; number_of_classes]
+%  D             labeled dataset (PRTools)  
+%
+%  Options.
+%   nPC          [1 -by- number_of_classes] 
+%                nPC(j)==nan means autodetection; by default nan
+%   nPC_em       nPC estimation method: 'PEV', 'MI', 'F', 'KG', 'PRESS'; by default 'PEV'     
+%   PEV          part of explained varince; if nPC(j)==nan then the number of principal components to return
+%                is the minimum number of PC such that the portion of explained variance is >= PEV(j); 
+%                by default 0.95
+%                if mean centering was not performed then PEV(j) defines the level 
+%                not for the explained variance but for the explained sum of squares; 
+%   F_cl         confidence level  for Mlinowski F-test  
+%   conf_level   confidence level for crit values of Q and T2 stats; by default 0.95
+%   use_ecv      force the usage of empirical critical values; by default 0
+%
+% OUTPUT
+%  SIMCAModel       
+%
+%
+%
+% DESCRIPTION
+%  
+%
+% SEE ALSO
+% pca_train
+
+% Copyright: S. Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: simca_train.m,v 1.5 2005/05/05 14:35:55 serguei Exp $
+
+function SIMCAModel = simca_train(varargin)
+
+Options = [];
+
+if isa(varargin{1},'dataset')
+ X = +varargin{1};
+ labels = varargin{1}.nlab;
+ X(labels == 0,:) = [];
+ labels(labels == 0) = [];
+  if nargin > 1
+   Options = varargin{2}; 
+ end
+else
+ X = varargin{1};
+ labels = varargin{2};
+  if nargin > 2
+   Options = varargin{3}; 
+ end
+end
+clear varargin;
+
+[N, d] = size(X);
+
+DefaultOptions.nPC = nan;
+DefaultOptions.nPC_em = 'PEV';
+DefaultOptions.PEV = 0.95;
+DefaultOptions.F_cl = 0.95;
+DefaultOptions.conf_level = 0.95;
+DefaultOptions.use_ecv = 0;
+Options = updstruct(DefaultOptions, Options);
+
+number_of_classes = max(labels);
+
+if length(Options.nPC) == 1
+  Options.nPC = repmat(Options.nPC, [1 number_of_classes]);
+end
+
+if length(Options.PEV) == 1
+  Options.PEV = repmat(Options.PEV, [1 number_of_classes]);
+end
+
+if length(Options.conf_level) == 1
+  Options.conf_level = repmat(Options.conf_level, [1 number_of_classes]);
+end
+
+if length(Options.F_cl) == 1
+  Options.F_cl = repmat(Options.F_cl, [1 number_of_classes]);
+end
+
+if exist('prwarning')
+  global PRWARNING
+  if isempty(PRWARNING)
+    prwarning;
+  end  
+  wl = PRWARNING;
+  prwarn = 1; 
+else
+  wl = warning;
+  prwarn = 0; 
+end
+
+for c=1:number_of_classes
+  X_c = X(labels==c,:);
+  SIMCAModel(c).Options.M = size(X_c,1)-1;
+  SIMCAModel(c).Options.nPC = Options.nPC(c);
+  SIMCAModel(c).Options.nPC_em = Options.nPC_em;  
+  SIMCAModel(c).Options.PEV = Options.PEV(c);
+  SIMCAModel(c).Options.F_cl = Options.F_cl(c);
+  SIMCAModel(c).Options.X_centering = nan;  
+  SIMCAModel(c).Options.X_scaling = [];  
+  
+  %Opt = SIMCAModel(c).Options;
+  %Opt.nPC = nan;
+  %Opt.nPC_em = 'ALL';
+  %Opt.nPC_em = 'NOPRESS';
+  %Out = pca_npc(X_c,Opt);  
+  %Out
+  %keyboard
+
+  [T,SIMCAModel(c).P,SIMCAModel(c).lambda,SIMCAModel(c).Options] = pca_train(X_c,SIMCAModel(c).Options);
+  
+  if prwarn 
+    prwarning(1);
+  else
+    warning('off');
+  end 
+
+  Stat = pca_stat(X_c, T, SIMCAModel(c).P, SIMCAModel(c).lambda, ...
+    SIMCAModel(c).Options.nPC, SIMCAModel(c).Options);
+
+  Crit = pca_crit(Options.conf_level(c), SIMCAModel(c).lambda, ...
+    SIMCAModel(c).Options.nPC, SIMCAModel(c).Options, Stat, Options.use_ecv);
+  
+  if prwarn 
+    prwarning(wl);
+  else
+    warning(wl);
+  end 
+
+  if Options.use_ecv
+    SIMCAModel(c).Crit.Q = Crit.Q_emp;    
+    SIMCAModel(c).Crit.T2 = Crit.T2_emp;    
+  else
+    SIMCAModel(c).Crit.Q = Crit.Q;    
+    if isnan(Crit.T2)
+      SIMCAModel(c).Crit.T2 = Crit.T2_emp;    
+    else
+      SIMCAModel(c).Crit.T2 = Crit.T2;    
+    end
+  end
+end
+
+return;
Index: /hypertools/hypertools/simcac.m
===================================================================
--- /hypertools/hypertools/simcac.m	(revision 3)
+++ /hypertools/hypertools/simcac.m	(revision 3)
@@ -0,0 +1,62 @@
+% SIMCAC Supervised SIMCA classifier
+%
+%   W=SIMCAC(A,M)
+%
+% DESCRIPTION
+% This function implements SIMCA classifier (prtools mapping). It builds a PCA model
+% for each class. For a new sample, distance to each model is computed
+% and the sample is assigned to the closest class.
+%
+% SEE ALSO
+% SIMCAM
+
+function w=simcac(a,m)
+
+   if (nargin < 1) | (isempty(a) & ~exist('m','var'))  
+      % Definition: an untrained mapping.
+      w = mapping(mfilename,{});
+      w = setname(w,'SIMCA classifier');
+     
+   elseif isempty(a) & isnumeric(m)
+       
+      w = mapping(mfilename,{m});
+      w = setname(w,'SIMCA classifier');
+
+   elseif ~exist('m','var') | ( exist('m','var') & isnumeric(m))
+
+	Options.use_ecv=1;
+	Options.nPC=NaN; % autodetection
+  if ~exist('m','var')
+	    Options.PEV=0.95;
+	else
+	    Options.PEV=m;
+	end
+       
+  
+  % Training: W will be the trained mapping.
+	[m,k,c] = getsize(a);
+
+	[n,lablist]=classsizes(a);
+
+	classdata=simca_train(a,Options);
+	
+	w=mapping(mfilename,'trained',{classdata},a.lablist,k,c);
+      
+   else 
+
+      % Execution of the mapping, W will be a dataset.
+      v = +m;
+      
+      classdata=v{1};
+
+      % distance to classes:
+      [lab,outl,Q,T2]=simca_apply(a,classdata);      
+      d=sqrt(Q.^2 + T2.^2);
+      
+      % the best is minimum, we turn it by switching the sign:
+      w=setdata(a,-d);
+      w=setfeatlab(w,getlab(m));
+      
+   end
+   
+   return
Index: /hypertools/hypertools/simcam.m
===================================================================
--- /hypertools/hypertools/simcam.m	(revision 3)
+++ /hypertools/hypertools/simcam.m	(revision 3)
@@ -0,0 +1,47 @@
+% SIMCAM Supervised SIMCA mapping
+%
+%   W=SIMCAM(A,M)
+%
+% DESCRIPTION
+% This function implements a SIMCA mapping (in prtools sens). For each class in a
+% C-class problem a PCA model is built. For new data samples, the trained
+% mapping returns a new 2*C dimensional feature space. First C dimensions
+% are the distances to class models (Q) and the remaining C dimensions
+% represent the distances within the model (T2).
+%
+% SEE ALSO
+% SIMCAC
+
+function w=simcam(a,m)
+
+   if (nargin < 1) | (isempty(a))  
+      % Definition: an untrained mapping.
+      w = mapping(mfilename,{});
+      w = setname(w,'SIMCA mapping');
+
+   elseif ~exist('m','var')
+      
+      % Training: W will be the trained mapping.
+      [m,k,c] = getsize(a);
+
+      [n,lablist]=classsizes(a);
+
+      classdata=simca_train(a);
+
+      w=mapping(mfilename,'trained',{classdata},a.lablist,k,2*c);
+      
+   else 
+
+      % Execution of the mapping, W will be a dataset.
+      v = +m;
+      
+      classdata=v{1};
+
+      % distance to classes:
+      [lab,outl,Q,T2]=simca_apply(a,classdata);      
+      
+      w=setdat(a,[Q,T2]);
+      
+   end
+   
+   return
Index: /hypertools/hypertools/simpleclust.m
===================================================================
--- /hypertools/hypertools/simpleclust.m	(revision 3)
+++ /hypertools/hypertools/simpleclust.m	(revision 3)
@@ -0,0 +1,107 @@
+% SIMPLECLUST simple and robust (and heuristic) clustering
+%
+%    [W,B,MODES]=SIMPLECLUST(A,WDIST,PERC)
+%
+% INPUT
+%   A - dataset (may be a single class)
+%   WDIST - dissimilarity mapping (def: dissimm('dasam'))
+%   PERC - percentile of cluster counts (def: 0.5 == median)
+%
+% OUTPUT
+%   W   - trained classifier capable of labeling new dataset
+%   B   - labeled input dataset A
+%   MODES - dataset with data modes samples
+%
+% DESCRIPTION
+% This function implements a simple & dirty clustering using modeseek
+% algorithm. First, outliers are detected and removed using PCA model
+% (SIMCA).  MODESEEK algorithm with different neighborhood sizes is used to
+% find resulting numbers of clusters. One-cluster solution is neglected.
+% Percentile (by default median) of number of clusters is taken as the most
+% viable solution.  Mapping capable of labeling new data, original
+% labeled dataset and identified modes are returned.
+
+% $Id: simpleclust.m,v 1.2 2005/10/19 11:33:37 serguei Exp $
+
+function [w,b,modes,cc]=simpleclust(a,wdist,perc)
+
+  if ~exist('wdist','var') | isempty(wdist), wdist=dissimm('dasam'); end
+  if ~exist('perc','var'), perc=0.5; end    
+  if ~isdataset(a), a=dataset(a); end
+    
+    % detect outliers
+    % sm=simca_train(a);
+    % [lab,isout]=simca_apply(a,sm);
+    
+    % get dataset without outliers
+    % b=a(find(isout==0),:);
+    b=a;
+
+    % construct a dissimilarity
+    % wdist=b*wdist;
+    % D=b*wdist;
+    D = b*(b*wdist);
+
+    % clear wdist % save memory
+    
+    cc=[]; % space for number of clusters found by modeseek
+    finish=0;
+    k=2; % we start from neighborhood of 2
+    seen_ones=0; % how many ones we found (for stopping crit)
+    
+    while finish==0
+      [lab,J]=modeseek(D,k);
+      
+      cc=[cc length(J)];
+      
+      if length(J)==1, seen_ones=seen_ones+1; end
+      
+      k=k+1;
+      
+      % we stop if we passed all neighborhood sizes or
+      % if we already saw 5 ones (all data form a single cluster 
+      % at this level)
+      
+      if k==size(D,1) | seen_ones>5, finish=1; end
+
+      % fprintf(1,'.');
+    end
+	
+    % retrieve 'reasonable' number of clusters
+    cc=cc(find(cc>1)); % remove ones
+
+    c=get_percentile(cc,perc);
+    
+    % get the closest number of clusters (percentile may be float)
+    [s,ind]=sort(abs(c-cc));
+    k=ind(1)+2;
+
+    [lab,J]=modeseek(D,k);
+
+    % create a dataset with modes and class labels (in order to build
+    % knnc on modes)
+    modes=dataset(+b(J,:),genlab(ones(1,length(J))));
+    fprintf(1,' %d ',size(modes,1));
+
+    % untrained dissimilarity mapping
+    %w=dissimm([],wdist{1},wdist{2});
+    %w=modes*w; % train the dissimilarity measure
+    w=modes*wdist;
+    
+    w2=(modes*w)*mindistc; % trained mindist classifier
+    w=w*w2; % trained classifier
+
+    % re-build modes as a dataset with original prototype class labels
+    % Modes preserve their original labels.
+    modes=b(J,:);
+
+    if size(w,2)==1
+      % we cannot invoke labeld as it assumes 1D dataset is a result
+      % of a two-class discriminant :-)
+      b=setlabels(a,ones(size(a,1),1));
+    else
+      b=setlabels(a,a*w*labeld); % apply it to the original dataset
+    end
+
+return
+
Index: /hypertools/hypertools/simplisma.m
===================================================================
--- /hypertools/hypertools/simplisma.m	(revision 3)
+++ /hypertools/hypertools/simplisma.m	(revision 3)
@@ -0,0 +1,174 @@
+%SIMPLISMA simple-to-use interactive self-modeling mixture analysis:
+%          selects set of "pure" variables
+%
+%  [Z, SEL_VAR_IND, SEL_VAR_PURITY, PURITY, R_RATIO, ERR] = SIMPLISMA(X, OPT)
+%
+% INPUT 
+%   X             [M -by- K] double matrix  
+%
+%   OPT.   
+%    MAX_NUM      the max number of variables to select, INF means selecting as many variables as possible,
+%                 until the rank of dataset is exausted; at least one variable will be always selected; by delault = INF
+%    EPS          stopping criteion; algorithm stops ERR < EPS, such features are not included into the set; by default = 1e-2 
+%    THETA        defines offset THETA*ABS(MAX(MAX(X))) used to supress noisy variables; by default = 1e-2 
+%    VERBOSE      force/disable messages; if PRPROGRESS is available: PRPROGRESS(VERBOSE,['%s\n'],MSG) will be run, 
+%                 if PRPROGRESS is not available: VERBOSE == [] or 0 -- no messages, VERBOSE ~= 0 runs DISP(MSG); 
+%                 by default = []
+%
+%
+% OUTPUT 
+%   Z               [M -by- K_SEL] double matrix containing only selected variables
+%   SEL_VAR_IND     [K_SEL -by- 1] vector of selected variables indices 
+%   SEL_VAR_PURITY  [K_SEL -by- 2] two vectors of selected variables purities 
+%                   in the first column are absolute purities, and in the second are relative purities
+%   PURITY          [K_SEL -by- K -by- 2]  two matrices of purity spectra (purities of all variables at all selection steps)
+%                   each row contains purities of all variables at particular selection step;
+%                   the first matrix contains abs purities, the second one containes relative purities
+%   R_RATIO         [K_SEL -by- 1] 
+%   ERR             [K_SEL -by- 1] relative squared error of the data projection to the subspace spanned by the select features
+%
+% DESRIPTION
+% Low level routine
+% Implementation of the SIMPLISMA algorithm described in 
+% "Interactive Self-Modeling Mixture Analysis" by W. Windig, J. Guilment, Anla. Chem. 119, 63, 1425-1432 
+%
+% Absolute dissim measure  abs_diss_(n+1) = ||dx||^2*det(Y_n^T Y_n)
+% Relative dissim measure  rel_diss_(n+1) = ||dx||^2
+%
+% Here, Y_n is the set of n selected features (columns), which are normalized to have a unit length, dx is the part of 
+% a feature x which is (part) orthogonal to span(Y). 
+%
+% SEE ALSO
+% SIMPLISMAM, SIMPLISMAPS, OPA, VARIMAX, ALS
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: simplisma.m,v 1.11 2006/03/15 12:17:15 serguei Exp $
+
+
+function [Z, sel_var_ind, sel_var_purity, purity, R_ratio, err] = simplisma(X,Options)
+
+if nargin < 2
+  Options = [];
+end
+
+DefOptions.max_num = inf;
+DefOptions.theta = 1e-2;
+DefOptions.eps = 1e-2;
+DefOptions.verbose = [];
+Options = updstruct(DefOptions, Options);
+
+%----------------
+prprog = exist('prprogress');
+if ~prprog & isempty(Options.verbose)
+  Options.verbose = 0;
+end
+%----------------
+
+[N, d] = size(X);
+Options.max_num = min([Options.max_num, N, d]);
+
+alpha = Options.theta*abs(max(X(:)));
+X_ss = sum(X.^2,1);
+SS = sum(X_ss);
+X_m = mean(X,1);
+X_std = sqrt(X_ss/N - X_m.^2);
+
+norm_factor = (1/N)./(X_m.^2 + (X_std+alpha).^2);
+R_factor = norm_factor.*X_std;
+purity_factor = R_factor./(abs(X_m)+alpha);
+
+R = sum(R_factor.*X_ss);
+purity = purity_factor.*X_ss;
+purity = cat(3,purity,purity);
+
+[sel_var_purity, ind] = max(purity(1,:,2));
+sel_var_purity = [sel_var_purity, sel_var_purity]; 
+Det_factor = norm_factor(ind).*X_ss(ind);
+Det = Det_factor;
+
+O = X(:,ind)/sqrt(X_ss(ind));
+
+Z = X(:,ind);
+X(:,ind) = [];
+X_ss(:,ind) = [];
+dX_ss = X_ss;
+norm_factor(ind) = [];
+R_factor(ind) = [];
+purity_factor(ind) = [];
+
+sel_var_ind = ind;
+var_ind = [1:d]';
+var_ind(ind) = [];
+
+dX_ss = dX_ss - ((O(:,end)'*X).^2);
+err = sum(dX_ss)/SS;
+
+R_new = sum(R_factor.*dX_ss);
+R_ratio(1) = Det_factor*R_new/R;
+R = R_new;
+
+Msg = ['step 1; max purities are'...
+         ' abs p(' num2str(sel_var_ind(1)) ')=' num2str(sel_var_purity(1,1)) ...
+         ' rel p(' num2str(sel_var_ind(1)) ')=' num2str(sel_var_purity(1,2)) ...
+         '; R_ratio=' num2str(R_ratio) '; err=' num2str(err)];
+
+if prprog
+    prprogress(Options.verbose,['%s\n'],Msg);
+elseif Options.verbose
+  disp(['simplisma: ' Msg]);
+end  
+
+for i=2:Options.max_num
+  %if R_ratio < Options.eps
+  if err(i-1) < Options.eps
+    break;
+  end
+
+  purity(i,var_ind,2) = purity_factor.*dX_ss;
+
+  [sel_var_purity(i,2), ind] = max(purity(i,var_ind,2));
+  Det_factor = norm_factor(ind).*dX_ss(ind);
+  
+  purity(i,var_ind,1) = purity(i,var_ind,2)*Det;
+  sel_var_purity(i,1) = sel_var_purity(i,2)*Det;
+  Det = Det_factor*Det;
+  
+  O = [O, (X(:,ind) - O*(O'*X(:,ind)))/sqrt(dX_ss(ind))];
+  
+  Z = [Z, X(:,ind)];
+  X(:,ind) = [];
+  X_ss(:,ind) = [];
+  dX_ss(:,ind) = [];  
+  norm_factor(ind) = [];
+  R_factor(ind) = [];
+  purity_factor(ind) = [];
+
+  sel_var_ind = [sel_var_ind; var_ind(ind)];
+  var_ind(ind) = [];
+  
+  dX_ss = dX_ss - ((O(:,end)'*X).^2);
+  err(i,1) = sum(dX_ss)/SS;
+  
+  R_new = sum(R_factor.*dX_ss);
+  R_ratio(i,1) = Det_factor*R_new/R;
+  R = R_new;
+  
+  Msg = ['step ' num2str(i) ...
+         '; max purities are' ...
+         ' abs p(' num2str(sel_var_ind(i)) ')=' num2str(sel_var_purity(i,1)) ...
+         ' rel p(' num2str(sel_var_ind(i)) ')=' num2str(sel_var_purity(i,2)) ...
+         '; R_ratio=' num2str(R_ratio(i)) '; err=' num2str(err(i))];
+
+  if prprog
+    prprogress(Options.verbose,['%s\n'],Msg);
+  elseif Options.verbose
+    disp(['simplisma: ' Msg]);
+  end  
+end
+
+return
+
+
Index: /hypertools/hypertools/simplismam.m
===================================================================
--- /hypertools/hypertools/simplismam.m	(revision 3)
+++ /hypertools/hypertools/simplismam.m	(revision 3)
@@ -0,0 +1,113 @@
+%SIMPLISMAM simple-to-use interactive self-modeling mixture analysis:
+%           selects set of "pure" variables
+%  
+%
+%  W = SIMPLISMAM
+%  W = SIMPLISMAM([],OPT)
+%
+%  W = A*W
+%  [W, SEL_VAR_PURITY, PURITY, R_RATIO, ERR] = MAP(A, W)
+%  [W, SEL_VAR_PURITY, PURITY, R_RATIO, ERR] = SIMPLISMAM(A, OPT)
+%
+%  C = B*W
+%  C = MAP(B,W)
+%  C = SIMPLISMAM(B,W)
+%
+%
+% INPUT 
+%   A             [M -by- K] training dataset
+%   B             [N -by- K] test dataset
+%
+%   OPT.          optional SIMPLISMA settings
+%    MAX_NUM      the max number of variables to select, INF means selecting as many variables as possible,a
+%                 until the rank of dataset is exausted; at least one variable will be always selected; by delault = INF
+%    EPS          stopping criteion; algorithm stops ERR < EPS, such features are not included into the set; by default = 1e-2 
+%    THETA        defines offset THETA*ABS(MAX((MAX(A)))) used to supress noisy variables; by default = 1e-2 
+%    VERBOSE      force/disable messages; if PRPROGRESS is available: PRPROGRESS(VERBOSE,['%s\n'],MSG) will be run; 
+%                 by default = []
+%
+% OUTPUT 
+%   W               [K -by- ?] untrained mapping or [K -by- K_SEL] trained feature selection mapping
+%                   after training, indices of selected variables stored in W.DATA.IND  
+%   SEL_VAR_IND     [K_SEL -by- 1] vector of selected variables indices 
+%   SEL_VAR_PURITY  [K_SEL -by- 2] two vectors of selected variables purities 
+%                   in the first column are absolute purities, and in the second are relative purities
+%   PURITY          [K_SEL -by- K -by- 2] two matrices which rows are purity spectra; 
+%                   each row contains purities of all variables at particular selection step
+%                   the first matrix contains abs purities, the second one containes relative purities
+%   R_RATIO         [K_SEL -by- 1] 
+%   ERR             [K_SEL -by- 1] relative squared error of the data projection to the subspace spanned by the select features
+%   C               [N -by- K_SEL] dataset, result of mapping execution on dataset B
+%
+% DESRIPTION
+% Implementation of the SIMPLISMA algorithm described in 
+% "Interactive Self-Modeling Mixture Analysis" by W. Windig, J. Guilment, Anla. Chem. 119, 63, 1425-1432 
+%
+% Absolute dissim measure  abs_diss_(n+1) = ||dx||^2*det(Y_n^T Y_n)
+% Relative dissim measure  rel_diss_(n+1) = ||dx||^2
+%
+% Here, Y_n is the set of n selected features (columns), which are normalized to have a unit length, dx is the part of 
+% a feature x which is (part) orthogonal to span(Y). 
+%
+% SEE ALSO
+% OPAM, VARIMAXFM, SIMPLIMAPS, OPAPS, VARIMAXOM, ALS, SIMPLISMA
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: simplismam.m,v 1.10 2007/01/31 21:52:19 serguei Exp $
+
+function [w, sel_var_purity, purity, R_ratio, err] = simplismam(a,w)
+
+% No dataset given: return untrained mapping.
+if (nargin < 1) | (isempty(a))
+  if nargin < 2
+    w = [];
+  end  
+  w = mapping(mfilename,'untrained',{w});
+  w = setname(w,'SIMPLISMA Mapping');
+  return
+end
+
+isdataset(a);           % Assert that A is a dataset.
+
+% training
+if nargin < 2 | ~isa(w,'mapping') 
+  if nargin < 2
+    w = [];  
+  end  
+
+  [m,k] = getsize(a);
+  
+  [z, sel_var_ind, sel_var_purity, purity, R_ratio, err] = simplisma(+a,w);
+  
+  w_data.ind = sel_var_ind;
+
+  %labels = [num2str([1:length(sel_var_ind)]','%-1d'),  num2str(sel_var_ind(:),'(%-1d)')];
+  labels = a.featlab(sel_var_ind,:);
+
+  % Save all useful data
+  w = mapping(mfilename,'trained',w_data,labels,size(a,2),length(sel_var_ind));
+  w = setname(w,'SIMPLISMA Feature Selection');
+  
+% applying
+else 
+  w_data = +w; % Unpack the mapping.
+  %w = a*cmapm(w.size_in,w_data.ind);
+  a = a(:,w_data.ind);
+  %a.featlab = w.labels;
+  units = specunits(a);
+  a = remove_spectra_info(a);
+  if units
+    user = a.user;
+    user.type = 'spectra';
+    user.units = units;
+    a.user = user;
+  end  
+  a.name = [a.name ': selected channels'];
+  w = a;
+end
+
+return
+
Index: /hypertools/hypertools/simplismaps.m
===================================================================
--- /hypertools/hypertools/simplismaps.m	(revision 3)
+++ /hypertools/hypertools/simplismaps.m	(revision 3)
@@ -0,0 +1,66 @@
+%SIMPLISMAPS simple-to-use interactive self-modeling mixture analysis:
+%           selects set of "pure" objects (prototype selection)
+%  
+%
+%  [B, SEL_OBJ_IND, SEL_OBJ_PURITY, PURITY, R_RATIO, ERR] = SIMPLISMAPS(A)
+%  [B, SEL_OBJ_IND, SEL_OBJ_PURITY, PURITY, R_RATIO, ERR] = SIMPLISMAPS(A, OPT)
+%
+%
+% INPUT 
+%   A             [M -by- K] training dataset
+%
+%   OPT.   
+%    MAX_NUM      the max number of objects to select, INF means selecting as many objects as possible,
+%                 until the rank of dataset is exausted; at least one objects will be always selected; by delault = INF
+%    EPS          stopping criteion; algorithm stops ERR < EPS, such objects are not included into the set; by default = 1e-2
+%    THETA        defines offset THETA*ABS(MAX((MAX(A)))) used to supress noisy objects; by default = 1e-2 
+%    VERBOSE      force/disable messages; if PRPROGRESS PRPROGRESS(VERBOSE,['%s\n'],MSG) will be run; 
+%                 by default = []
+%
+%
+% OUTPUT 
+%   B               [M_SEL -by- K] dataset containing selected object (prototypes)
+%   SEL_OBJ_IND     [M_SEL -by- 1] vector of selected objects indices 
+%   SEL_OBJ_PURITY  [M_SEL -by- 2] two vectors of selected objects purities 
+%                   in the first column are absolute purities, and in the second are relative purities
+%   PURITY          [M -by- M_SEL -by- 2] two matrices which columns are purity profiles; 
+%                   each columns contains purities of all objects at particular selection step;
+%                   the first matrix contains abs purities, the second one containes relative purities
+%   R_RATIO         [M_SEL -by- 1] 
+%   ERR             [M_SEL -by- 1] relative squared error of the data projection to the subspace spanned by the select objects
+%
+% DESRIPTION
+% Implementation of the SIMPLISMA algorithm described in 
+% "Interactive Self-Modeling Mixture Analysis" by W. Windig, J. Guilment, Anla. Chem. 119, 63, 1425-1432 
+% (applied to the transposed data matrix)
+%
+% Absolute dissim measure  abs_diss_(n+1) = ||dx||^2*det(Y_n Y_n^T)
+% Relative dissim measure  rel_diss_(n+1) = ||dx||^2
+%
+% Here, Y_n is the set of n selected objects (rows), which are normalized to have a unit length, dx is the part of 
+% an object x which is (part) orthogonal to span(Y). 
+%
+%
+% SEE ALSO
+% OPAPS, VARIMAXOM, SIMPLISMAM, OPAM, VARIMAXFM, ALS, SIMPLISMA
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: simplismaps.m,v 1.6 2007/01/31 21:52:19 serguei Exp $
+
+function [b, sel_obj_ind, sel_obj_purity, purity, R_ratio, err] = simplismam(a,Opt)
+
+if nargin < 2
+  Opt = [];
+end
+
+[y, sel_obj_ind, sel_obj_purity, purity, R_ratio, err] = simplisma((+a)',Opt);
+
+purity = permute(purity,[2 1 3]);  
+b = a(sel_obj_ind,:);
+b.name = [b.name ': selected spectra'];
+
+return
+
Index: /hypertools/hypertools/smoothm.m
===================================================================
--- /hypertools/hypertools/smoothm.m	(revision 3)
+++ /hypertools/hypertools/smoothm.m	(revision 3)
@@ -0,0 +1,94 @@
+% SMOOTHM Smoothing and derivatives mapping
+%
+%    W = SMOOTHM(NAME,SIGMA,DER)
+%    W = SMOOTHM(NAME,WS,P,DER)
+%
+% INPUT
+%   NAME   smoothing algorithm ('Gaussian' or 'SG')
+%   SIGMA  sigma in Gaussian smoothing
+%   WS     window size in Savitsky-Golay alg.
+%   P      polynomial degree in SG
+%   DER    derivative order (default: 0)
+%
+% OUTPUT
+%   W      fixed smoothing mapping
+%
+% DESCRIPTION
+% SMOOTHM is a fixed mapping capable of computing smoothed derivatives
+% of spectra using either Savitzky-Golay or Gaussian smoothing.
+% DIPImage is required when using Gaussian filtering.
+%
+% SEE ALSO
+% DSPEC_SHAPE, DSHAPE, DERFILTER
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+% $Id: smoothm.m,v 1.5 2007/10/29 10:46:23 serguei Exp $
+
+function W = smoothm(a,par1,par2,par3)
+
+	if nargin == 0 
+		W = mapping(mfilename,'fixed',{'Gaussian',1});
+		W = setname(W,'Spectral smoothing mapping (Gaussian sigma=1.0)');	
+	elseif ~isa(a,'dataset')
+		% a is supposed to be smoothing type
+		switch lower(a)
+		 case {'gauss','gaussian'}
+		  if ~exist('par1','var'), par1=1; end % sigma
+		  if ~exist('par2','var'), par2=0; end % derivative
+		  str=sprintf('sigma=%2.1f',par1);
+		  if par2~=0
+		      str=[str sprintf(',der=%1d',par2)];
+		  end
+		  W = mapping(mfilename,'fixed',{'Gaussian',par1,par2});
+		  W = setname(W,...
+				['Spectral smoothing mapping (Gaussian '...
+				 str ')';]);
+		 case {'sg','savitsky-golay'}
+		  % polynom order
+		  if ~exist('par1','var'), par1=3; end % window size
+		  if ~exist('par2','var'), par2=1; end % polynom order
+		  if ~exist('par3','var'), par3=0; end % derivative
+
+		  % call sg to get coefficient matrix:
+		  CM=sg(par1,par2,par3);
+
+		  str=sprintf('ws=%d,p=%d,d=%d',par1,par2,par3);
+		  W = mapping(mfilename,'fixed',{'Savitsky-Golay',CM});
+		  W = setname(W,...
+			      ['Spectral smoothing mapping (Savitsky-Golay ' ...
+			       str ')']);
+		 otherwise
+		  error('unknown mapping type');     
+		end
+	elseif isa(a,'dataset')
+		% execution 
+		switch lower(par1)
+		 case 'gaussian'
+		  if ~exist('par3','var'), par3=0; end % derivative
+		  b = (+a);
+      if size(a,1) == 1
+        b = [b; b];
+      end  
+      b = double(dip_gauss(b,[1 0],[par2 par2],[par3 0]));
+      if size(a,1) == 1
+        b = b(1,:);
+      end  
+      a = setdata(a,b);
+      clear b;
+      
+		 case 'savitsky-golay'
+		  % CM is in par2
+		  a.data=sg(par2,+a,2); % in spectral domain
+		 otherwise
+		  error('unknown mapping type');
+		end
+		W=a;
+	end
+
+
+	return
+
+
Index: /hypertools/hypertools/speccolormap.m
===================================================================
--- /hypertools/hypertools/speccolormap.m	(revision 3)
+++ /hypertools/hypertools/speccolormap.m	(revision 3)
@@ -0,0 +1,11 @@
+% SPECCOLORMAP Set the spectral colormap
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function speccolormap
+	
+	colormap(get_spec_colormap);
+	
+	
Index: /hypertools/hypertools/specnormm.m
===================================================================
--- /hypertools/hypertools/specnormm.m	(revision 3)
+++ /hypertools/hypertools/specnormm.m	(revision 3)
@@ -0,0 +1,87 @@
+% SPECNORMM Spectral normalization mapping
+%
+%     W = SPECNORMM(A,T)
+%
+% 'none'       - no normalization
+% 'unitarea'   - normalize spectra to unit area (by default)
+% 'unitbdl',1  - normalize spectra to unit block-distance length
+% 'unitedl',2  - normalize spectra to unit euclidian-distance length
+
+% Copyright: Pavel Paclik, pavel@ph.tn.tudelft.nl
+% Faculty of Applied Physics, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+function w = specnormm(a,t)
+
+%prtrace(mfilename);
+if nargin < 2 | isempty(t)
+  t = 'unitarea';
+end
+
+if nargin < 1 | isempty(a)
+  switch t
+	case {'none', 'unitarea', 'unitbdl', 'unitedl'}
+    ;  
+  otherwise
+    if isa(t,'double') 
+      if length(t) ~= 1 | t <= 0
+        error('the wrong mapping parameter');
+      end  
+    else  
+      error('unknown mapping type');       
+    end
+  end
+
+  w = mapping(mfilename,'fixed',{t});
+  w = setname(w,['Spectral normalization mapping: ' num2str(t)]);
+  
+else
+  disp(t)
+	
+  switch t
+  case 'none'      
+    ;  
+  case 'unitarea'
+    norm=sum(+a,2);
+    a = setdata(a,+a./repmat(norm, [1,size(a,2)]));
+
+  otherwise    
+    switch t
+    case 'unitbdl'
+      t = 1;
+    case 'unitedl'
+      t = 2;
+    end
+      
+    if ~isa(t,'double') | length(t) ~= 1 | t <= 0
+      error('the wrong mapping parameter');
+    end
+    
+    if ~isinf(t)
+      norm=(sum(abs(+a).^t,2)).^(1/t);
+    else
+      norm=max(abs(+a),2);
+    end
+	  
+    a = setdata(a,+a./repmat(norm,1,size(a,2)));    
+  end    
+  
+  w=a;  
+end
+	
+return
+
+
+%       if 0
+%       [m, k] = size(a);
+%       step = 10000;
+%       begs = 1:step:m;
+%       ends = begs + (step-1);
+%       ends(end) = m;
+%       for i=1:length(begs)
+%         norm=sum(+a(begs(i):ends(i),:),2);
+%         a(begs(i):ends(i),:) = (+a(begs(i):ends(i),:))./repmat(norm, [1,size(a,2)]);
+%       end
+%       end  
+      
+
Index: /hypertools/hypertools/subsample.m
===================================================================
--- /hypertools/hypertools/subsample.m	(revision 3)
+++ /hypertools/hypertools/subsample.m	(revision 3)
@@ -0,0 +1,67 @@
+function res = subsample(dset,rc,ss_dset_ind)
+%
+% Spectral image subsampling 
+%
+%   ss_dsets = subsample(dset,rc)
+%   ss_dset  = subsample(dset,rc,ds_ind)
+%
+% ss_dset    dataset object containig spectral image
+% ss_dsets   cell-array of dataset objects containig subsampled spectral images
+%            or dataset (if ds_ind was specified)
+%
+
+% Copyright: S.Verzakov, serguei@ph.tn.tudelft.nl
+% Faculty of Applied Sciences, Delft University of Technology
+% P.O. Box 5046, 2600 GA Delft, The Netherlands
+
+if nargin < 3
+  ss_dset_ind = [];
+end
+
+objsize = dset.objsize;
+rows=objsize(1);
+cols=objsize(2);
+
+if isempty(ss_dset_ind)
+  res = {};
+  for i=1:rc(1)
+    rind = [i:rc(1):rows];
+    ss_rows = length(rind);
+
+    for j=1:rc(2)
+      cind = [j:rc(2):cols];    
+      ss_cols = length(cind);    
+      [cc, rr] = meshgrid(cind,rind);
+      ind = sub2ind(objsize,rr(:),cc(:));
+      res{i,j} = dset(ind,:);
+      res{i,j}.objsize = [ss_rows ss_cols];
+    end
+  end
+
+else
+  rind = [ss_dset_ind(1):rc(1):rows];
+  cind = [ss_dset_ind(2):rc(2):cols];
+  ss_rows = length(rind);
+  ss_cols = length(cind);    
+  [cc, rr] = meshgrid(cind,rind);
+  ind = sub2ind(objsize,rr(:),cc(:));
+  res = dset(ind,:);
+  res.objsize = [ss_rows ss_cols];
+end  
+
+return
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /hypertools/hypertools/subsamplem.m
===================================================================
--- /hypertools/hypertools/subsamplem.m	(revision 3)
+++ /hypertools/hypertools/subsamplem.m	(revision 3)
@@ -0,0 +1,46 @@
+% SUBSAMPLEM Spectral subsampling mapping
+%
+%    W = SUBSAMPLEM(NAME,STEP)
+%
+% INPUT
+%   NAME  - subsampling algorithm ('step')
+%   STEP  - subsampling step
+%
+% OUTPUT
+%   W      - fixed subsampling mapping
+%
+
+% $Id: subsamplem.m,v 1.3 2005/02/10 15:24:07 pavel Exp $
+
+function W = subsamplem(a,par1,par2)
+
+	if nargin == 0 
+		W = mapping(mfilename,'fixed',{'step',5});
+		W = setname(W,'Spectral subsampling mapping (step, step=5)');	
+	elseif ~isa(a,'dataset')
+		% a is supposed to be smoothing type
+		switch lower(a)
+		 case {'step'}
+		  str=sprintf('step=%2d',par1);		  
+		  W = mapping(mfilename,'fixed',{'step',par1});
+		  W = setname(W,...
+				['Spectral subsampling mapping (step, '...
+				 str ')';]);
+		 otherwise
+		  error('unknown mapping type');     
+		end
+	elseif isa(a,'dataset')
+		% execution 
+		switch lower(par1)
+		 case 'step'
+		  a.data=a(:,1:par2:end);
+		 otherwise
+		  error('unknown mapping type');
+		end
+		W=a;
+	end
+
+
+	return
+
+
Index: /hypertools/hypertools/tma_unmix.m
===================================================================
--- /hypertools/hypertools/tma_unmix.m	(revision 3)
+++ /hypertools/hypertools/tma_unmix.m	(revision 3)
@@ -0,0 +1,26 @@
+function tma_unmix
+
+% (C) 2006 S.A. Verzakov, s.verzakov@tudelft.nl
+
+tm_do(tml_main_unmix);
+
+return
+
+function FuncList  = tml_main_unmix
+
+FuncList.Title         = 'HyperTools: Unixing';
+FuncList.HideOnExec    = 1;
+FuncList.DisableOnExec = 1;
+
+% the first column is a title, the second is a function handle
+FuncList.List = {...
+  ...
+  'OPA/ALS',         @tmr_opa; ...
+  'SIMPLISMA/ALS',   @tmr_simplisma; ...
+  'PCA/VARIMAX/ALS', @tmr_varimax; ...
+  'MAF/ALS',         @tmr_maf; ...
+  'MNF/ALS',         @tmr_mnf; ...
+};
+
+return
+
Index: /hypertools/hypertools/tmr_maf.m
===================================================================
--- /hypertools/hypertools/tmr_maf.m	(revision 3)
+++ /hypertools/hypertools/tmr_maf.m	(revision 3)
@@ -0,0 +1,214 @@
+function tmr_maf(h,eventdata,varargin)
+% 
+
+% (C) 2006 S. Verzakov, verzakov@tudelft.nl
+
+% title of application
+Title = 'MAF/ALS';
+
+% width & font size of input dialog
+Width = 0.3;   % normalized
+FontSize = 10; % points (9,10,11,12) are recommended
+
+ImmediateApply = -1;
+
+%=== do not change this code (begin)
+InpDesc = InputDescription;   
+DlgOptions.Title    = Title;
+DlgOptions.Width    = Width;
+DlgOptions.FontSize = FontSize;
+DlgOptions.Mode     = 'Run';
+DlgOptions.RunFunc  = @Run;
+DlgOptions.FinFunc  = @tm_fin;
+DlgOptions.FinInp   = get(h,'Parent');
+DlgOptions.ImmApp   = ImmediateApply;
+advdlg(InpDesc,DlgOptions)
+%=== do not change this code (end)
+
+return;
+
+%------------------------------------------------------- InputDescription ---
+% Here we define the parameters that control the appearance of the main (plot) figure (in the left).
+% We describe the uicontrols in the input dialog box (right)
+% Possible control types are shown and their use is described below
+
+function id = InputDescription
+
+% edit (variable)
+id.Dataset.Type = 'variable';
+id.Dataset.Prompt = 'Read data from a dataset';
+id.Dataset.CanBeEmpty = 1; % default 0
+id.Dataset.Mode = 'get'; % default 'put' ('put','get')
+id.Dataset.WarnBeforeOverwrite = 0; % default 1 
+id.Dataset.MakeGlobal = 0; % default 0 
+id.Dataset.Default = 'data'; % default '' 
+
+% delimiter
+id.Delimiter1a.Type = 'delimiter';
+id.Delimiter1a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter1b.Type = 'delimiter';
+id.Delimiter1b.Prompt = '--- MAF parameters ----------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (double)
+id.MAF_NumFrac.Type = 'double';
+id.MAF_NumFrac.Prompt = 'Number of components/Fraction of explained autocovariance';
+id.MAF_NumFrac.Range = [0 inf];
+id.MAF_NumFrac.Inclusive = [0 0];
+id.MAF_NumFrac.Length = [1];
+id.MAF_NumFrac.Default = [0.95]; %default [] 
+
+% delimiter
+id.Delimiter2a.Type = 'delimiter';
+id.Delimiter2a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter2b.Type = 'delimiter';
+id.Delimiter2b.Prompt = '--- ALS parameters ------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (int)
+id.ALS_MaxIt.Type = 'int';
+id.ALS_MaxIt.Prompt = 'Maximal number of iterations';
+id.ALS_MaxIt.Range = [0 inf];
+id.ALS_MaxIt.Inclusive = [1 0];
+id.ALS_MaxIt.Length = [1];
+id.ALS_MaxIt.Default = [0]; %default [] 
+
+% popup 
+id.ALS_CritType.Type = 'set';
+id.ALS_CritType.Prompt = 'Type of stopping criterion';
+id.ALS_CritType.Style = 'pop'; % default 'pop' ('pop', 'box') 
+id.ALS_CritType.Return = 'val'; % default 'val' ('val' - return string, 'ind' - return index/indices)
+id.ALS_CritType.List = {'convergence','reconstruction'};
+id.ALS_CritType.Default = 1; % default 1
+
+% edit (double)
+id.ALS_Eps.Type = 'double';
+id.ALS_Eps.Prompt = 'Stopping critetion';
+id.ALS_Eps.Range = [0 inf];
+id.ALS_Eps.Inclusive = [1 0];
+id.ALS_Eps.Length = [1];
+id.ALS_Eps.Default = [1e-2]; %default [] 
+
+% delimiter
+id.Delimiter3a.Type = 'delimiter';
+id.Delimiter3a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter3b.Type = 'delimiter';
+id.Delimiter3b.Prompt = '--- Output ---------------------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (double)
+id.ProgRep.Type = 'double';
+id.ProgRep.Prompt = 'Progress report file handle (1 means command window)';
+id.ProgRep.Length = [1];
+id.ProgRep.Default = [1]; % default [] 
+id.ProgRep.CanBeEmpty = 1;
+
+% edit (variable)
+id.Out.Type = 'variable';
+id.Out.Prompt = 'Save data in a structure';
+id.Out.CanBeEmpty = 1; % default 0
+id.Out.Mode = 'put'; % default 'put' ('put','get')
+id.Out.WarnBeforeOverwrite = 0; % default 1 
+id.Out.MakeGlobal = 0; % default 0 
+id.Out.Default = 'out'; % default '' 
+id.Out.Enable = 'on'; % default 'on'
+
+return;
+
+
+%------------------------------------------------------- Run ---
+% It is the response to the 'Run' button in the input dialog.
+% We take the parameter values from  the input dialog (the right one) and, with them, 
+% we run the algorithm and plot the results in the plot (left) window
+
+function Run(in)
+
+layout = [2 2];
+
+h(1) = tm_figure(['MAF extracted channels'], 'MAF_ExtChan', 'close', [layout 1]);  clf;
+h(2) = tm_figure('MAF error', 'MAF_Err', 'close', [layout 2]);  clf;
+
+if in.ALS_MaxIt > 0
+  h(3) = tm_figure('Pure spectra (refined by ALS)',   'MAF_Spec',     'close', [layout 3]);  clf;
+  h(4) = tm_figure('Pure channels (refined by ALS)',  'MAF_Chan',     'close', [layout 4]);  clf;
+else
+  h(3) = tm_figure('MAF: Spectra',   'MAF_Spec',     'close', [layout 3]);  clf;
+  h(4) = tm_figure('MAF: Channels',  'MAF_Chan',     'close', [layout 4]);  clf;
+end  
+
+drawnow
+
+x = tm_getvar(in.Dataset);
+
+opt_als.max_iter = in.ALS_MaxIt;
+opt_als.crit     = in.ALS_CritType;
+opt_als.eps      = in.ALS_Eps;
+opt_als.verbose  = in.ProgRep;
+opt_als.mode     = 'features';
+
+[out.w, num_frac,crit] = maf(x, in.MAF_NumFrac);
+out.k_ext = size(out.w,2);
+out.crit = crit;
+
+w = out.w;
+wdata = +w;
+offset = wdata.offset;
+wdata.offset = zeros(size(offset));
+w.data = wdata;
+out.z0 = remove_spectra_info(x*w);
+out.z0.name = [x.name ': extracted channels'];
+%out.z0 = remove_spectra_info(x*out.w);
+
+m = size(x,1);
+err = 1 - cumsum((sum((+out.z0).^2,1) - m*offset.^2))/(sum(sum((+x).^2)) - m*sum(mean(+x).^2));
+
+figure(h(1));
+showspim(out.z0)
+daspect([1 1 1])
+colormap(jet)
+shg
+  
+figure(h(2))
+plot([1-cumsum(out.crit(1:out.k_ext))/sum(out.crit), err(:)]) 
+legend('unexplained autocovariance fraction',sprintf('unexplained var frac (rel sqr reconst err)\'));
+xlabel('# of components')
+
+drawnow
+
+if opt_als.max_iter > 0
+  opt_als.mode = 'features';
+  [out.z, out.y] = als(x,out.z0,opt_als);
+else
+  out.z = out.z0;
+  out.y = (+out.z)\(+x);
+  out.y = dataset(out.y);
+  out.y.featlab  = x.featlab;
+  out.y.featsize = x.featsize;
+  out.y.user     = x.user;
+  out.y.name = [x.name ': extracted spectra'];
+end  
+
+figure(h(3))
+showspim(out.y)
+shg
+  
+figure(h(4));
+showspim(out.z)
+colormap(jet)
+shg
+  
+drawnow
+
+tm_putvar(in.Out, out);
+
+return
+
Index: /hypertools/hypertools/tmr_mnf.m
===================================================================
--- /hypertools/hypertools/tmr_mnf.m	(revision 3)
+++ /hypertools/hypertools/tmr_mnf.m	(revision 3)
@@ -0,0 +1,299 @@
+function tmr_mnf(h,eventdata,varargin)
+% 
+
+% (C) 2006 S. Verzakov, verzakov@tudelft.nl
+
+% title of application
+Title = 'MNF/ALS';
+
+% width & font size of input dialog
+Width = 0.3;   % normalized
+FontSize = 10; % points (9,10,11,12) are recommended
+
+ImmediateApply = -1;
+
+%=== do not change this code (begin)
+InpDesc = InputDescription;   
+DlgOptions.Title    = Title;
+DlgOptions.Width    = Width;
+DlgOptions.FontSize = FontSize;
+DlgOptions.Mode     = 'Run';
+DlgOptions.RunFunc  = @Run;
+DlgOptions.FinFunc  = @tm_fin;
+DlgOptions.FinInp   = get(h,'Parent');
+DlgOptions.ImmApp   = ImmediateApply;
+advdlg(InpDesc,DlgOptions)
+%=== do not change this code (end)
+
+return;
+
+%------------------------------------------------------- InputDescription ---
+% Here we define the parameters that control the appearance of the main (plot) figure (in the left).
+% We describe the uicontrols in the input dialog box (right)
+% Possible control types are shown and their use is described below
+
+function id = InputDescription
+
+% edit (variable)
+id.Dataset.Type = 'variable';
+id.Dataset.Prompt = 'Read data from a dataset';
+id.Dataset.CanBeEmpty = 1; % default 0
+id.Dataset.Mode = 'get'; % default 'put' ('put','get')
+id.Dataset.WarnBeforeOverwrite = 0; % default 1 
+id.Dataset.MakeGlobal = 0; % default 0 
+id.Dataset.Default = 'data'; % default '' 
+
+% delimiter
+id.Delimiter1a.Type = 'delimiter';
+id.Delimiter1a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter1b.Type = 'delimiter';
+id.Delimiter1b.Prompt = '--- MNF parameters ----------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (double)
+id.MNF_NumFrac.Type = 'double';
+id.MNF_NumFrac.Prompt = 'Number of components/Fraction of explained variance';
+id.MNF_NumFrac.Range = [-inf inf];
+id.MNF_NumFrac.Inclusive = [1 1];
+id.MNF_NumFrac.Length = [1];
+id.MNF_NumFrac.Default = [0.95]; %default [] 
+
+% popup 
+id.MNF_CritType.Type = 'set';
+id.MNF_CritType.Prompt = 'Type of citerion';
+id.MNF_CritType.Style = 'pop'; % default 'pop' ('pop', 'box') 
+id.MNF_CritType.Return = 'val'; % default 'val' ('val' - return ret val, or string from list if ret val is empty, 'ind' - return index/indices)
+id.MNF_CritType.ReturnValue = {'acor', 'acov', 'nf', 'n'}; %cell array of values to be returned, default {}
+id.MNF_CritType.List = {'max autocorrelation factors','max autocovriance factors', 'min noise fraction', 'min noise'};
+id.MNF_CritType.Default = 1; % default 1
+
+% popup 
+id.MNF_EstimMethod.Type = 'set';
+id.MNF_EstimMethod.Prompt = 'Estimation method';
+id.MNF_EstimMethod.Style = 'pop'; % default 'pop' ('pop', 'box') 
+id.MNF_EstimMethod.Return = 'val'; % default 'val' ('val' - return ret val, or string from list if ret val is empty, 'ind' - return index/indices)
+id.MNF_EstimMethod.ReturnValue = {'shift', 'smooth'}; %cell array of values to be returned, default {}
+id.MNF_EstimMethod.List = {'shift image','smooth image'};
+id.MNF_EstimMethod.Default = 1; % default 1
+
+
+% edit (double)
+id.MNF_Param.Type = 'double';
+id.MNF_Param.Prompt = 'Size of shift/Sigma of Gaussian';
+id.MNF_Param.Range = [0 inf];
+id.MNF_Param.Inclusive = [0 0];
+id.MNF_Param.Length = [1];
+id.MNF_Param.Default = [1]; %default [] 
+
+% checkbox
+id.MNF_MeanCentering.Type = 'logical';
+id.MNF_MeanCentering.Prompt = 'Center data before factor extraction';
+id.MNF_MeanCentering.Default = 1; % default 0
+
+% checkbox
+id.MNF_DirtyTrick.Type = 'logical';
+id.MNF_DirtyTrick.Prompt = 'Do a dirty trick: compute max autocor as min noise frac';
+id.MNF_DirtyTrick.Default = 1; % default 0
+
+
+% delimiter
+id.Delimiter2a.Type = 'delimiter';
+id.Delimiter2a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter2b.Type = 'delimiter';
+id.Delimiter2b.Prompt = '--- ALS parameters ------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (int)
+id.ALS_MaxIt.Type = 'int';
+id.ALS_MaxIt.Prompt = 'Maximal number of iterations';
+id.ALS_MaxIt.Range = [0 inf];
+id.ALS_MaxIt.Inclusive = [1 0];
+id.ALS_MaxIt.Length = [1];
+id.ALS_MaxIt.Default = [0]; %default [] 
+
+% popup 
+id.ALS_CritType.Type = 'set';
+id.ALS_CritType.Prompt = 'Type of stopping criterion';
+id.ALS_CritType.Style = 'pop'; % default 'pop' ('pop', 'box') 
+id.ALS_CritType.Return = 'val'; % default 'val' ('val' - return string, 'ind' - return index/indices)
+id.ALS_CritType.List = {'convergence','reconstruction'};
+id.ALS_CritType.Default = 1; % default 1
+
+% edit (double)
+id.ALS_Eps.Type = 'double';
+id.ALS_Eps.Prompt = 'Stopping critetion';
+id.ALS_Eps.Range = [0 inf];
+id.ALS_Eps.Inclusive = [1 0];
+id.ALS_Eps.Length = [1];
+id.ALS_Eps.Default = [1e-2]; %default [] 
+
+% delimiter
+id.Delimiter3a.Type = 'delimiter';
+id.Delimiter3a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter3b.Type = 'delimiter';
+id.Delimiter3b.Prompt = '--- Output ---------------------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (double)
+id.ProgRep.Type = 'double';
+id.ProgRep.Prompt = 'Progress report file handle (1 means command window)';
+id.ProgRep.Length = [1];
+id.ProgRep.Default = [1]; % default [] 
+id.ProgRep.CanBeEmpty = 1;
+
+% edit (variable)
+id.Out.Type = 'variable';
+id.Out.Prompt = 'Save data in a structure';
+id.Out.CanBeEmpty = 1; % default 0
+id.Out.Mode = 'put'; % default 'put' ('put','get')
+id.Out.WarnBeforeOverwrite = 0; % default 1 
+id.Out.MakeGlobal = 0; % default 0 
+id.Out.Default = 'out'; % default '' 
+id.Out.Enable = 'on'; % default 'on'
+
+return;
+
+
+%------------------------------------------------------- Run ---
+% It is the response to the 'Run' button in the input dialog.
+% We take the parameter values from  the input dialog (the right one) and, with them, 
+% we run the algorithm and plot the results in the plot (left) window
+
+function Run(in)
+
+layout = [2 2];
+
+h(1) = tm_figure(['MNF extracted channels'], 'MNF_ExtChan', 'close', [layout 1]);  clf;
+h(2) = tm_figure('MNF error', 'MNF_Err', 'close', [layout 2]);  clf;
+
+if in.ALS_MaxIt > 0
+  h(3) = tm_figure('Pure spectra (refined by ALS)',   'MNF_Spec',     'close', [layout 3]);  clf;
+  h(4) = tm_figure('Pure channels (refined by ALS)',  'MNF_Chan',     'close', [layout 4]);  clf;
+else
+  h(3) = tm_figure('MNF: Spectra',   'MNF_Spec',     'close', [layout 3]);  clf;
+  h(4) = tm_figure('MNF: Channels',  'MNF_Chan',     'close', [layout 4]);  clf;
+end  
+
+drawnow
+
+x = tm_getvar(in.Dataset);
+
+opt_als.max_iter = in.ALS_MaxIt;
+opt_als.crit     = in.ALS_CritType;
+opt_als.eps      = in.ALS_Eps;
+opt_als.verbose  = in.ProgRep;
+
+[out.w, num_frac,crit,frac,tot] = mnfm(x, in.MNF_NumFrac, in.MNF_CritType, in.MNF_EstimMethod, in.MNF_Param, in.MNF_MeanCentering, in.MNF_DirtyTrick);
+out.k_ext = size(out.w,2);
+out.frac = frac;
+out.crit = crit;
+
+w = out.w;
+wdata = +w;
+offset = wdata.offset;
+wdata.offset = zeros(size(offset));
+w.data = wdata;
+out.z0 = remove_spectra_info(x*w);
+out.z0.name = [x.name ': extracted channels'];
+%out.z0 = remove_spectra_info(x*out.w);
+
+figure(h(1));
+showspim(out.z0)
+daspect([1 1 1])
+colormap(jet)
+shg
+  
+figure(h(2))
+subplot(2,1,1)
+plot(1-cumsum(out.frac(1:min(out.k_ext+3,end))));
+legend('relative squared reconstruction error');
+
+
+subplot(2,1,1)
+plot(1-cumsum(out.frac(1:min(out.k_ext+3,end))));
+legend('relative squared reconstruction error');
+
+switch in.MNF_CritType
+case  'nf'
+  subplot(2,1,2)
+  plot(crit(1:min(out.k_ext+3,end)))
+  if in.MNF_MeanCentering   
+    legend('noise var/component variance')
+  else
+    legend('noise MSS/component MSS')
+  end
+  
+case  'n'
+  subplot(2,1,2)
+  plot(crit(1:min(out.k_ext+3,end))/tot);
+  if in.MNF_MeanCentering   
+    legend('noise var/total variance')
+  else
+    legend('noise MSS/total MSS')
+  end
+    
+case  'acor'
+  subplot(2,1,2)
+  plot(crit(1:min(out.k_ext+3,end)))
+  if in.MNF_MeanCentering   
+    legend('autocorrelation')
+  else
+    legend('uncentered autcorrelation')
+  end
+    
+case  'acov'
+  subplot(2,1,1)
+  plot([1-cumsum(out.frac(1:min(out.k_ext+3,end))), 1-cumsum(crit(1:min(out.k_ext+3,end)))/sum(crit)]);
+  legend('relative squared reconstruction error', 'unexplained autocovariance fraction');
+  
+  subplot(2,1,2)
+  plot(crit(1:min(out.k_ext+3,end))/tot)
+  if in.MNF_MeanCentering   
+    legend('autocovariance/total variance')
+  else
+    legend('uncentered autocovariance/total MSS')
+  end
+end
+    
+xlabel('# of components')
+drawnow
+
+if opt_als.max_iter > 0
+  opt_als.mode     = 'features';
+  [out.z, out.y] = als(x,out.z0,opt_als);
+else
+  out.z = out.z0;
+  out.y = (+out.z)\(+x);
+  m = size(x,1);
+
+  out.y = dataset(out.y);
+  out.y.featlab  = x.featlab;
+  out.y.featsize = x.featsize;
+  out.y.user     = x.user;
+  out.y.name = [x.name ': extracted spectra'];
+end  
+
+figure(h(3))
+showspim(out.y)
+shg
+  
+figure(h(4));
+showspim(out.z)
+colormap(jet)
+shg
+  
+drawnow
+
+tm_putvar(in.Out, out);
+
+return
+
Index: /hypertools/hypertools/tmr_opa.m
===================================================================
--- /hypertools/hypertools/tmr_opa.m	(revision 3)
+++ /hypertools/hypertools/tmr_opa.m	(revision 3)
@@ -0,0 +1,316 @@
+function tmr_opa(h,eventdata,varargin)
+% 
+
+% (C) 2006 S. Verzakov, verzakov@tudelft.nl
+
+% title of application
+Title = 'OPA/ALS';
+
+% width & font size of input dialog
+Width = 0.3;   % normalized
+FontSize = 10; % points (9,10,11,12) are recommended
+
+ImmediateApply = -1;
+
+%=== do not change this code (begin)
+InpDesc = InputDescription;   
+DlgOptions.Title    = Title;
+DlgOptions.Width    = Width;
+DlgOptions.FontSize = FontSize;
+DlgOptions.Mode     = 'Run';
+DlgOptions.RunFunc  = @Run;
+DlgOptions.FinFunc  = @tm_fin;
+DlgOptions.FinInp   = get(h,'Parent');
+DlgOptions.ImmApp   = ImmediateApply;
+advdlg(InpDesc,DlgOptions)
+%=== do not change this code (end)
+
+return;
+
+%------------------------------------------------------- InputDescription ---
+% Here we define the parameters that control the appearance of the main (plot) figure (in the left).
+% We describe the uicontrols in the input dialog box (right)
+% Possible control types are shown and their use is described below
+
+function id = InputDescription
+
+% edit (variable)
+id.Dataset.Type = 'variable';
+id.Dataset.Prompt = 'Read data from a dataset';
+id.Dataset.CanBeEmpty = 1; % default 0
+id.Dataset.Mode = 'get'; % default 'put' ('put','get')
+id.Dataset.WarnBeforeOverwrite = 0; % default 1 
+id.Dataset.MakeGlobal = 0; % default 0 
+id.Dataset.Default = 'data'; % default '' 
+
+% delimiter
+id.Delimiter1a.Type = 'delimiter';
+id.Delimiter1a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter1b.Type = 'delimiter';
+id.Delimiter1b.Prompt = '--- OPA parameters ------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% popup 
+id.OPA_Mode.Type = 'set';
+id.OPA_Mode.Prompt = 'Mode';
+id.OPA_Mode.Style = 'pop'; % default 'pop' ('pop', 'box') 
+id.OPA_Mode.Return = 'val'; % default 'val' ('val' - return string, 'ind' - return index/indices)
+id.OPA_Mode.List = {'pure spectra','pure channels'};
+id.OPA_Mode.Default = 1; % default 1
+
+% edit (int)
+id.OPA_MaxNum.Type = 'int';
+id.OPA_MaxNum.Prompt = 'Maximal number of components [1, inf]';
+id.OPA_MaxNum.Range = [1 inf];
+id.OPA_MaxNum.Inclusive = [1 1];
+id.OPA_MaxNum.Length = [1];
+id.OPA_MaxNum.Default = [inf]; %default [] 
+
+% popup 
+%id.OPA_IndepMeas.Type = 'set';
+%id.OPA_IndepMeas.Prompt = 'Independance measure (inluences returned dissim values only)';
+%id.OPA_IndepMeas.Style = 'pop'; % default 'pop' ('pop', 'box') 
+%id.OPA_IndepMeas.Return = 'val'; % default 'val' ('val' - return string, 'ind' - return index/indices)
+%id.OPA_IndepMeas.List = {'determinant','projection'};
+%id.OPA_IndepMeas.Default = 1; % default 1
+
+% edit (double)
+id.OPA_Eps.Type = 'double';
+id.OPA_Eps.Prompt = 'Stopping critetion';
+id.OPA_Eps.Range = [0 inf];
+id.OPA_Eps.Inclusive = [1 0];
+id.OPA_Eps.Length = [1];
+id.OPA_Eps.Default = [1e-2]; %default [] 
+
+% delimiter
+id.Delimiter2a.Type = 'delimiter';
+id.Delimiter2a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter2b.Type = 'delimiter';
+id.Delimiter2b.Prompt = '--- ALS parameters ------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (int)
+id.ALS_MaxIt.Type = 'int';
+id.ALS_MaxIt.Prompt = 'Maximal number of iterations';
+id.ALS_MaxIt.Range = [0 inf];
+id.ALS_MaxIt.Inclusive = [1 0];
+id.ALS_MaxIt.Length = [1];
+id.ALS_MaxIt.Default = [0]; %default [] 
+
+% popup 
+id.ALS_CritType.Type = 'set';
+id.ALS_CritType.Prompt = 'Type of stopping criterion';
+id.ALS_CritType.Style = 'pop'; % default 'pop' ('pop', 'box') 
+id.ALS_CritType.Return = 'val'; % default 'val' ('val' - return string, 'ind' - return index/indices)
+id.ALS_CritType.List = {'convergence','reconstruction'};
+id.ALS_CritType.Default = 1; % default 1
+
+% edit (double)
+id.ALS_Eps.Type = 'double';
+id.ALS_Eps.Prompt = 'Stopping critetion';
+id.ALS_Eps.Range = [0 inf];
+id.ALS_Eps.Inclusive = [1 0];
+id.ALS_Eps.Length = [1];
+id.ALS_Eps.Default = [1e-2]; %default [] 
+
+% delimiter
+id.Delimiter3a.Type = 'delimiter';
+id.Delimiter3a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter3b.Type = 'delimiter';
+id.Delimiter3b.Prompt = '--- Output ---------------------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (double)
+id.ProgRep.Type = 'double';
+id.ProgRep.Prompt = 'Progress report file handle (1 means command window)';
+id.ProgRep.Length = [1];
+id.ProgRep.Default = [1]; % default [] 
+id.ProgRep.CanBeEmpty = 1;
+
+% edit (variable)
+id.Out.Type = 'variable';
+id.Out.Prompt = 'Save data in a structure';
+id.Out.CanBeEmpty = 1; % default 0
+id.Out.Mode = 'put'; % default 'put' ('put','get')
+id.Out.WarnBeforeOverwrite = 0; % default 1 
+id.Out.MakeGlobal = 0; % default 0 
+id.Out.Default = 'out'; % default '' 
+id.Out.Enable = 'on'; % default 'on'
+
+return;
+
+
+%------------------------------------------------------- Run ---
+% It is the response to the 'Run' button in the input dialog.
+% We take the parameter values from  the input dialog (the right one) and, with them, 
+% we run the algorithm and plot the results in the plot (left) window
+
+function Run(in)
+
+layout = [2 2];
+
+h(1) = tm_figure(['OPA ' in.OPA_Mode ' selection'], 'OPA_SpecChan', 'close', [layout 1]);  clf;
+h(2) = tm_figure('OPA dissim and error',            'OPA_Diss&Err', 'close', [layout 2]);  clf;
+
+if in.ALS_MaxIt > 0
+  h(3) = tm_figure('Pure spectra (refined by ALS)',   'OPA_Spec',     'close', [layout 3]);  clf;
+  h(4) = tm_figure('Pure channels (refined by ALS)',  'OPA_Chan',     'close', [layout 4]);  clf;
+else
+  h(3) = tm_figure('OPA: Spectra',   'OPA_Spec',     'close', [layout 3]);  clf;
+  h(4) = tm_figure('OPA: Channels',  'OPA_Chan',     'close', [layout 4]);  clf;
+end  
+
+
+drawnow
+
+x = tm_getvar(in.Dataset);
+  
+opt_opa.max_num = in.OPA_MaxNum;
+
+%switch in.OPA_IndepMeas
+%case 'absolute'
+%  opt_opa.indep_meas = 'abs';  
+%case 'relaive'
+%  opt_opa.indep_meas = 'rel';    
+%end
+
+opt_opa.eps = in.OPA_Eps;
+opt_opa.verbose = in.ProgRep;
+
+opt_als.max_iter = in.ALS_MaxIt;
+opt_als.crit     = in.ALS_CritType;
+opt_als.eps      = in.ALS_Eps;
+opt_als.verbose  = in.ProgRep;
+%opt_als.crop_mode = 'features';
+
+switch in.OPA_Mode
+case 'pure spectra'
+  [out.y0, out.sel_obj_ind, out.sel_obj_dis, out.dis, out.err] = opaps(x,opt_opa);
+
+  
+  figure(h(1))
+  [rind, cind] = ind2sub(x.objsize,out.sel_obj_ind);
+  ha = showspim(out.y0,[],[rind(:), cind(:)]);
+  shg
+  
+  figure(h(2))
+  subplot(3,1,1)
+  plot(out.sel_obj_dis(:,1))
+  ylabel('abs dissim')
+  subplot(3,1,2)
+  plot(out.sel_obj_dis(:,2))
+  ylabel('rel dissim')
+  subplot(3,1,3)
+  plot(out.err)
+  ylabel('rel sqr proj err')
+  xlabel('# of components')
+  shg
+  
+  drawnow
+  
+  if 0
+  ind = [1,4,6,10,11,14,15];
+  xind = 1:length(out.sel_obj_ind);
+  xind(ind) = [];
+  out.out0 = out;
+  out.y0(xind,:) = [];
+  out.sel_obj_ind(xind) = [];
+  out.sel_obj_dis(xind,:) = []; 
+  out.dis(:,xind,:) = []; 
+  out.err(xind) = [];
+  [rind, cind] = ind2sub(x.objsize,out.sel_obj_ind);
+  end
+
+  
+  if opt_als.max_iter > 0
+    opt_als.mode = 'samples';
+    [out.z, out.y] = als(x,out.y0,opt_als);
+    y_desc = [repmat('spec ',[size(out.y0,1) 1]) num2str((1:size(out.y0,1))') repmat(': r=',[size(out.y0,1) 1]) num2str(rind(:)) repmat(', c=',[size(out.y0,1) 1]) num2str(cind(:)) repmat(', refined',[size(out.y0,1) 1])];
+  else
+    out.y = out.y0;  
+    out.z = remove_spectra_info(x);
+    out.z = setdata(out.z,(+x)/(+out.y),(1:size(out.y,1))');  
+    out.z.name = [out.z.name ': extracted channels'];
+  end  
+
+
+case 'pure channels'
+  [out.w, out.sel_var_dis, out.dis, out.err] = opam(x,opt_opa);
+  out.z0 = x*out.w;
+  
+  figure(h(1));
+  ha = showspim(out.z0);
+  daspect([1 1 1])
+  colormap(jet)
+  shg
+  
+  figure(h(2))
+  subplot(3,1,1)
+  plot(out.sel_var_dis(:,1))
+  ylabel('abs dissim')
+  subplot(3,1,2)
+  plot(out.sel_var_dis(:,2))
+  ylabel('rel dissim')
+  subplot(3,1,3)
+  plot(out.err)
+  ylabel('rel squared proj err')
+  xlabel('# of components')
+  shg
+
+  drawnow
+  
+  if opt_als.max_iter > 0
+    opt_als.mode = 'features';
+    [out.z, out.y] = als(x,out.z0,opt_als);
+    
+    units = specunits(x);
+    if ~isempty(units)
+      units = [' ' units];  
+    end
+    out.z.featlab = [num2str(out.z0.featlab) repmat([units ', refined'],[size(out.z0,2) 1])];
+  else
+    out.z = out.z0;
+    out.y = (+out.z)\(+x);
+    out.y = dataset(out.y);
+    out.y.featlab  = x.featlab;
+    out.y.featsize = x.featsize;
+    out.y.user     = x.user;
+    out.y.name     = [x.name ': extracted spectra']
+  end  
+end
+
+figure(h(3))
+if isfield(out,'y0');
+  if opt_als.max_iter == 0 
+    showspim(out.y,[],[rind(:),cind(:)])
+  else
+    showspim(out.y,[],y_desc)
+  end
+else
+  showspim(out.y,[],[],out.w.data.ind);
+end
+shg
+  
+figure(h(4));
+if isfield(out,'y0');
+  showspim(out.z,[],[],[rind(:),cind(:)])
+else
+  showspim(out.z);
+end
+shg
+  
+drawnow
+
+tm_putvar(in.Out, out);
+
+return
+
Index: /hypertools/hypertools/tmr_simplisma.m
===================================================================
--- /hypertools/hypertools/tmr_simplisma.m	(revision 3)
+++ /hypertools/hypertools/tmr_simplisma.m	(revision 3)
@@ -0,0 +1,304 @@
+function tmr_simplisma(h,eventdata,varargin)
+% 
+
+% (C) 2006 S. Verzakov, verzakov@tudelft.nl
+
+% title of application
+Title = 'SIMPLISMA/ALS';
+
+% width & font size of input dialog
+Width = 0.3;   % normalized
+FontSize = 10; % points (9,10,11,12) are recommended
+
+ImmediateApply = -1;
+
+%=== do not change this code (begin)
+InpDesc = InputDescription;   
+DlgOptions.Title    = Title;
+DlgOptions.Width    = Width;
+DlgOptions.FontSize = FontSize;
+DlgOptions.Mode     = 'Run';
+DlgOptions.RunFunc  = @Run;
+DlgOptions.FinFunc  = @tm_fin;
+DlgOptions.FinInp   = get(h,'Parent');
+DlgOptions.ImmApp   = ImmediateApply;
+advdlg(InpDesc,DlgOptions)
+%=== do not change this code (end)
+
+return;
+
+%------------------------------------------------------- InputDescription ---
+% Here we define the parameters that control the appearance of the main (plot) figure (in the left).
+% We describe the uicontrols in the input dialog box (right)
+% Possible control types are shown and their use is described below
+
+function id = InputDescription
+
+% edit (variable)
+id.Dataset.Type = 'variable';
+id.Dataset.Prompt = 'Read data from a dataset';
+id.Dataset.CanBeEmpty = 1; % default 0
+id.Dataset.Mode = 'get'; % default 'put' ('put','get')
+id.Dataset.WarnBeforeOverwrite = 0; % default 1 
+id.Dataset.MakeGlobal = 0; % default 0 
+id.Dataset.Default = 'data'; % default '' 
+
+% delimiter
+id.Delimiter1a.Type = 'delimiter';
+id.Delimiter1a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter1b.Type = 'delimiter';
+id.Delimiter1b.Prompt = '--- SIMPLISMA parameters ----------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% popup 
+id.SIMPLISMA_Mode.Type = 'set';
+id.SIMPLISMA_Mode.Prompt = 'Mode';
+id.SIMPLISMA_Mode.Style = 'pop'; % default 'pop' ('pop', 'box') 
+id.SIMPLISMA_Mode.Return = 'val'; % default 'val' ('val' - return string, 'ind' - return index/indices)
+id.SIMPLISMA_Mode.List = {'pure spectra','pure channels'};
+id.SIMPLISMA_Mode.Default = 1; % default 1
+
+% edit (int)
+id.SIMPLISMA_MaxNum.Type = 'int';
+id.SIMPLISMA_MaxNum.Prompt = 'Maximal number of components [1, inf]';
+id.SIMPLISMA_MaxNum.Range = [1 inf];
+id.SIMPLISMA_MaxNum.Inclusive = [1 1];
+id.SIMPLISMA_MaxNum.Length = [1];
+id.SIMPLISMA_MaxNum.Default = [inf]; %default [] 
+
+% popup 
+%id.SIMPLISMA_IndepMeas.Type = 'set';
+%id.SIMPLISMA_IndepMeas.Prompt = 'Independance measure (inluences returned dissim values only)';
+%id.SIMPLISMA_IndepMeas.Style = 'pop'; % default 'pop' ('pop', 'box') 
+%id.SIMPLISMA_IndepMeas.Return = 'val'; % default 'val' ('val' - return string, 'ind' - return index/indices)
+%id.SIMPLISMA_IndepMeas.List = {'determinant','projection'};
+%id.SIMPLISMA_IndepMeas.Default = 1; % default 1
+
+% edit (double)
+id.SIMPLISMA_Theta.Type = 'double';
+id.SIMPLISMA_Theta.Prompt = 'Theta: regularization offset';
+id.SIMPLISMA_Theta.Range = [0 inf];
+id.SIMPLISMA_Theta.Inclusive = [1 0];
+id.SIMPLISMA_Theta.Length = [1];
+id.SIMPLISMA_Theta.Default = [1e-2]; %default [] 
+
+% edit (double)
+id.SIMPLISMA_Eps.Type = 'double';
+id.SIMPLISMA_Eps.Prompt = 'Stopping critetion';
+id.SIMPLISMA_Eps.Range = [0 inf];
+id.SIMPLISMA_Eps.Inclusive = [1 0];
+id.SIMPLISMA_Eps.Length = [1];
+id.SIMPLISMA_Eps.Default = [1e-2]; %default [] 
+
+% delimiter
+id.Delimiter2a.Type = 'delimiter';
+id.Delimiter2a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter2b.Type = 'delimiter';
+id.Delimiter2b.Prompt = '--- ALS parameters ------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (int)
+id.ALS_MaxIt.Type = 'int';
+id.ALS_MaxIt.Prompt = 'Maximal number of iterations';
+id.ALS_MaxIt.Range = [0 inf];
+id.ALS_MaxIt.Inclusive = [1 0];
+id.ALS_MaxIt.Length = [1];
+id.ALS_MaxIt.Default = [0]; %default [] 
+
+% popup 
+id.ALS_CritType.Type = 'set';
+id.ALS_CritType.Prompt = 'Type of stopping criterion';
+id.ALS_CritType.Style = 'pop'; % default 'pop' ('pop', 'box') 
+id.ALS_CritType.Return = 'val'; % default 'val' ('val' - return string, 'ind' - return index/indices)
+id.ALS_CritType.List = {'convergence','reconstruction'};
+id.ALS_CritType.Default = 1; % default 1
+
+% edit (double)
+id.ALS_Eps.Type = 'double';
+id.ALS_Eps.Prompt = 'Stopping critetion';
+id.ALS_Eps.Range = [0 inf];
+id.ALS_Eps.Inclusive = [1 0];
+id.ALS_Eps.Length = [1];
+id.ALS_Eps.Default = [1e-2]; %default [] 
+
+% delimiter
+id.Delimiter3a.Type = 'delimiter';
+id.Delimiter3a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter3b.Type = 'delimiter';
+id.Delimiter3b.Prompt = '--- Output ---------------------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (double)
+id.ProgRep.Type = 'double';
+id.ProgRep.Prompt = 'Progress report file handle (1 means command window)';
+id.ProgRep.Length = [1];
+id.ProgRep.Default = [1]; % default [] 
+id.ProgRep.CanBeEmpty = 1;
+
+% edit (variable)
+id.Out.Type = 'variable';
+id.Out.Prompt = 'Save data in a structure';
+id.Out.CanBeEmpty = 1; % default 0
+id.Out.Mode = 'put'; % default 'put' ('put','get')
+id.Out.WarnBeforeOverwrite = 0; % default 1 
+id.Out.MakeGlobal = 0; % default 0 
+id.Out.Default = 'out'; % default '' 
+id.Out.Enable = 'on'; % default 'on'
+
+return;
+
+
+%------------------------------------------------------- Run ---
+% It is the response to the 'Run' button in the input dialog.
+% We take the parameter values from  the input dialog (the right one) and, with them, 
+% we run the algorithm and plot the results in the plot (left) window
+
+function Run(in)
+
+layout = [2 2];
+
+h(1) = tm_figure(['SIMPLISMA ' in.SIMPLISMA_Mode ' selection'], 'SIMPLISMA_SpecChan', 'close', [layout 1]);  clf;
+h(2) = tm_figure('SIMPLISMA purity and error',            'SIMPLISMA_Pur&Err', 'close', [layout 2]);  clf;
+
+if in.ALS_MaxIt > 0
+  h(3) = tm_figure('Pure spectra (refined by ALS)',   'SIMPLISMA_Spec',     'close', [layout 3]);  clf;
+  h(4) = tm_figure('Pure channels (refined by ALS)',  'SIMPLISMA_Chan',     'close', [layout 4]);  clf;
+else
+  h(3) = tm_figure('SIMPLISMA: Spectra',   'SIMPLISMA_Spec',     'close', [layout 3]);  clf;
+  h(4) = tm_figure('SIMPLISMA: Channels',  'SIMPLISMA_Chan',     'close', [layout 4]);  clf;
+end  
+
+
+drawnow
+
+x = tm_getvar(in.Dataset);
+
+opt_simplisma.max_num = in.SIMPLISMA_MaxNum;
+opt_simplisma.theta   = in.SIMPLISMA_Theta;
+opt_simplisma.eps     = in.SIMPLISMA_Eps;
+opt_simplisma.verbose = in.ProgRep;
+
+opt_als.max_iter = in.ALS_MaxIt;
+opt_als.crit     = in.ALS_CritType;
+opt_als.eps      = in.ALS_Eps;
+opt_als.verbose  = in.ProgRep;
+
+
+switch in.SIMPLISMA_Mode
+case 'pure spectra'
+  [out.y0, out.sel_obj_ind, out.sel_obj_purity, out.purity, out.R_ratio, out.err] = simplismaps(x, opt_simplisma);
+  
+  figure(h(1))
+  [rind, cind] = ind2sub(x.objsize,out.sel_obj_ind);
+  showspim(out.y0,[],[rind(:) cind(:)])
+  shg
+  
+  figure(h(2))
+  subplot(3,1,1)
+  plot(out.sel_obj_purity(:,1))
+  ylabel('abs purity')
+  subplot(3,1,2)
+  plot(out.sel_obj_purity(:,2))
+  ylabel('rel purity')
+  subplot(3,1,3)
+  plot([1:length(out.err)]', [out.R_ratio, out.err])
+  ylabel('R_{ratio} and err')
+  xlabel('# of components')
+  shg
+  
+  drawnow
+
+  if opt_als.max_iter > 0
+    opt_als.mode = 'samples';
+    [out.z, out.y] = als(x,out.y0,opt_als);
+    y_desc = [repmat('spec ',[size(out.y0,1) 1]) num2str((1:size(out.y0))') repmat(': r=',[size(out.y0,1) 1]) num2str(rind(:)) repmat(', c=',[size(out.y0,1) 1]) num2str(cind(:)) repmat(', refined',[size(out.y0,1) 1])];
+  else
+    out.y = out.y0;  
+    out.z = remove_spectra_info(x);
+    out.z = setdata(out.z,(+x)/(+out.y),(1:size(out.y,1))');  
+    out.z.name = [out.z.name ': extracted channels'];
+  end  
+
+
+case 'pure channels'
+  [out.w, out.sel_var_purity, out.purity, out.R_ratio, out.err] = simplismam(x, opt_simplisma);
+  out.z0 = x*out.w;
+
+  figure(h(1));
+  showspim(out.z0)
+  daspect([1 1 1])
+  colormap(jet)
+  shg
+  
+  figure(h(2))
+  subplot(3,1,1)
+  plot(out.sel_var_purity(:,1))
+  ylabel('abs purity')
+  subplot(3,1,2)
+  plot(out.sel_var_purity(:,2))
+  ylabel('rel purity')
+  subplot(3,1,3)
+  plot([1:length(out.err)]', [out.R_ratio, out.err])
+  ylabel('R_{ratio} and err')
+  xlabel('# of components')
+  shg
+  
+  drawnow
+  
+  if opt_als.max_iter > 0
+    opt_als.mode = 'features';    
+    [out.z, out.y] = als(x,out.z0,opt_als);
+    
+    units = specunits(x);
+    if ~isempty(units)
+      units = [' ' units];  
+    end
+    out.z.featlab = [num2str(out.z0.featlab) repmat([units ', refined'],[size(out.z0,2) 1])];
+
+  else
+    out.z = out.z0;
+    out.y = (+out.z)\(+x);
+    out.y = dataset(out.y);
+    out.y.featlab  = x.featlab;
+    out.y.featsize = x.featsize;
+    out.y.user     = x.user;
+    out.y.name     = [x.name ': extracted spectra']
+  end  
+end
+
+
+figure(h(3))
+if isfield(out,'y0');
+  if opt_als.max_iter == 0 
+    showspim(out.y,[],[rind(:),cind(:)])
+  else
+    showspim(out.y,[],y_desc)
+  end
+else
+  showspim(out.y,[],[],out.w.data.ind);
+end
+shg
+  
+figure(h(4));
+if isfield(out,'y0');
+  showspim(out.z,[],[],[rind(:),cind(:)])
+else
+  showspim(out.z);
+end
+shg
+  
+drawnow
+
+tm_putvar(in.Out, out);
+
+return
+
Index: /hypertools/hypertools/tmr_varimax.m
===================================================================
--- /hypertools/hypertools/tmr_varimax.m	(revision 3)
+++ /hypertools/hypertools/tmr_varimax.m	(revision 3)
@@ -0,0 +1,279 @@
+function tmr_varimax(h,eventdata,varargin)
+% 
+
+% (C) 2006 S. Verzakov, verzakov@tudelft.nl
+
+% title of application
+Title = 'PCA/VARIMAX/ALS';
+
+% width & font size of input dialog
+Width = 0.3;   % normalized
+FontSize = 10; % points (9,10,11,12) are recommended
+
+ImmediateApply = -1;
+
+%=== do not change this code (begin)
+InpDesc = InputDescription;   
+DlgOptions.Title    = Title;
+DlgOptions.Width    = Width;
+DlgOptions.FontSize = FontSize;
+DlgOptions.Mode     = 'Run';
+DlgOptions.RunFunc  = @Run;
+DlgOptions.FinFunc  = @tm_fin;
+DlgOptions.FinInp   = get(h,'Parent');
+DlgOptions.ImmApp   = ImmediateApply;
+advdlg(InpDesc,DlgOptions)
+%=== do not change this code (end)
+
+return;
+
+%------------------------------------------------------- InputDescription ---
+% Here we define the parameters that control the appearance of the main (plot) figure (in the left).
+% We describe the uicontrols in the input dialog box (right)
+% Possible control types are shown and their use is described below
+
+function id = InputDescription
+
+% edit (variable)
+id.Dataset.Type = 'variable';
+id.Dataset.Prompt = 'Read data from a dataset';
+id.Dataset.CanBeEmpty = 1; % default 0
+id.Dataset.Mode = 'get'; % default 'put' ('put','get')
+id.Dataset.WarnBeforeOverwrite = 0; % default 1 
+id.Dataset.MakeGlobal = 0; % default 0 
+id.Dataset.Default = 'data'; % default '' 
+
+% delimiter
+id.Delimiter1a.Type = 'delimiter';
+id.Delimiter1a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter1b.Type = 'delimiter';
+id.Delimiter1b.Prompt = '--- PCA/VARIMAX parameters ----------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% popup 
+id.VARIMAX_Mode.Type = 'set';
+id.VARIMAX_Mode.Prompt = 'Mode';
+id.VARIMAX_Mode.Style = 'pop'; % default 'pop' ('pop', 'box') 
+id.VARIMAX_Mode.Return = 'val'; % default 'val' ('val' - return string, 'ind' - return index/indices)
+id.VARIMAX_Mode.List = {'sparse spectra (pixels)','sparse channels (images)'};
+id.VARIMAX_Mode.Default = 1; % default 1
+
+% edit (double)
+id.VARIMAX_NumFrac.Type = 'double';
+id.VARIMAX_NumFrac.Prompt = 'Number of components/Fraction of explained sum of squares';
+id.VARIMAX_NumFrac.Range = [0 inf];
+id.VARIMAX_NumFrac.Inclusive = [0 0];
+id.VARIMAX_NumFrac.Length = [1];
+id.VARIMAX_NumFrac.Default = [0.95]; %default [] 
+
+% edit (int)
+id.VARIMAX_NAttempts.Type = 'int';
+id.VARIMAX_NAttempts.Prompt = 'Number of attempts';
+id.VARIMAX_NAttempts.Range = [1 inf];
+id.VARIMAX_NAttempts.Inclusive = [1 0];
+id.VARIMAX_NAttempts.Length = [1];
+id.VARIMAX_NAttempts.Default = [3]; %default [] 
+
+% edit (int)
+id.VARIMAX_MaxIter.Type = 'int';
+id.VARIMAX_MaxIter.Prompt = 'Number of full iterations within an attempt';
+id.VARIMAX_MaxIter.Range = [0 inf];
+id.VARIMAX_MaxIter.Inclusive = [1 0];
+id.VARIMAX_MaxIter.Length = [1];
+id.VARIMAX_MaxIter.Default = [3]; %default [] 
+
+% edit (double)
+id.VARIMAX_Eps.Type = 'double';
+id.VARIMAX_Eps.Prompt = 'Stopping critetion: (new_var-old_var) < eps*old_var';
+id.VARIMAX_Eps.Range = [0 1];
+id.VARIMAX_Eps.Inclusive = [0 0];
+id.VARIMAX_Eps.Length = [1];
+id.VARIMAX_Eps.Default = [1e-6]; %default [] 
+
+% delimiter
+id.Delimiter2a.Type = 'delimiter';
+id.Delimiter2a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter2b.Type = 'delimiter';
+id.Delimiter2b.Prompt = '--- ALS parameters ------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (int)
+id.ALS_MaxIt.Type = 'int';
+id.ALS_MaxIt.Prompt = 'Maximal number of iterations';
+id.ALS_MaxIt.Range = [0 inf];
+id.ALS_MaxIt.Inclusive = [1 0];
+id.ALS_MaxIt.Length = [1];
+id.ALS_MaxIt.Default = [0]; %default [] 
+
+% popup 
+id.ALS_CritType.Type = 'set';
+id.ALS_CritType.Prompt = 'Type of stopping criterion';
+id.ALS_CritType.Style = 'pop'; % default 'pop' ('pop', 'box') 
+id.ALS_CritType.Return = 'val'; % default 'val' ('val' - return string, 'ind' - return index/indices)
+id.ALS_CritType.List = {'convergence','reconstruction'};
+id.ALS_CritType.Default = 1; % default 1
+
+% edit (double)
+id.ALS_Eps.Type = 'double';
+id.ALS_Eps.Prompt = 'Stopping critetion';
+id.ALS_Eps.Range = [0 inf];
+id.ALS_Eps.Inclusive = [1 0];
+id.ALS_Eps.Length = [1];
+id.ALS_Eps.Default = [1e-2]; %default [] 
+
+% delimiter
+id.Delimiter3a.Type = 'delimiter';
+id.Delimiter3a.Prompt = '';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% delimiter
+id.Delimiter3b.Type = 'delimiter';
+id.Delimiter3b.Prompt = '--- Output ---------------------------------------------------------------';
+% default '----------------------------------------------------------------------------------------------------------------------------------------------'
+
+% edit (double)
+id.ProgRep.Type = 'double';
+id.ProgRep.Prompt = 'Progress report file handle (1 means command window)';
+id.ProgRep.Length = [1];
+id.ProgRep.Default = [1]; % default [] 
+id.ProgRep.CanBeEmpty = 1;
+
+% edit (variable)
+id.Out.Type = 'variable';
+id.Out.Prompt = 'Save data in a structure';
+id.Out.CanBeEmpty = 1; % default 0
+id.Out.Mode = 'put'; % default 'put' ('put','get')
+id.Out.WarnBeforeOverwrite = 0; % default 1 
+id.Out.MakeGlobal = 0; % default 0 
+id.Out.Default = 'out'; % default '' 
+id.Out.Enable = 'on'; % default 'on'
+
+return;
+
+
+%------------------------------------------------------- Run ---
+% It is the response to the 'Run' button in the input dialog.
+% We take the parameter values from  the input dialog (the right one) and, with them, 
+% we run the algorithm and plot the results in the plot (left) window
+
+function Run(in)
+
+layout = [2 2];
+
+h(1) = tm_figure(['VARIMAX ' in.VARIMAX_Mode ' extraction'], 'VARIMAX_SpecChan', 'close', [layout 1]);  clf;
+h(2) = tm_figure('PCA err and VARIMAX sparsity', 'VARIMAX_Err&Spars', 'close', [layout 2]);  clf;
+
+if in.ALS_MaxIt > 0
+  h(3) = tm_figure('Pure spectra (refined by ALS)',   'VARIMAX_Spec', 'close', [layout 3]);  clf;
+  h(4) = tm_figure('Pure channels (refined by ALS)',  'VARIMAX_Chan', 'close', [layout 4]);  clf;
+else
+  h(3) = tm_figure('VARIMAX: Sectra',   'VARIMAX_Spec',  'close', [layout 3]);  clf;
+  h(4) = tm_figure('VARIMAX: Channels', 'VARIMAX_Chan',  'close', [layout 4]);  clf;
+end
+
+
+drawnow
+
+x = tm_getvar(in.Dataset);
+  
+opt_varimax.n_attempts = in.VARIMAX_NAttempts;
+opt_varimax.max_iter   = in.VARIMAX_MaxIter;
+opt_varimax.eps        = in.VARIMAX_Eps;
+opt_varimax.verbose    = in.ProgRep;
+
+opt_als.max_iter = in.ALS_MaxIt;
+opt_als.crit     = in.ALS_CritType;
+opt_als.eps      = in.ALS_Eps;
+opt_als.verbose  = in.ProgRep;
+
+
+switch in.VARIMAX_Mode
+case 'sparse spectra (pixels)'
+  [out.w, out.k_ext, out.frac, out.v, out.z, out.y0] = varimaxom(x, in.VARIMAX_NumFrac, opt_varimax);
+
+  %out.y0 = dataset((out.w.data.rot)');
+  %out.y0.featlab = x.featlab;
+  %out.y0.featsize = x.featsize;
+  %out.y0.user = x.user;
+  
+  figure(h(1))
+  showspim(out.y0)
+  shg
+  
+  figure(h(2))
+  subplot(2,1,1)
+  plot((1-out.frac)')
+  ylabel('PCA err')
+  subplot(2,1,2)
+  plot(out.v')
+  xlabel('# of components')
+  ylabel('VARIMAX spars')
+  shg
+   
+  drawnow  
+  
+  if opt_als.max_iter > 0
+    opt_als.mode = 'samples';
+    [out.z, out.y] = als(x,out.y0,opt_als);
+  else
+    out.y = out.y0;
+    %out.z = remove_spec_info(x*out.y0);
+  end
+
+case 'sparse channels (images)'
+  [out.w, out.k_ext, out.frac, out.v, out.z0, out.y] = varimaxfm(x, in.VARIMAX_NumFrac, opt_varimax);
+
+  %out.z0 = remove_spec_info(x*out.w);
+  
+  figure(h(1));
+  showspim(out.z0)
+  daspect([1 1 1])
+  colormap(jet)
+  shg
+  
+  figure(h(2))
+  subplot(2,1,1)
+  plot((1-out.frac)')
+  ylabel('PCA err')
+  subplot(2,1,2)
+  plot(out.v')
+  xlabel('# of components')
+  ylabel('VARIMAX spars')
+  shg
+
+  drawnow
+
+  if opt_als.max_iter > 0
+    opt_als.mode = 'features';
+    [out.z, out.y] = als(x,out.z0,opt_als);
+  else
+    out.z = out.z0;
+    %out.y = dataset(out.w.data.rot\eye(size(out.w.data.rot,1)));
+    %out.y.featlab = x.featlab;
+    %out.y.featsize = x.featsize;
+    %out.y.user = x.user;
+  end
+end
+
+figure(h(3))
+showspim(out.y) 
+shg
+
+figure(h(4));
+showspim(out.z)
+daspect([1 1 1])
+colormap(jet)
+shg
+  
+drawnow
+
+tm_putvar(in.Out, out);
+
+return
+
Index: /hypertools/hypertools/varimax.m
===================================================================
--- /hypertools/hypertools/varimax.m	(revision 3)
+++ /hypertools/hypertools/varimax.m	(revision 3)
@@ -0,0 +1,148 @@
+%VARIMAX Calculation of the new (sparse) loadings (axes) given the current
+%
+%  [P_MAX, V_MAX] = VARIMAX(P)
+%  [P_MAX, V_MAX] = VARIMAX(P, OPT)
+%
+% INPUT 
+%   P           [K -by- N] orthonormal loadings matrix (P'*P == EYE(N))
+%               usually P columns are a few first (N) pca directions of K
+%               dimensional dataset
+%
+%   OPT.   
+%    N_ATTEMPTS   the number of independent attempts to maximize the varimax criterion; by default = 3
+%    MAX_ITER     the max number of iterations wihin each attempt; each iteration involves 
+%                 optimization over all unsorted pairs visited in random order; by default = 3 
+%    SORT         put the simplest factors first; by default = 1;
+%    EPS          convergence criterion (NEW_CRIT-OLD_CRIT < EPS*OLD_CRIT); by default = 1e-6
+%    VERBOSE      force/disable messages; if PRPROGRESS is available: PRPROGRESS(VERBOSE,['%s\n'],MSG) will be run, 
+%                 if PRPROGRESS is not available: VERBOSE == [] or 0 -- no messages, VERBOSE ~= 0 runs DISP(MSG); 
+%                 by default = []
+%
+%
+% OUTPUT 
+%    P_MAX      [K -by- N] orthonormal loadings matrix (P_MAX'*P_MAX == EYE(N))
+%    V_MAX      [1 -by- N] row of variances of squared factors (sparsity)
+%
+% DESCRIPTION
+% This routine calculates what is called raw Kaiser varimax 
+%
+% SEE ALSO
+% OPA, SIMPLISMA, ALS
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: varimax.m,v 1.10 2007/01/19 00:39:19 serguei Exp $
+
+function [P_max, v_max] = varimax(P, Options)
+
+if nargin < 2
+  Options = [];
+end
+
+DefOptions.n_attempts  = 3;
+DefOptions.max_iter   = 3;
+DefOptions.sort       = 1;
+DefOptions.eps        = 1e-2;
+DefOptions.verbose    = [];
+Options = updstruct(DefOptions, Options);
+
+%----------------
+prprog = exist('prprogress');
+if ~prprog & isempty(Options.verbose)
+  Options.verbose = 0;
+end
+%----------------
+
+P_0   = P;
+P_max = P;
+
+[k, n] = size(P);
+v_max = var(P.*P,1);  
+sum_v_max  = sum(v_max);
+sum_v_0    = sum_v_max;
+
+
+Msg = ['initial total var: ' num2str(sum_v_0)];
+if prprog
+    prprogress(Options.verbose,['%s\n'],Msg);
+elseif Options.verbose
+  disp(['varimax: ' Msg]);
+end  
+
+[i,j] = ind2sub([n,n],find(triu(ones(n),1)));
+npairs = length(i);
+ok = 0;
+for a=1:Options.n_attempts
+  sum_v = sum_v_0;
+  for b=1:Options.max_iter
+    ind = randperm(npairs);
+    for c=1:npairs
+      ii = i(ind(c));
+      jj = j(ind(c));
+
+      dp2 = diff(P(:,[jj, ii]).^2,1,2);
+      pp = prod(P(:,[ii, jj]),2);
+
+      x = k*(sum(dp2.^2) - 4*sum(pp.^2)) - sum(dp2).^2 - 4*sum(pp).^2;
+      y = 4*(k*sum(dp2.*pp) - sum(dp2)*sum(pp));        
+      r = sqrt(x.^2 + y.^2);
+
+      cos4phi = x/r;
+      cosphi2 = 0.5*(1 + sqrt(0.5*(1+cos4phi)));
+      cosphi = sqrt(cosphi2);
+      sinphi = sign(y)*sqrt(1 - cosphi2);
+      %[cos(0.25*atan2(y,x)), cosphi; sin(0.25*atan2(y,x)), sinphi]      
+      %pause
+      R = [[cosphi, -sinphi]; [sinphi, cosphi]];
+      P(:,[ii, jj]) = P(:,[ii, jj])*R; 
+    end
+  
+    sum_v_old = sum_v;
+    v = var(P.*P,1);  
+    sum_v = sum(v);
+
+    Msg = ['attempt: ' num2str(a) '; iter: ' num2str(b) '; total var: ' num2str(sum_v) '; max total var: ' num2str(sum_v_max)];
+    if prprog
+      prprogress(Options.verbose,['%s\n'],Msg);
+    elseif Options.verbose
+      disp(['varimax: ' Msg]);
+    end  
+
+    if (sum_v - sum_v_old) < Options.eps*sum_v_old
+      ok = 1;   
+      break;  
+    end  
+  end
+  
+  if ~ok
+    Msg = ['the maximum number of iterations (' num2str(Options.max_iter) ') is reached before convergence'];
+    if prprog
+      prprogress(Options.verbose,['%s\n'],Msg);
+    elseif Options.verbose
+      disp(['varimax: ' Msg]);
+    end  
+  end 
+
+  if sum_v > sum_v_max
+    P_max = P;
+    v_max = v;
+    sum_v_max = sum_v;    
+  end
+
+  P = P_0;
+end  
+
+clear P_0 P;
+
+if Options.sort
+  [v_max, ind] = sort(v_max);
+  v_max = fliplr(v_max);
+  P_max = P_max(:,fliplr(ind));
+end
+
+return
+
+
+
Index: /hypertools/hypertools/varimaxfm.m
===================================================================
--- /hypertools/hypertools/varimaxfm.m	(revision 3)
+++ /hypertools/hypertools/varimaxfm.m	(revision 3)
@@ -0,0 +1,183 @@
+%VARIMAXFM Extracts sparse (pure) features 
+%          
+%  
+%  U = VARIMAXFM
+%  U = VARIMAXFM([], K_EXT, OPT)
+%  U = VARIMAXFM([], FRAC, OPT)
+%
+%  W = A*U
+%  [W, K_EXT, FRAC, V, P, Z, Y] = MAP(A,U)
+%  [W, K_EXT, FRAC, V, P, Z, Y] = VARIMAXFM(A)
+%  [W, K_EXT, FRAC, V, P, Z, Y] = VARIMAXFM(A, K_TO_EXT, OPT)
+%  [W, K_EXT, FRAC, V, P, Z, Y] = VARIMAXFM(A, FRAC_TO_EXP, OPT)
+%  Y = DATASET(W.DATA.ROT \ EYE(SIZE(W.DATA.ROT,1))) 
+%
+%  C = B*W
+%  C = MAP(B, W)
+%  C = VARIMAXFM(B, W)
+%
+% INPUT 
+%   A             [M -by- K] training dataset
+%   B             [N -by- K] test dataset
+%
+%   U             [K -by- ?] untrained VARIMAXFM mapping
+%   W             [K -by- K_EXT] trained VARIMAXFM affine feature extraction mapping;
+%   K_TO_EXT, 
+%   FRAC_TO_EXT   
+%                 the (integer) number of components to be extracted (1<= K_TO_EXT <= (K,M)) or 
+%                 which fraction of variance to be explained (0 < FRAC_TO_EXP < 1) by PCA;
+%                 NOTE: the number of PCs taken into account should be smaller than number of 
+%                 objects/features in the training dataset (otherwise the result of algorithm is trivial);
+%                 by default FRAC = 0.95
+%
+%   OPT.          optional VARIMAX settings 
+%    N_ATTEMPTS   the number of independent attempts to maximize the varimax criterion; by default = 3 
+%    MAX_ITER     the max number of iterations wihin each attempt; each iteration involves 
+%                 optimization over all unsorted pairs visited in random order; by default = 3 
+%    SORT         put the simplest factors first; by default = 1;
+%    EPS          convergence criterion (NEW_VAR-OLD_VAR < EPS*OLD_VAR); by default = 1e-6
+%    VERBOSE      force/disable messages; PRPROGRESS(VERBOSE,['%s\n'],MSG) will be run; 
+%                 by default = []
+%
+% OUTPUT 
+%   U            [K -by- ?] untrained VARIMAXOM mapping
+%   W            [K -by- K_EXT] trained VARIMAXOM affine feature extraction mapping;
+%   K_EXT        the actual number of extracted features; can be less than K_TO_EXT 
+%   FRAC         [1 -by- K_EXT ] row of the varince fractions; FRAC(N) is variance fraction explained by first N PC's   
+%                FRAC corresponds to the PCA, which is the first step of VARIMAX, not to the final feature extraction, 
+%                except the FRAC(K_EXT) which is the total fraction of explained variance for both PCA and VARIMAX
+%   V            [1 -by- K_EXT ] row of variances of squared factors (sparsity)
+%   Z            [K -by- K_EXT] scores the result of mapping on training set
+%   Y            [K_EXT -by- K] loadings (generalized inverse of mapping W: if Z = A*W, 
+%                then A = Z*Y + error)            
+%   C            [N -by- K_EXT] dataset, result of mapping execution on dataset B
+%
+%
+%
+% DESRIPTION
+% This routine calculates what is called a raw Kaiser varimax. 
+% Applied to the transposed data matrix.
+%
+% It is conceptiually close to the SIMPLISMA and OPA mappings. 
+% It assumes that pure variables (concentration profiles) 
+% have sparse structure. The output of the algorithm are extracted features  
+% (linear combinations of original features). The letter F in
+% the name of routine means that it is expected that exctracted pure
+% features shows sparse behaviour for the training set objects.
+% Loadings (pure objects or spectra) can be obtained either directly 
+% or by Y = DATASET(W.DATA.ROT \ EYE(SIZE(W.DATA.ROT,1)))
+%
+% NOTE: PCA is done by low level routine not by PRTools PCA mapping.  
+% No mean centering, no calss information is used. Scaling or
+% any other type of preprocessing is the users responsibility.
+%
+% SEE ALSO
+% OPAM, SIMPLISMAM, VARIMAXOM, SIMPLIMAPS, OPAPS, ALS, VARIMAX 
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: varimaxfm.m,v 1.4 2007/01/31 21:52:19 serguei Exp $
+
+function [w, k_ext, frac, v, z, y] = varimaxfm(a, w, Opt)
+
+% No dataset given: return untrained mapping.
+if (nargin < 1) | (isempty(a))
+  if nargin < 2
+    w = 0.95;
+  end  
+  if nargin < 3
+    Opt = [];
+  end  
+  
+  w = mapping(mfilename,'untrained',{w});
+  w = setname(w,'VARIMAXFM Mapping');
+  return
+end
+
+isdataset(a);           % Assert that A is a dataset 
+
+% training
+if nargin < 2 | ~isa(w,'mapping') 
+  if nargin < 2 | isempty(w)
+    k_to_ext_or_frac_to_expl = 0.95;  
+  else  
+    k_to_ext_or_frac_to_expl = w;  
+  end  
+
+  if nargin < 3
+    Opt = [];  
+  end  
+  
+  [m,k] = getsize(a);
+  if k_to_ext_or_frac_to_expl >= m
+    error('number of components to extract should be less than the number of objects in a training dataset');
+  end  
+  
+  PCAOptions.M = 1;
+  if k_to_ext_or_frac_to_expl >= 1
+    PCAOptions.nPC = floor(k_to_ext_or_frac_to_expl);
+  else
+    PCAOptions.nPC    = nan;
+    PCAOptions.nPC_em = 'PEV';
+    PCAOptions.PEV    = k_to_ext_or_frac_to_expl;
+  end
+  
+  [T, P, lambda, Options]  = pca_train((+a)',PCAOptions); 
+  k_ext = length(lambda);
+  frac  = cumsum(lambda/Options.Tr1);
+
+  labin = a.featlab;
+  featsize = a.featsize;
+  a.data = zeros(m,1);
+
+  [P_max,v] = varimax(P,Opt);
+  
+  R = P'*P_max;
+  
+  % normalization factor for loadings (spectra will be l2 normalized)
+  h = sqrt(sum(repmat(lambda(:), [1 k_ext]).*(R.^2), 1));
+  
+  W = T * (repmat(1./lambda(:),[1 k_ext]).* R .* repmat(h,[k_ext 1]));
+  
+  
+  if nargout >= 5
+    % loadings
+    %y = (W\eye(k));
+    %W = (y'\eye(k))';
+    
+    y = dataset((repmat(1./h(:),[1 k_ext]).* R') *T');
+
+    y.featlab  = labin;
+    y.featsize = featsize;
+    y.user     = a.user;
+    y.name    = [y.name ': extracted spectra']; 
+  end
+
+  if nargout >= 6
+    % scores
+    % z = (+a)*W;
+    
+    z = a; clear a;
+    z.data = P_max .* repmat(h,[m 1]);
+    z.featlab = num2str([1:k_ext]','varivector%-1d');   
+    z = remove_spectra_info(z);
+    z.name    = [z.name ': extracted channels']; 
+  end
+
+  
+  % Save all useful data
+  w = affine(W,zeros(1,k_ext),labin,num2str([1:k_ext]','varivector%-1d'),size(W,1),size(W,2));
+  w = setname(w,'VARIMAXFM Mapping');
+
+% applying
+else 
+  % affine will do a job
+  w = a*w;
+  w = remove_spectra_info(w);
+  w.name = [w.name ': exctracted channels'];
+end
+
+return
+
Index: /hypertools/hypertools/varimaxom.m
===================================================================
--- /hypertools/hypertools/varimaxom.m	(revision 3)
+++ /hypertools/hypertools/varimaxom.m	(revision 3)
@@ -0,0 +1,167 @@
+%VARIMAXOM Extracts sparse (pure) objects and creates a feature extraction 
+%          mapping; features are extracted by the projection to the prototypes
+%          
+%  
+%  U = VARIMAXOM
+%  U = VARIMAXOM([], K_EXT, OPT)
+%  U = VARIMAXOM([], FRAC, OPT)
+%
+%  W = A*U
+%  [W, K_EXT, FRAC, V, Z, Y] = MAP(A, U)
+%  [W, K_EXT, FRAC, V, Z, Y] = VARIMAXOM(A)
+%  [W, K_EXT, FRAC, V, Z, Y] = VARIMAXOM(A, K_TO_EXT, OPT)
+%  [W, K_EXT, FRAC, V, Z, Y] = VARIMAXOM(A, FRAC_TO_EXP, OPT)
+%  Y = DATASET((W.DATA.ROT)')
+%
+%  C = B*W
+%  C = MAP(B, W)
+%  C = VARIMAXOM(B, W)
+%
+% INPUT 
+%   A             [M -by- K] training dataset
+%   B             [N -by- K] test dataset
+%
+%   U             [K -by- ?] untrained VARIMAXOM mapping
+%   W             [K -by- K_EXT] trained VARIMAXOM affine feature extraction mapping;
+%   K_TO_EXT, 
+%   FRAC_TO_EXP   
+%                 the (integer) number of components to be extracted (1<= K_TO_EXT < MIN(K,M)) or 
+%                 which fraction of variance to be explained (0 < FRAC_TO_EXP < 1) by PCA;
+%                 NOTE: the number of PCs taken into account should be smaller than number of 
+%                 original features/objects (otherwise the result of algorithm is trivial);
+%                 by default FRAC = 0.95
+%
+%   OPT.          optional VARIMAX settings 
+%    N_ATTEMPTS   the number of independent attempts to maximize the varimax criterion; by default = 3 
+%    MAX_ITER     the max number of iterations wihin each attempt; each iteration involves 
+%                 optimization over all unsorted pairs visited in random order; by default = 3 
+%    SORT         put the simplest factors first; by default = 1;
+%    EPS          convergence criterion (NEW_VAR-OLD_VAR < EPS*OLD_VAR); by default = 1e-6
+%    VERBOSE      force/disable messages; PRPROGRESS(VERBOSE,['%s\n'],MSG) will be run; 
+%                 by default = []
+%
+% OUTPUT 
+%   U            [K -by- ?] untrained VARIMAXOM mapping
+%   W            [K -by- K_EXT] trained VARIMAXOM affine feature extraction mapping;
+%   PROTO        extracted prototypes (transposed varivectors/loadings)
+%   K_EXT        the actual number of extracted features; can be less than K_TO_EXT 
+%   FRAC         [1 -by- K_EXT ] row of the varince fractions; FRAC(N) is variance fraction explained by first N PC's   
+%                FRAC corresponds to the PCA, which is the first step of VARIMAX, not to the final feature extraction, 
+%                except the FRAC(K_EXT) which is the total fraction of explained variance for both PCA and VARIMAX
+%   V            [1 -by- K_EXT ] row of variances of squared factors (sparsity)
+%   Z            [K -by- K_EXT] scores the result of mapping on training set
+%   Y            [K_EXT -by- K] loadings (generalized inverse of mapping W: if Z = A*W, 
+%                then A = Z*Y + error, W is orthonormal so generalized inverse is the transpose)            
+%   C            [N -by- K_EXT] dataset, result of mapping execution on dataset B
+%
+%
+% DESRIPTION
+% This routine calculates what is called a raw Kaiser varimax. 
+%
+% It is conceptiually close to the SIMPLISMA and OPA prototype selections
+% not to mappings. It assumes that pure objects (spectra) have sparse
+% structure. The output of the algorithm are extracted objects  (linear
+% combinations of original objects). Because of historical reasons it  is
+% implemented as a mapping. Extracted objects Y can be obtained directly or 
+% can extracted by Y=DATASET((W.DATA.ROT)'). The letter O in
+% the name of routine means that it is expected that exctracted pure
+% objects have sparse representation in original feature space.
+%
+% NOTE: PCA is done by low level routine not by PRTools PCA mapping.  
+% No mean centering, no calss information is used. Scaling or
+% any other type of preprocessing is the users responsibility.
+%
+% SEE ALSO
+% SIMPLIMAPS, OPAPS, VARIMAXFM, OPAM, SIMPLISMAM, ALS, VARIMAX 
+
+% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl 
+% Faculty EWI, Delft University of Technology
+% P.O. Box 5031, 2600 GA Delft, The Netherlands
+
+% $Id: varimaxom.m,v 1.4 2007/01/31 21:52:19 serguei Exp $
+
+function [w, k_ext, frac, v, z, y] = varimaxom(a, w, Opt)
+
+% No dataset given: return untrained mapping.
+if (nargin < 1) | (isempty(a))
+  if nargin < 2
+    w = 0.95;
+  end  
+  if nargin < 3
+    Opt = [];
+  end  
+  
+  w = mapping(mfilename,'untrained',{w});
+  w = setname(w,'VARIMAXOM Mapping');
+  return
+end
+
+isdataset(a);           % Assert that A is a dataset 
+
+% training
+if nargin < 2 | ~isa(w,'mapping') 
+  if nargin < 2 | isempty(w)
+    k_to_ext_or_frac_to_expl = 0.95;  
+  else  
+    k_to_ext_or_frac_to_expl = w;  
+  end  
+
+  if nargin < 3
+    Opt = [];  
+  end  
+  
+  [m,k] = getsize(a);
+  if k_to_ext_or_frac_to_expl >= k
+    error('number of components to extract should be less than the number of original features');
+  end  
+  
+  PCAOptions.M = 1;
+  if k_to_ext_or_frac_to_expl >= 1
+    PCAOptions.nPC = floor(k_to_ext_or_frac_to_expl);
+  else
+    PCAOptions.nPC    = nan;
+    PCAOptions.nPC_em = 'PEV';
+    PCAOptions.PEV = k_to_ext_or_frac_to_expl;
+  end
+  
+  [T, P, lambda, Options]  = pca_train(+a,PCAOptions); 
+  k_ext = length(lambda);
+  frac  = cumsum(lambda/Options.Tr1);
+  
+  labin    = a.featlab;
+  featsize = a.featsize;  
+  a.data = zeros(m,1);
+
+  [P_max,v] = varimax(P,Opt);
+  
+  if nargout >= 5
+    %loadings
+    y = dataset(P_max');
+    y.featlab = labin;
+    y.user    = a.user;
+    y.name    = [y.name ': extracted spectra']; 
+  end
+  
+  if nargout >= 6
+    %scores
+    z = a; clear a;
+    z.data = T*(P'*P_max);
+    z.featlab = num2str([1:k_ext]','varivector%-1d');
+    z = remove_spectra_info(z);
+    z.name    = [z.name ': extracted channels']; 
+  end
+
+  % Save all useful data
+  w = affine(P_max,zeros(1,k_ext),labin,num2str([1:k_ext]','varivector%-1d'),size(P_max,1),size(P_max,2));
+  w = setname(w,'VARIMAXOM Mapping');
+
+% applying
+else 
+  % affine will do a job
+  w = a*w;
+  w = remove_spectra_info(w);
+  w.name = [w.name ': exctracted channels'];
+end
+
+return
+
