function [U, Uc] = slrangespace(tar, varargin)
%SLRANGESPACE Determines the subspace of the range of X
%
% $ Syntax $
%   - U = slrangespace(tar)
%   - U = slrangespace(tar, ...)
%   - [U, Uc] = slrangespace(...)
%
% $ Arguments $
%   - tar:      the target, can be a sample matrix or covariance
%   - U:        the basis for the range space
%   - Uc:       the basis for the orthogonal complement of the range
%
% $ Description $
%   - U = slrangespace(tar) determines the range space of tar in default 
%     settings. That is to set the dimension to be the rank of tar. Note
%     that tar can have two forms: a sample matrix or a covariance
%     given by the syntax {'cov', C}.
%
%   - U = slrangespace(tar, ...) determines the range space of X using
%     the specified dimension determination schemes. The arguments 
%     input following X will be delivered to sldim_by_eigval for dimension
%     determination.
%
%   - [U, Uc] = slrangespace(...) also returns orthogonal complement of U.
%
% $ History $
%   - Created by Dahua Lin on Apr 25, 2005
%

%% parse and verify input arguments

if isnumeric(tar)   
    target_type = 1;        % target is sample
    
    if ndims(tar) ~= 2
        error('sltoolbox:invalidarg', ...
            'When tar is sample matrix, it should be a 2D matrix');
    end
    
    X = tar;
    d = size(X, 1);
    
elseif iscell(tar)
    
    if length(tar) == 2 && ischar(tar{1}) ...
            && strcmpi(tar{1}, 'cov')
        
        target_type = 2;        % target is covariance
        
        C = tar{2};
        d = size(C, 1);
        
        if ~isequal(size(C), [d d])
            error('sltoolbox:invalidarg', ...
                'A covariance matrix should be square');
        end
        
    else        
        error('sltoolbox:invalidarg', ...
            'The target should be a sample matrix or a covariance given by cell');        
    end
    
else
    
    error('sltoolbox:invalidarg', ...
        'The target should be a sample matrix or a covariance given by cell');        
end

if nargout == 0
    return;
elseif nargout == 1
    need_complement = false;
else
    need_complement = true;
end
    

%% compute

switch target_type
    
    case 1      % sample matrix     
        
        if ~need_complement
            [U, D] = svd(X, 0);
        else
            [U, D] = svd(X);
        end
        
        evals = diag(D) .^ 2;
        clear D;
                                        
    case 2      % covariance
        
        [evals, U] = slsymeig(C);
        
end
    
evals = max(evals, 0);
k = sldim_by_eigval(evals, varargin{:});

%% output

if ~need_complement
    U = U(:, 1:k);
else
    if k == size(U, 2)
        Uc = zeros(d, 0);
    else
        Uc = U(:, k+1:end);
        U  = U(:, 1:k);
    end
end

