function [outPerf, outYc_pred, outYa_pred, outFMat, outThres_using, outLearnedMat] = ...
    PRW_Tri_Driver(inX, inYc, inYa, inTr_idx, inTe_idx, inPara, inYc_init, inYa_init)

% input:
% inX:  n by d
% inYc: n by k
% inYa: n by l
% inTr_idx:
% inTe_idx:
% inPara:
%       inPara.k    : KNN graph
%       inPara.alpha: parameter for label correlation.
%       inPara.gamma: probability for random walk restart
%       inPara.lamda: probability for (a,c) layers jumping
%       inPara.beta1: probability for (x,c) layers junmping
%       inPara.beta2: probability for (x,a) layers junmping
%       inPara.eta: parameter for p0 init
% inYc_init: the initialization for Yc_te : n_te x k
% inYa_init: the initialization for Ya_te : n_te x l
%
% output:
%       outYc_pred: the pred matrix for stage class
%       outYa_pred: the pred matrix for annotation
%       outFMat:    the learned matrix after PRW
%       outThresh_using: the thresholds for annotation got by adaptive
%                        thresholding function
%       outLearnedMat: the sub matrice for the learned matrix to record the
%                      c-c, c-a, a-c, a-a relationships
%       outPerf:
%               outPerf.stat_info_a: annotation
%               outPerf.stat_a: annotation
%               outPerf.class_stat_a: annotation
%               outPerf.confusionMat: the classification confusion matrix
%               outPerf.accuacy_c: the classification ACC
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% check the input
if ((size(inX, 1) ~= size(inYc, 1)) || (size(inYc, 2) == 1))
    error('The size of the input X and Yc are not compatible!');
else
    [n, d] = size(inX);
    [n, k] = size(inYc);
end
if ((size(inX, 1) ~= size(inYa, 1)) || (size(inYa, 2) == 1))
    error('The size of the input X and Ya are not compatible!');
else
    [n, l] = size(inYa);
end
% using the input inYc_init and inYa_init to do the initialization for 
% the unlabeled ones (testing data)
X_tr = inX(inTr_idx, :);
X_te = inX(inTe_idx, :);
Yc_tr = inYc(inTr_idx, :);
Yc_te = inYc_init;
Yc_gt = inYc(inTe_idx, :);
Ya_tr = inYa(inTr_idx, :);
Ya_te = inYa_init;
Ya_gt = inYa(inTe_idx, :);
% re-arrange the data, the stage label and the annotation. 
% Put the labeled on the top and unlabeled at the bottom.
X = [X_tr; X_te];
Yc = [Yc_tr; Yc_te];
Ya = [Ya_tr; Ya_te];
Y = [Yc, Ya];
num_tr = length(inTr_idx);
tr_idx = 1: num_tr;
te_idx = (num_tr + 1) : n;
% PRW on Tri-Relationship graph
[M, H, outFMat] = PRW_Tri(X, Yc, Ya, num_tr, inPara);
% adaptive thresh for the annotation
outThres_using = zeros(1, size(Ya, 2));
for ii = (size(Yc,2) +1) : size(Y, 2)
    disp(ii-size(Yc, 2))
    outThres_using(ii-size(Yc, 2)) = f_cal_thres_best_f1(outFMat(tr_idx, ii), Y(tr_idx, ii));
end
% get the sub matrices
f_matrix_xc = outFMat(1:n, 1:k);
f_matrix_xa = outFMat(1:n, (k+1):end);
outLearnedMat.f_matrix_cc = outFMat((n+1):(n+k),1:k);
outLearnedMat.f_matrix_ca = outFMat((n+1):(n+k),(k+1):end); 
outLearnedMat.f_matrix_ac = outFMat((n+k+1):end, 1:k);
outLearnedMat.f_matrix_aa = outFMat((n+k+1):end, (k+1):end);
% use the max as the label for stage class
f_matrix_xc_test = f_matrix_xc(te_idx, :);
outYc_pred = zeros(length(te_idx), k);
[max_val, ind] = max(f_matrix_xc_test,[],2);
for i = 1: length(te_idx)
    j = ind(i);
    outYc_pred(i,j) = 1;
end

% use the ones above the adaptive threshold as the labels for annotation
outYa_pred = zeros(length(te_idx), l);
f_matrix_xa = f_matrix_xa - repmat(outThres_using, n, 1);
f_matrix_xa_test = f_matrix_xa(te_idx, :);
outYa_pred = double(f_matrix_xa_test > 0);
% evaluate the prediction
[stat_info_a, stat_a, class_stat_a] = f_cal_stat_info(Ya_gt, outYa_pred);
[confusionMat, accuacy_c] = compute_confusion_matrix(mapMat2Vec(Yc_gt), mapMat2Vec(outYc_pred), 1);
outPerf.stat_info_a = stat_info_a;
outPerf.stat_a = stat_a;
outPerf.class_stat_a = class_stat_a;
outPerf.confusionMat = confusionMat;
outPerf.accuacy_c = accuacy_c;
   


end





