/*
 *
 */

#include <networkit/community/AdjustedRandMeasure.hpp>
#include <networkit/community/PartitionIntersection.hpp>


double NetworKit::AdjustedRandMeasure::getDissimilarity(const NetworKit::Graph &G, const NetworKit::Partition &zeta, const NetworKit::Partition &eta) {
    Partition intersection = PartitionIntersection().calculate(zeta, eta);

    std::vector<count> size_zeta(zeta.upperBound(), 0);
    std::vector<count> size_eta(eta.upperBound(), 0);
    std::vector<count> size_intersection(intersection.upperBound(), 0);

    // precompute sizes for each cluster
    G.forNodes([&](node u){
        index C = zeta[u];
        index D = eta[u];
        index I = intersection[u];
        assert (C != none);
        assert (D != none);
        assert (I != none);
        size_zeta[C] += 1;
        size_eta[D] += 1;
        size_intersection[I] += 1;
    });


    count randIndex = 0;
    for (count s : size_intersection) {
        randIndex += s * (s - 1) / 2;
    }

    count sumZeta = 0;
    for (count s : size_zeta) {
        sumZeta += s * (s - 1) / 2;
    }

    count sumEta = 0;
    for (count s : size_eta) {
        sumEta += s * (s - 1) / 2;
    }

    count n = G.numberOfNodes();

    double maxIndex = 0.5 * (sumZeta + sumEta);

    double expectedIndex = sumZeta * sumEta / (n * (n-1) / 2);

    if (maxIndex == 0) { // both clusterings are singleton clusterings
        return 0.0;
    } else if (maxIndex == expectedIndex) { // both partitions contain one cluster the whole graph
        return 0.0;
    } else {
        return 1.0 - (randIndex - expectedIndex) / (maxIndex - expectedIndex);
    }
}
