function [ncut, ncut_bases, ncut_init, meta_init] = func_meta_init(data, dname)
%%% Clustering_by_co_init.: implementing three initializations, i.e.,
%%% simple_init (using NCUT), heter_init, and heter_co_init
%%% He Zhang, Feb. 2013

warning('off');

%% involved methods
methods = {...
    'KernelPNMFeu', ...
    'NonnegativeSpectralClustering', ...
    'SymTriOrthNMF', ...
    'lsd', ...
    'SymPLSA', ...
    'dcd_1', ...
    'dcd_1.2', ...
    'dcd_2', ...
    'dcd_5', ...
    'OneSpectralClustering'
    };
nm = length(methods);% 10 methods

verbose = false;
nSeed = 0;
max_iter = 10000;
check_step = 10001;
rounds = 5;

ncut = cell(1, 3);
ncut_bases = cell(1, 12);
ncut_init = cell(1, 4);
meta_init = cell(1, 5);

%% load graph data
graph = sparse(data.A); graph = double(graph+graph'>0);
A = graph;  A(logical(eye(size(A, 1)))) = 0;
label = data.C; k = length(unique(label));

%% simple_init by NCUT
fprintf('\n  running simple_init ... \n');
% initialization by ncut
W0 = ncutW(A, k); W0 = W0+0.2;
W0 = bsxfun(@rdivide, W0, sum(W0,1));
[~, testLabel] = max(W0, [], 2);
ncut_bases{1, 2} = testLabel; % adding the NCUT base
purity = compute_purity_entropy(label, testLabel);
nmi = compute_nmi(label, testLabel);
ncut{1, 1} = dname;
ncut{1, 2} = purity; 
ncut{1, 3} = nmi;
% looping in each method
nm = length(methods);
Ws_init = cell(1, nm);
ncut_init{1, 1} = dname;
for mi = 1:nm
    method = methods{mi};
    %fprintf('\nNow ncut_init in : %s(size=%g)\n', method, size(A, 1));
    if strcmp(method, 'OneSpectralClustering') % Note: 1-SPEC is not affected by initializations.
        W = OneSpectralClustering(A, 'rcc', k, 0, 0, 0);
        W = W(:, end);
        testLabel = W;
    else
        [W, obj] = func_meta_clustering(method, A, k, max_iter, check_step, verbose, nSeed, W0);
        [~, testLabel] = max(W, [], 2);
    end
    purity = compute_purity_entropy(label, testLabel);
    nmi = compute_nmi(label, testLabel);
    % save ncut_init
    ncut_init{1, 2} = [ncut_init{1, 2}, purity];
    ncut_init{1, 3} = [ncut_init{1, 3}, nmi];
    ncut_init{1, 4} = [ncut_init{1, 4}, obj];
    Ws_init{mi} = W;
    ncut_bases{1, 2+mi} = testLabel;
end
ncut_bases = cell2mat(ncut_bases(1, 2:end));

%% heter_init, and heter_co_init init with rounds = 5
% Note: heter_init is equal to heter_co_init with rounds = 1
methods2 = methods(1:end-1); % remove the OneSpectralClustering method
nm = length(methods2); % 9 methods now
meta_init{1, 1} = dname;
Ws = cell(1, nm); objs = zeros(rounds, nm); init_ms = cell(rounds, nm);
purities = zeros(rounds, nm); nmis = zeros(rounds, nm);
% loop several rounds
for rs = 1:rounds
    if rs == 1
        fprintf('\n  running heter_init ... \n');
    else
        fprintf('\n  running heter_co_init with round = %g ... \n', rs);
    end
    
    for mi_cur = 1:nm
        %fprintf('\nCurrent: %s\n\n', methods2{mi_cur});
        if rs == 1
            cur_W = Ws_init(1:end-1);
        else
            cur_W = Ws;
        end
        W_tmp = cell(1, nm); obj_tmp = zeros(1, nm);
        p_tmp = zeros(1, nm); nmi_tmp = zeros(1, nm);
        % loop in each of the other methods
        for mi_oth = 1:length(methods2)
            %fprintf('  now in: %s ', methods{mi_oth});
            [W, obj] = func_meta_clustering(methods2{mi_cur}, A, k, ...
                max_iter, check_step, verbose, nSeed, cur_W{mi_oth}+0.2);
            [~, testLabel] = max(W, [], 2);
            purity = compute_purity_entropy(label, testLabel);
            nmi = compute_nmi(label, testLabel);
            W_tmp{mi_oth} = W; obj_tmp(mi_oth) = obj;
            p_tmp(mi_oth) = purity; nmi_tmp(mi_oth) = nmi;
        end
        % update W according to minimun obj
        [val, indx] = min(obj_tmp);
        Ws{mi_cur} = W_tmp{indx(1)};
        objs(rs, mi_cur) = obj_tmp(indx(1));
        purities(rs, mi_cur) = p_tmp(indx(1));
        nmis(rs, mi_cur) = nmi_tmp(indx(1));
        init_ms{rs, mi_cur} = methods2{indx(1)};
    end
end
% save meta_init
meta_init{1, 2} = purities;
meta_init{1, 3} = nmis;
meta_init{1, 4} = objs;
meta_init{1, 5} = init_ms; % use init_ms to check which method initializes at each round
