function [r] = GR( X, Q, varargin )
%GDL(Rank) Main algorithm, rank data using Geodesic Distance Learning 
%
%
% Input:
%  - X: m-by-n matrix, each column is a sample
%  - Q: Query, an index number
%
% Optional Input:
%  - mode: the mode of visualization, default is 5, options are below:
%      1: draw the ranking results in a heat map
%      2: draw the normalized vector field
%      3: draw the unnormalized vector field
%      4: draw the initial vector field
%      5: draw all of the four figures
%      else: draw nothing
%  - W: the weight graph, an n-by-n (sparse) matrix, default is none
%  - k: the number of K-Nearest Neighbor, default is 8
%  - d: the dimension of embedded data manifold in assumption, default is 2
%  - nb: the number of nearest neighbors of the query to estimate the
%        vector field, default is 8
%  - lambda1: the first parameter t in the main algorithm, default is 1
%  - lambda2: the second paramter c in the mian algorithm, default is 1
%          
% Output:
%  - r: a struct including the ranking function and vector field
%      -f: the ranking function
%      -v: the unnormalized vector field
%      -nv: the normalized vector field
%      -v0: the initial vector field
%      -time: the CPU time used in all computing
%
% Examples:
%   fea = rand(500,3);
%   Q = 10;
%   r = GR(fea,Q);

time=cputime;
ip = inputParser;
ip.FunctionName = 'GR';
ip.addRequired('X', @ismatrix);
ip.addRequired('Q', @ismatrix);

ip.addOptional('mode', 5, @isnumeric);
ip.addOptional('W', [], @ismatrix);
ip.addOptional('k', 8, @isnumeric);
ip.addOptional('d', 2, @isnumeric);
ip.addOptional('nb', 500, @isnumeric);%8
ip.addOptional('lambda1', 1, @isnumeric);
ip.addOptional('lambda2', 1, @isnumeric);
ip.parse(X, Q, varargin{:});
par = ip.Results;
mode = par.mode;
W = par.W;
k = par.k;
d = par.d;
nb = par.nb;
lambda1 = par.lambda1;
lambda2 = par.lambda2;

S = size(X);
n = S(1);
Y = zeros(size(X,1),1);
Y(Q) = 1;
Label = [];
Label.y = Y;
Label.mask = false(size(X, 1),1);
Label.mask(Q) = true;
if isempty(W)
    W=constructW(X, struct('k', k, 'bSelfConnected', false));
end
mats = gdl_MakeMats(X', d, W, Y, 'use_parfor', false, 'nb', nb);
r=[];
r.v = gdl_first_v(mats, d, lambda1);
r.v = reshape(r.v, d, n);
r.nv = gdl_second_nv(r.v, Q);
r.f = -gdl_third_f(mats, Label, r.nv, lambda2);
r.v0=reshape(mats.V0,d,S(1));
gdl_draw(X,Q,mats,r,mode);
r.time=cputime-time;
end

