def test_directed_consistency_igraph_famous(self):
        """Test gamma estimate consistency on undirected and (symmetric) directed versions of various famous graphs."""

        for G in generate_igraph_famous():
            random_membership = generate_random_partition(G.vcount(), 5)

            gamma_undirected = gamma_estimate(G, random_membership)
            G.to_directed()
            gamma_directed = gamma_estimate(G, random_membership)

            self.assertAlmostEqual(gamma_undirected, gamma_directed, places=10)
Exemple #2
0
def run_method(G,
               ground_truth_communities,
               num_louvain_runs,
               method,
               gamma_sweep_min=0.5,
               gamma_sweep_max=2.0):
    """
    Run one trial of comparing our benchmark to typical Louvain strategies

    :param G: graph of interest
    :param ground_truth_communities: ground truth community vector
    :param method: "modularity pruning", "modularity pruning ground truth K", "gamma sweep" or "ground truth gamma"
    :return: list of NMIs compared to the ground truth communities
    """
    ground_truth_gamma = gamma_estimate(G, ground_truth_communities)

    if ground_truth_gamma > gamma_sweep_max:
        print(f"Ground truth gamma {ground_truth_gamma:.2f} is large")

    if ground_truth_gamma is None:
        raise ValueError(
            "Cannot use a graph with degenerate ground truth communities")

    if method == "modularity pruning" or method == "modularity pruning ground truth K" or method == "gamma sweep":
        gammas = np.linspace(gamma_sweep_min, gamma_sweep_max,
                             num_louvain_runs)
    elif method == "ground truth gamma":
        gammas = np.linspace(ground_truth_gamma, ground_truth_gamma,
                             num_louvain_runs)
    else:
        raise ValueError(f"Option {method} is not valid")

    parts = repeated_louvain_from_gammas(G, gammas)

    if method == "modularity pruning":
        stable_parts = prune_to_stable_partitions(G,
                                                  parts,
                                                  gamma_start=gammas[0],
                                                  gamma_end=gammas[-1],
                                                  single_threaded=True)
        nmis = [nmi(ground_truth_communities, p) for p in stable_parts]
    elif method == "modularity pruning ground truth K":
        ground_truth_K = num_communities(ground_truth_communities)
        stable_parts = prune_to_stable_partitions(
            G,
            parts,
            gamma_start=gammas[0],
            gamma_end=gammas[-1],
            restrict_num_communities=ground_truth_K,
            single_threaded=True)
        nmis = [nmi(ground_truth_communities, p) for p in stable_parts]
    else:  # method == "gamma sweep" or method == "ground truth gamma":
        nmis = [nmi(ground_truth_communities, p) for p in parts]

    return nmis
Exemple #3
0
def generate_boxplot_results():
    results = []
    for i in range(len(Gs)):
        for p in pickle.load(open(f"parts{i}.p", "rb")):
            K = num_communities(p)
            g_est = gamma_estimate(Gs[i], p)

            if g_est is not None and 2 <= K < K_MAX:
                assert g_est < 15
                results.append((K, g_est))

    pickle.dump(results, open("boxplot_results.p", "wb"))
if __name__ == "__main__":
    N = 600
    B = N // 3
    p_in1 = 10 / 99
    p_in2 = p_in1 * 0.75  # 5/66
    p_out1 = 0.25 / 40  # 1/160

    for i, p_out2 in enumerate([0.02, 0.035, 0.05]):  # delta
        pref_matrix = [[p_in1, p_out1, p_out1], [p_out1, p_in2, p_out2],
                       [p_out1, p_out2, p_in2]]
        block_sizes = [B] * 3
        G = ig.Graph.SBM(N, pref_matrix, block_sizes)
        assert G.is_connected()

        ground_truth = tuple(i // B for i in range(N))
        true_gamma = gamma_estimate(G, ground_truth)
        ground_truth2 = tuple(min(1, i // B) for i in range(N))
        true_gamma2 = gamma_estimate(G, ground_truth2)

        # Store shared force-directed layout to make later plotting layouts consistent
        layout = G.layout_fruchterman_reingold(niter=1000)

        out2 = ig.plot(louvain.RBConfigurationVertexPartition(G, ground_truth),
                       f"bistable_sbm_delta{i}_2-community.png",
                       bbox=(1000, 1000),
                       layout=layout)
        out3 = ig.plot(louvain.RBConfigurationVertexPartition(
            G, ground_truth2),
                       f"bistable_sbm_delta{i}_3-community.png",
                       bbox=(1000, 1000),
                       layout=layout)
from modularitypruning.parameter_estimation_utilities import gamma_estimate, ranges_to_gamma_estimates
from modularitypruning.plotting import plot_estimates
from random import randint
import matplotlib.pyplot as plt
import numpy as np

if __name__ == "__main__":
    while True:
        G = ig.Graph.Erdos_Renyi(n=10, m=20)
        while not G.is_connected():
            G = ig.Graph.Erdos_Renyi(n=10, m=20)

        p1 = sorted_tuple(tuple(randint(0, 2) for _ in range(G.vcount())))
        p2 = sorted_tuple(tuple(randint(0, 2) for _ in range(G.vcount())))

        g1 = gamma_estimate(G, p1)
        g2 = gamma_estimate(G, p2)

        if g1 is None or g2 is None or np.isnan(g1) or np.isnan(g2):
            continue

        part1 = louvain_part_with_membership(G, p1)
        part2 = louvain_part_with_membership(G, p2)

        if part1.quality(resolution_parameter=g2) > part2.quality(resolution_parameter=g2):
            if part2.quality(resolution_parameter=g1) > part1.quality(resolution_parameter=g1):
                layout = G.layout_fruchterman_reingold(niter=1000)
                out = ig.plot(part1, layout=layout)
                out.save("estimation_loop1.png")
                out = ig.plot(part2, layout=layout)
                out.save("estimation_loop2.png")
Exemple #6
0
def generate_bistable_SBM_test_output():
    print("Running bistable SBM test...")

    N = 2400
    p2s = (np.linspace(0.01, 0.02, 5).tolist() +
           np.linspace(0.02, 0.025, 15).tolist() +
           np.linspace(0.025, 0.0475, 5).tolist() +
           np.linspace(0.0475, 0.0525, 15).tolist() +
           np.linspace(0.0525, 0.06, 5).tolist())

    c2s = []  # probability of K=2 stability
    c3s = []  # probability of K=3 stability
    cboths = []  # probability of bistability
    progress = Progress(TRIALS_PER_DELTA * len(p2s))

    for p_out2 in p2s:
        total = 0
        count_2stable = 0
        count_3stable = 0
        count_both_stable = 0

        while total < TRIALS_PER_DELTA:
            p_in1 = 10 / 99  # m_in = 10/3
            p_in2 = p_in1 * 0.75  # m_in = 5/2 for each block
            p_out1 = 0.25 / 40  # m_out = 1.25
            # p_out2 in outer loop

            pref_matrix = [[p_in1, p_out1, p_out1], [p_out1, p_in2, p_out2],
                           [p_out1, p_out2, p_in2]]
            block_sizes = [N // 3] * 3
            G = ig.Graph.SBM(N, pref_matrix, block_sizes)

            if not G.is_connected():
                print("\rDisconnected graph. Skipping...", end='', flush=True)
                continue

            ground_truth = tuple(i // block_sizes[0] for i in range(N))
            ground_truth2 = tuple(
                min(1, i // block_sizes[0]) for i in range(N))
            true_gamma = gamma_estimate(G, ground_truth)
            true_gamma2 = gamma_estimate(G, ground_truth2)

            if true_gamma is None or true_gamma2 is None:
                print("\rDegenerate ground truth estimate. Skipping...",
                      end='',
                      flush=True)
                continue

            all_parts = repeated_parallel_louvain_from_gammas(
                G,
                gammas=np.linspace(GAMMA_START, GAMMA_END,
                                   LOUVAIN_ITERATIONS_PER_DELTA),
                show_progress=False)
            ranges = CHAMP_2D(G, all_parts, GAMMA_START, GAMMA_END)
            gamma_estimates = ranges_to_gamma_estimates(G, ranges)

            stable2, stable3 = False, False
            for g_start, g_end, membership, g_est in gamma_estimates:
                if g_est is not None and g_start <= g_est <= g_end:
                    if num_communities(membership) == 2:
                        stable2 = True
                    elif num_communities(membership) == 3:
                        stable3 = True

            if stable2:
                count_2stable += 1
            if stable3:
                count_3stable += 1
            if stable2 and stable3:
                count_both_stable += 1
            total += 1

            progress.increment()

        c2s.append(count_2stable / total)
        c3s.append(count_3stable / total)
        cboths.append(count_both_stable / total)

    progress.done()

    with open("SBM_constant_probs.out", "w") as f:
        print(N, file=f)
        print(p2s, file=f)
        print(c2s, file=f)
        print(c3s, file=f)
        print(cboths, file=f)