function xy = Isomap(D,ndims,options);
% isomap - computes Isomap embedding using the algorithm of
% Tenenbaum, de Silva, and Langford (2000).
%
% xy = isomap(X,ndims,options);
% or
% xy = isomap(D,ndims,options);
%
% 'X' is a D x N matrix (D = dimensionality, N = #points)
% 'D' is either a local distance matrix (with Inf when no connection),
% or a global one (i.e. it contains already computed geodesic
% distances between pair of points).
% OPTIONAL:
% 'ndims' is the number of output dimensions (default =2).
% 'options.distance_mode' is either 'local' (set if D is a local distance matrix)
% or 'global' (set if D is a geodesic distance).
% 'options.nn_epsilon' : set it if you want to compute the nearest
% neighbor by thresholding.
% 'options.nn_nbr' : set it if you want to compute the nearest
% neighbor by using a fixed number of neighbors.
%
% Modified by Gabriel Peyr?? from the original code :
%
% BEGIN COPYRIGHT NOTICE
%
% Isomap code -- (c) 1998-2000 Josh Tenenbaum
%
% This code is provided as is, with no guarantees except that
% bugs are almost surely present. Published reports of research
% using this code (or a modified version) should cite the
% article that describes the algorithm:
%
% J. B. Tenenbaum, V. de Silva, J. C. Langford (2000). A global
% geometric framework for nonlinear dimensionality reduction.
% Science 290 (5500): 2319-2323, 22 December 2000.
%
% Comments and bug reports are welcome. Email to jbt@psych.stanford.edu.
% I would also appreciate hearing about how you used this code,
% improvements that you have made to it, or translations into other
% languages.
%
% You are free to modify, extend or distribute this code, as long
% as this copyright notice is included whole and unchanged.
%
% END COPYRIGHT NOTICE
options.null = 0;
if nargin<2
ndims = 2;
end
if isfield(options, 'distance_mode')
distance_mode = 'local';
else
if ~isempty(find(isinf(D)));
distance_mode = 'local';
else
distance_mode = 'global';
end
end
if isfield(options, 'verb')
verb = options.verb;
else
verb = 1;
end
use_landmarks = 0;
points_list = 1:size(D,2);
if isfield(options, 'landmarks')
use_landmarks = 1;
landmarks = options.landmarks;
nbr_landmarks = length(landmarks);
points_list = landmarks;
end
if size(D,1)~=size(D,2)
X = D;
% D is the location of point in space, compute the distance matrix
% using some NN-graph
D = compute_nn_graph(X,options);
distance_mode = 'local';
end
N = size(D,1);
if strcmp(distance_mode, 'local')
%%%%% Compute shortest paths %%%%%
if verb
disp('- computing shortest paths');
end
% D = floyd(D);
Ws = D;
Ws(Ws==Inf) = 0;
Ws = sparse(Ws);
% compute the distance between point_list and the remaining points
D = compute_distance_graph(Ws, points_list);
if use_landmarks
Dfull = D;
D = D(:,landmarks);
Nfull = N;
N = nbr_landmarks;
end
end
if sum(D==Inf)>0
warning('Distance matrix contains Inf value (non-connected graph)');
D(D==Inf) = max(D(not(D==Inf)))*2;
end
%%%%% Construct low-dimensional embeddings (Classical MDS) %%%%%
if verb
disp('- constructing low-dimensional embeddings.');
end
opt.disp = 0; opt.isreal = 1; opt.issym = 1;
M = -.5*(D.^2 - sum(D.^2)'*ones(1,N)/N - ones(N,1)*sum(D.^2)/N + sum(sum(D.^2))/(N^2));
[xy, val] = eigs(M, ndims, 'LR', opt);
for i=1:ndims
xy(:,i) = xy(:,i)*sqrt(val(i,i));
end
if use_landmarks
% interpolation on the full set of points
% x = 1/2 * (L^T) * ( delta_n-delta_x )
xy1 = zeros(Nfull,ndims);
% transpose of embedding
LT = xy';
for i=1:ndims
LT(i,:) = LT(i,:) / val(i,i);
end
deltan = mean(D,2);
for x=1:Nfull
deltax = Dfull(:,x);
xy1(x,:) = 1/2 * ( LT * ( deltan-deltax ) )';
end
xy = xy1;
end