function main_time(network_type,view, networks_idx, test_percent, valid_percent, Total_methods)
networks = {'amazon-product', 'export', 'aidorganizations_issues', 'congressmen_topics_US', 'drug_target_GPCR_2009', 'drug_target_HQ_2014', 'drug_target_enzyme_2009', 'drug_target_ionchannel_2009', 'industries_eductionfields_IPUMS', 'occupations_tasks_ONET', 'tfs_genes_regulation_ecoli', 'users_movies_movielens100k', 'drug_target_moesm4_esm'};

networks = networks(networks_idx);
% Total_methods = {'NSA_batch', 'JCF', 'SSCF'};
merge_funcs = {'normalization'};
CF_merge_funcs = {'normalization'};
measures = {'p','aup','aupr','auc','pbcorr', 'p_k', 'rec_k', 'ndcg_k'};
CHA_measures = {};
for i = 1:length(measures)
    CHA_measures = [CHA_measures ['CHA_' measures{i}] ];
end
measures = [measures CHA_measures];
allmeasures = {};
topks = [1, 5, 10, 20, 30, 40, 50];
for m2 = 1:length(measures)
    if endsWith(measures{m2}, '_k')
        for k = 1:length(topks)
            allmeasures = [allmeasures [measures{m2}(1:end-2) '_at_'  num2str(topks(k))]];
        end
    else
        allmeasures = [allmeasures measures{m2}];
    end
end
denominators = {'sum_of_nlcl'};
% denominators = {'sum_of_degree', 'sum_of_nlcl', 'union_of_neighbors'};
% alphas = linspace(0, 1, 11);
alphas = [0.5];
exps = [1];
processings = {'nothing'};
parameters = {'denominator', 'exp', 'processing', 'alpha', 'merge_func'};
CF_parameters = {'alpha'};
index_dic = containers.Map( ...
    {'NSA_val', 'NSA_batch', 'NSA3.1_val', 'NSA3.1_batch'}, ...
    {'CH3_L2', 'CH3_L2', 'CH3v5a_L2', 'CH3v5a_L2'});

for j = 1:1
    for i = 1:length(networks)
        load(['./' network_type '_dataset/' view '_based/' num2str(test_percent) '/matrices/' networks{i} '.mat'], 'xx')
        load(['./' network_type '_dataset/' view '_based/' num2str(test_percent) '/sparsified_matrices/' networks{i} '_train.mat'], 'matrices')
        x = xx{1};
        fprintf('%d/%d: %s (%dx%d) ... ', i, length(networks), networks{i}, size(x,1), size(x,2));
        for tm = 1:length(Total_methods)
            
            x = xx{j};
            adj = matrices{j};
            if (Total_methods{tm} == "SSCF") || (Total_methods{tm} == "JCF")
                root = [network_type '_result/' view '_based/' num2str(test_percent) '/' Total_methods{tm} '/' networks{i} '/' num2str(j) '/'];
                CF_batch(root, adj, x, Total_methods{tm}, CF_merge_funcs, alphas, topks, measures, CF_parameters);            
            elseif (Total_methods{tm} == "NSA_batch") || (Total_methods{tm} == "NSA3.1_batch")
                root = [network_type '_result/' view '_based/' num2str(test_percent) '/' Total_methods{tm} '/' networks{i} '/' num2str(j) '/'];
                NSA_batch(root, adj, x, denominators, exps, processings, merge_funcs, alphas, topks, measures, parameters, index_dic(Total_methods{tm}));
            end
        end
    end
end


function CF_batch(root, adj, x, method, merge_funcs, alphas, topks, measures, parameters)
[item_sim, user_sim] = compute_similarity(method, adj);
for merge_func = 1:length(merge_funcs)
    [item_one_mode, user_one_mode] = merge(merge_funcs{merge_func}, adj, item_sim, user_sim);
    for alpha = 1:length(alphas)
        out = [root 'alpha' num2str(alphas(alpha)) '.mat'];
        half_half = alphas(alpha) * item_one_mode + (1-alphas(alpha))*user_one_mode;
        value = evaluate(half_half, adj, x, topks, measures, out);
        this_parameter = containers.Map(parameters, {alphas(alpha)});
    end
end



function NSA_batch(root, adj, x, denominators, exps, processings, merge_funcs, alphas, topks, measures, parameters, index)
[item_C1, info] = CHA_linkpred_bipartite(adj', {index}, 0, 100);
[user_C1, info] = CHA_linkpred_bipartite(adj, {index}, 0, 100);
item_sim = item_C1;
user_sim = user_C1;
item_degree = sum(adj, 1);
user_degree = sum(adj, 2);
for denominator = 1:length(denominators)
    [item_dom, user_dom] = compute_NSA_dom(denominators{denominator}, adj, item_degree, user_degree);
    for exp = 1:length(exps)
        item_scaled_sim = item_sim ./ (item_dom .^ exps(exp));
        user_scaled_sim = user_sim ./ (user_dom .^ exps(exp));
        for processing = 1:length(processings)
            item_scaled_sim1 = add_op_func(item_scaled_sim, processings{processing});
            user_scaled_sim1 = add_op_func(user_scaled_sim, processings{processing});
            for merge_func = 1:length(merge_funcs)
                [item_one_mode, user_one_mode] = merge(merge_funcs{merge_func}, adj, item_scaled_sim1, user_scaled_sim1);
                for alpha = 1:length(alphas)
                    out = [root denominators{denominator} '_exp' num2str(exps(exp)) '_' processings{processing} '_alpha' num2str(alphas(alpha)) '_' merge_funcs{merge_func} '.mat'];
                    half_half = alphas(alpha) * item_one_mode + (1-alphas(alpha))*user_one_mode;
                    value = evaluate(half_half, adj, x, topks, measures, out);
                end
            end
        end
    end
end


function [item_sim, user_sim] = compute_similarity(method, adj)
if (method == "SSCF") || (method == "SSCF_val")
    [item_sim, user_sim] = SaplingSimilarity(adj);
elseif (method == "JCF") || (method == "JCF_val")
    [item_sim, user_sim] = JaccardSimilarity(adj);
end

function [item_sap, user_sap] = SaplingSimilarity(M)
N = size(M, 1);
k = sum(M, 1);
CO = M' * M;
B1 = (1-(CO.*(1-CO./k)+(k-CO')'.*(1-(k-CO')'./(N-k)))'./(k.*(1-k./N)))'.*sign(((CO.*N./k)'./k)' - 1);
B1(isnan(B1)) = 0;

N = size(M, 2);
k = sum(M, 2);
CO = M * M';
B2 = (1-(CO.*(1-CO./k)+(k-CO')'.*(1-(k-CO')'./(N-k)))'./(k.*(1-k./N)))'.*sign(((CO.*N./k)'./k)' - 1);
B2(isnan(B2)) = 0;

item_sap = B1;
user_sap = B2;

function [item_jac, user_jac] = JaccardSimilarity(adj)
item_degree = sum(adj, 1);
user_degree = sum(adj, 2);

item_I = adj' * adj;
item_U = item_degree' + item_degree - item_I;
item_jac = item_I ./ item_U;

user_I = adj * adj';
user_U = user_degree + user_degree' - user_I;
user_jac = user_I ./ user_U;

function [item_dom, user_dom] = compute_NSA_dom(denominator, adj, item_degree, user_degree)
if denominator == "sum_of_degree"
    item_dom = item_degree' + item_degree;
    user_dom = user_degree + user_degree';
elseif denominator == "sum_of_nlcl"
    item_nlcl = item_degree' + item_degree - adj' * adj * 2;
    user_nlcl = user_degree + user_degree' - adj * adj' * 2;
    item_dom = item_nlcl+1;
    user_dom = user_nlcl+1;
elseif denominator == "union_of_neighbors"
    item_U = item_degree' + item_degree - adj' * adj;
    user_U = user_degree + user_degree' - adj * adj';
    item_dom = item_U;
    user_dom = user_U;
end


function [item_sap_one_mode, user_sap_one_mode] = merge(merge_func, adj, item_sap, user_sap)
if merge_func == "sum"
    item_sap_one_mode = (item_sap * adj')';
    user_sap_one_mode = user_sap * adj; 
elseif merge_func == "normalization"
    item_degree = repmat(sum(abs(item_sap), 2), 1,size(adj', 2));
    temp = ones(size(item_degree));
    temp(item_degree == 0) = 0;
    item_degree(item_degree == 0) = 1;
    item_sap_one_mode = ((item_sap * adj') ./ item_degree .* temp)';

    user_degree = repmat(sum(abs(user_sap), 2), 1, size(adj, 2));
    temp = ones(size(user_degree));
    temp(user_degree == 0) = 0;
    user_degree(user_degree == 0) = 1;
    user_sap_one_mode = (user_sap * adj) ./ user_degree .* temp; 
elseif merge_func == "sub"
    item_degree = repmat(sum(abs(item_sap), 2), 1,size(adj', 2));
    temp = ones(size(item_degree));
    temp(item_degree == 0) = 0;
    item_degree(item_degree == 0) = 1;
    item_sap_one_mode = 1+((item_sap * (adj'-1)) ./ item_degree .* temp)';

    user_degree = repmat(sum(abs(user_sap), 2), 1, size(adj, 2));
    temp = ones(size(user_degree));
    temp(user_degree == 0) = 0;
    user_degree(user_degree == 0) = 1;
    user_sap_one_mode = 1+((user_sap * (adj-1)) ./ user_degree .* temp);
elseif merge_func == "mean"
    item_mono_adj = adj' * adj;
    item_mono_adj(item_mono_adj>0) = 1;
    item_degree = item_mono_adj * adj';
    temp = ones(size(item_degree));
    temp(item_degree == 0) = 0;
    item_degree(item_degree == 0) = 1;
    item_sap_one_mode = ((item_sap * adj') ./ item_degree .* temp)';
    
    user_mono_adj = adj * adj';
    user_mono_adj(user_mono_adj>0) = 1;
    user_degree = user_mono_adj * adj;
    temp = ones(size(user_degree));
    temp(user_degree == 0) = 0;
    user_degree(user_degree == 0) = 1;
    user_sap_one_mode = (user_sap * adj) ./ user_degree .* temp;
end

function half_half = add_op_func(half_half, method)
if strcmp(method, 'nothing')
    return
end
half_half = abs(half_half - min(half_half(:)) - max(half_half(:)));
G = graph(half_half);
half_half = distances(G);
if strcmp(method, 'euclidean')
    half_half = squareform(pdist(half_half, method));
    half_half = abs(half_half - min(half_half(:)) - max(half_half()));
elseif strcmp(method, 'pearson')
    half_half = (corrcoef(half_half) + 1) / 2;
end

function value = evaluate(half_half, adj, x, topks, measures, out)
[CHA_p_k, CHA_rec_k, CHA_ndcg_k] = prediction_evaluation_ks(half_half, adj, topks);
[CHA_p, CHA_aup, CHA_aupr, CHA_auc, CHA_pbcorr] = prediction_evaluation_20(full(half_half(:)), full(adj(:)));

half_half(adj==1)=0;
new_labels = x;
new_labels(adj==1) = 0;
[p_k, rec_k, ndcg_k] = prediction_evaluation_ks(half_half, new_labels, topks);

[row, col, value] = find(half_half);
labels = x(sub2ind(size(x),row,col));
[p, aup, aupr, auc, pbcorr] = prediction_evaluation_20(value, labels);
% save(out, measures{:});
value = containers.Map();
for m2 = 1:length(measures)
    if endsWith(measures{m2}, '_k')
        for k = 1:length(topks)
            eval(sprintf('value(''%s_at_%s'') = %s(%s);', measures{m2}(1:end-2), num2str(topks(k)), measures{m2}, num2str(k)));
        end
    else
        eval(sprintf('value(''%s'') = %s;', measures{m2}, measures{m2}));
    end
end

function [p_k, rec_k, ndcg_k] = prediction_evaluation_ks(half_half, new_labels, topks)
p_k = [];
rec_k = [];
ndcg_k = [];
for k = 1:length(topks)
    [p_k(k), rec_k(k), ndcg_k(k)] = prediction_evaluation_k(half_half, new_labels, topks(k));
end

function checkdir(out)
if ~exist(out, 'dir')
    mkdir(out);
end


function tunedparameter = find_tunedparameter(parameters, iters2, root, target_measure)
myparameter = cell(length(parameters), iters2);
for k = 1:iters2
    path = [root num2str(k) '/best.mat'];
    load(path, 'bestparameter');
    thisparameter = bestparameter(target_measure);
    for p = 1:length(parameters)
        myparameter{p, k} = thisparameter(parameters{p});
    end
end
tunedparameter = cell(length(parameters), 1);
for p = 1:length(parameters)
    row = myparameter(p, :);
    if (strcmp(parameters{p}, 'exp')) || (strcmp(parameters{p}, 'alpha'))
        tunedparameter{p} = mode(cell2mat(row));
    else
        [uniqueStrs, ~, idx] = unique(row);
        counts = histcounts(idx, 1:numel(uniqueStrs)+1);
        [~, maxIdx] = max(counts);
        tunedparameter{p} = uniqueStrs{maxIdx};
    end
end







            
            