function [scores, methods] = CH_scores(x, par)

%%% INPUT %%%
% x - Adjacency matrix of the network (unweighted, undirected and zero-diagonal).
%
% par - 1 or 0 to indicate if the function should use parallel computation or not;
%   if empty or not given, par = 1.
%
%%% OUTPUT %%%
% scores - 3D matrix, the first two dimensions represent the matrix of scores for each CH model,
%   the third dimension indicates the different CH models.
%   Higher scores suggest higher likelihood of connection between the node pairs.
%
% methods - Names of the CH models, ordered according to the third dimension of the scores output

% MEX support function:
% The "CHA" Matlab function requires the MEX function "find_paths_node_mex".
% Please compile the C source file "find_paths_node_mex.c" using the Matlab command
% mex find_paths_node_mex.c
% It will generate a MEX file with platform-dependent extension,
% .mexw64 for Windows, .mexa64 for Linux, .mexmaci64 for Apple Mac.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% check input
narginchk(1,2)
validateattributes(x, {'numeric'}, {'square','binary'});
x = sparse(x);
if ~issymmetric(x)
    error('The input matrix must be symmetric.')
end
if any(x(speye(size(x))==1))
    error('The input matrix must be zero-diagonal.')
end
if ~exist('par', 'var') || isempty(par)
    par = Inf;
else
    validateattributes(par, {'numeric'}, {'scalar','integer','>=',0,'<=',1});
    if par == 1
        par = Inf;
    end
end

% initialization
L = [2,3];
models = {'RA','CH1','CH2','CH3'};
methods = cell(length(L)*length(models),1);
for i = 1:length(L)
    for j = 1:length(models)
        methods{(i-1)*length(models)+j} = [models{j} '_L' num2str(L(i))];
    end
end
N = length(x);
M = length(methods);
scores = zeros(N,N,M);
deg = full(sum(x,1));
[~,order] = sort(deg);
order(order) = 1:N;

% compute CH scores
parfor (s = 1:N, par)
    scores(s,:,:) = compute_scores_node(x, s, L, models, deg, order, N, M);
end
for m = 1:M
    scores(:,:,m) = max(scores(:,:,m),scores(:,:,m)');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function scores = compute_scores_node(x, s, L, models, deg, order, N, M)

paths_cell = find_paths_node_mex(x, s, L(end), order);

scores = zeros(N,M);
for i = 1:length(L)
    for n = 1:N
        l = L(i)-1;
        if ~isempty(paths_cell{l,n})
            paths = paths_cell{l,n};
            paths_size = size(paths);
            paths = reshape(paths, 1, numel(paths));
            [cn,~,idx] = unique(paths);
            d = deg(paths);
            di = full(sum(x(cn,cn),1));
            di = di(idx);
            de = d - di - full(x(s,paths)) - full(x(n,paths));
            d = reshape(d, paths_size);
            di = reshape(di, paths_size);
            de = reshape(de, paths_size);
            
            for j = 1:length(models)
                m = (i-1)*length(models)+j;
                switch models{j}
                    case 'RA'
                        scores(n,m) = sum(1./geomean(d,1),2);
                    case 'CH1'
                        scores(n,m) = sum(geomean(di,1)./geomean(d,1),2);
                    case 'CH2'
                        scores(n,m) = sum(geomean(1+di,1)./geomean(1+de,1),2);
                    case 'CH3'
                        scores(n,m) = sum(1./geomean(1+de,1),2);
                end
            end
        end
    end
end
