function [vGraph, vEigenVecs, vEigenVals, vLaplacian, vNNInfo] = 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'
%       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
%       kNN            : number of nn to consider in all computations
%       WhichEigenVals : 'small' or 'large'
%       MaxEigenVals   : Maximum number of eigenvalues to keep
%       Delta          : Scaling parameter if 'gauss' type is used (kernel type is e^{-(\frac{||x-y||}{Delta})^2})
%       Precision      : Desired precision
%       EigEnergyThres : fraction of energy of the first MaxEigenValues to preserve, it's a number i (0,1]
%       NNsymm         : how to symmetrize the weight matrix if cType=='nn'
%                             'ave' for 1/2(W+W*)
%                             'leftadj' for W*W
%                             'rightadj' for WW*
%   cF              : function whose gradient affects the weights
%
% OUT:
%   vGraph      : structure: vGraph.D are the degrees of vSamples,
%                            vGraph.W is the distance matrix
%   vEigenVecs : M by cNumberOfEigenValues 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)]
%

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

% Build the graph
lGraphOpts.kNN = cOpts.kNN;
lGraphOpts.NNsymm = cOpts.NNsymm;
lGraphOpts.Delta = cOpts.Delta;
lGraphOpts.Precision = cOpts.Precision;
[vGraph,vNNInfo] = FastGraphFromData(cX,lGraphOpts,cOpts.Type,cF);
% Compute the Laplace eigenfunctions
[vEigenVecs, vEigenVals,vLaplacian] = FastLaplacianEigs( cOpts, vGraph.D, vGraph.W, lMaxEigs, 1e-15 );
if cOpts.EigEnergyThres < 1
    % Keep enough eigenvectors to satisfy the specified threshold    
    lEnergyTotal = sum((1-vEigenVals).^2);
    lEnergySoFar = 0;
    lOk = 0; % False
    for lk = 1:lMaxEigs
        lEnergySoFar = lEnergySoFar + (1-vEigenVals(lk))^2;
        if lk >= 3
            if lEnergySoFar/lEnergyTotal >= cOpts.EigEnergyThres
                lOk = 1; % True
                break;
            end;
        end;
    end;
    % Make sure threshold is met
    if lOk == 0,
        fprintf('Warning -- LaplacianDetEigs: Energy of %d eigenvectors < %d (threshold)\n', lk, cOpts.EigEnergyThres);
    end;
else
    lk = lMaxEigs;
end;

% Return the results
vEigenVecs = vEigenVecs(1:lk,:)';
vEigenVals = vEigenVals(1:lk);

return;