function [vGraph, vEigenVecs, vEigenVals, vLaplacian, vNNInfo, vDiffusion] = FastLaplacianDetEigs( cX, cOpts, cF );

%
% function [vGraph, vEigenVecs, vEigenVals,vLaplacian, vNNInfo] = FastLaplacianDetEigs( cX, cOpts, cF );
%
% IN:
%   cX              : M by N matrix of M points in R^N
%   cOpts:          : structure containing the following fields:
%       Type           : 'nn' or 'gauss'
%       if Type == 'nn':
%                   kNN     : number of nearest neighbors if cType=='nn'
%                   Delta         : width of gaussian, if Delta == Inf, then uses 1 for all edge weights
%       if Type == 'gauss'
%                   Delta         : width of gaussian if cType=='gauss'
%                   Precision     : determines the range_search radius when cType=='gauss'
%       Epsilon   : no diffusion outside any local metric ball of radius Epsilon (used only by flexible metrics)
%       NormalizationType :  'graph':   D^{-1/2}(D-W)D^{-1/2}
%                            'graphmarkov' : D^{-1/2}(D-W)D^{-1/2} but the returned eigenvectors are rescaled by D^{-1/2}, so they are the same as 'ave'
%                            'beltrami' : It's like 'graph' applied to the kernel obtained after initial density normalization by D^{-1}
%                            'ave':     D^{-1}(D-W)
%                            'noave':   D-W
%                            'none':    W
%       WhichEigenVals : 'small' or 'large'
%       MaxEigenVals   : Maximum number of eigenvalues to keep
%       EigEnergyThres : fraction of energy of the first MaxEigenValues to preserve, it's a number \in (0,1]
%       NNsymm  : how to symmetrize the weight matrix (empty otherwise)
%                   'ave' for 1/2(W+W*)
%                   'leftadj' for W*W
%                   'rightadj' for WW*
%        GetWeightsFcn : pointer to function to compute weights, as in GetWeightsFcn_Template.m
%   cF              : function whose gradient affects the weights
%
% OUT:
%   vGraph      : structure: vGraph.D are the degrees of vSamples,
%                            vGraph.W is the distance matrix
%   vEigenVecs : cNumberOfEigenValues by M matrix of eigenvectors
%   vEigenVals : cNumberOfEigenValues vector
%   vLaplacian : sparse matrix representing the laplacian
%
% USES:
%   FastGraphFromData, FastLaplacianEigs
%
% SOURCE CONTROL
%   MM : 03/13/04           [changed slightly interface, because of changes in FastGraphData (integrated with range searches)]
%   MM : 05/31/04           [changed a few things in the parameters, to adjust for changes to FastGraphFromData]
%   MM : 06/07/04           [small changes]
%

% Parameter: Maximum number of eigenvalues to keep
lMaxEigs = min(cOpts.MaxEigenVals, size(cX,1));

% Build the graph
[vGraph,vNNInfo] = FastGraphFromData(cX,cOpts,cOpts.Type,cF);
% Compute the Laplace eigenfunctions
[vEigenVecs, vEigenVals,vLaplacian,vDiffusion] = FastLaplacianEigs( cOpts, vGraph.D, vGraph.W, lMaxEigs, 1e-15 );
if isfield(cOpts,'EigEnergyThres')
    if cOpts.EigEnergyThres < 1
        % Keep enough eigenvectors to satisfy the specified threshold    
        lEnergyTotal = norm(vEigenVals);
        lEnergySoFar = 0;
        for lk = 1:lMaxEigs
            lEnergySoFar = lEnergySoFar + (vEigenVals(lk)^2);
            if lEnergySoFar/lEnergyTotal >= cOpts.EigEnergyThres
                break;
            end;
        end;
        % Return the results
        vEigenVecs = vEigenVecs(:,1:lk);
        vEigenVals = vEigenVals(1:lk);
    end;
end;


return;