function A = slkfd(K, nums, varargin)
%SLKFD Perform Kernelized Fisher Discriminant Analysis
%
% $ Syntax $
%   - A = slkfd(K, nums, ...)
%
% $ Arguments $
%   - K:        the kernel gram matrix of the training samples
%   - nums:     the numbers of samples in all classes
%   - A:        the projection coefficient matrix 
% 
% $ Description $
%   - A = slkfd(K, nums, ...) performs Kernerlized Fisher discriminant 
%     analysis on the samples X according to the specified properties. 
%     \*
%     \t   Table 1.  The properties of Fisher Discriminant Analysis   \\
%     \h     name     &     description                                \\
%           'sol'     &  The cell containing the arguments for solving
%                        the generalized eigen-problem by slsymgeig.  
%                        default = {}.                                 \\
%           'dimset'  &  The cell containing the arguments for determining
%                        the output feature dimension. default = {}.
%                        (refer to sldim_by_eigval).                   \\
%           'Sb'      &  The pre-computed kernelized between-class 
%                        scattering matrix or the cell containing 
%                        the arguments for computing the kernelized 
%                        scatter matrix in the form {type, ...}, 
%                        which is input to slkernelscatter.     \\
%           'Sw'      &  The pre-computed kernelized within-class 
%                        scattering matrix or the cell containing 
%                        the arguments for computing the scatter 
%                        matrix in the form {type, ...}, which is 
%                        input to slkernelscatter.     \\
%         'weights'   &  The sample weights. default = [].   \\
%     \*  
%
% $ History $
%   - Created by Dahua Lin on May 03, 2006
%

%% parse and verify input arguments

if nargin < 2
    raise_lackinput('slkfd', 2);
end

% for K
n = size(K, 1);
if ~isequal(size(K), [n, n])
    error('sltoolbox:invaliddims', ...
        'K should be a square matrix');
end

% for nums
nc = length(nums);
if ~isequal(size(nums), [1 nc])
    error('sltoolbox:sizmismatch', ...
        'nums should be a 1 x nc row vector');
end

% for options

opts.sol = {};
opts.dimset = {};
opts.Sb = {'Sb'};
opts.Sw = {'Sw'};
opts.weights = [];
opts = slparseprops(opts, varargin{:});

has_Sb = ~isempty(opts.Sb) && isnumeric(opts.Sb);
has_Sw = ~isempty(opts.Sw) && isnumeric(opts.Sw);
if has_Sb
    Sb = opts.Sb;
    if ~isequal(size(Sb), [n n])
        error('sltoolbox:sizmismatch', ...
            'Sb should be a n x n matrix');
    end
end
if has_Sw
    Sw = opts.Sw;
    if ~isequal(size(Sw), [n n])
        error('sltoolbox:sizmismatch', ...
            'Sw should be a n x n matrix');
    end
end

if ~isempty(opts.weights)
    w = opts.weights;
    if ~isequal(size(w), [1 n])
        error('sltoolbox:sizmismatch', ...
            'The weights should be a 1 x n row vector');
    end
else
    w = [];
end


%% Compute 

%% Step 1: Construct the eigen-problem

if ~has_Sb
    Sb = slscatter(K, opts.Sb{:}, 'sweights', w, 'nums', nums);
end

if ~has_Sw
    Sw = slscatter(K, opts.Sw{:}, 'sweights', w, 'nums', nums);
end


%% Step 2: Resolve the eigen-problem

[evs, A] = slsymgeig(Sb, Sw, opts.sol{:});

rk = sldim_by_eigval(evs, opts.dimset{:});
A = A(:, 1:rk);


