import pytest import networkx as nx def test_modularity_increase(): G = nx.LFR_benchmark_graph( 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 ) partition = [{u} for u in G.nodes()] mod = nx.community.modularity(G, partition) partition = nx.community.louvain_communities(G) assert nx.community.modularity(G, partition) > mod def test_valid_partition(): G = nx.LFR_benchmark_graph( 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 ) H = G.to_directed() partition = nx.community.louvain_communities(G) partition2 = nx.community.louvain_communities(H) assert nx.community.is_partition(G, partition) assert nx.community.is_partition(H, partition2) def test_karate_club_partition(): G = nx.karate_club_graph() part = [ {0, 1, 2, 3, 7, 9, 11, 12, 13, 17, 19, 21}, {16, 4, 5, 6, 10}, {23, 25, 27, 28, 24, 31}, {32, 33, 8, 14, 15, 18, 20, 22, 26, 29, 30}, ] partition = nx.community.louvain_communities(G, seed=2, weight=None) assert part == partition def test_partition_iterator(): G = nx.path_graph(15) parts_iter = nx.community.louvain_partitions(G, seed=42) first_part = next(parts_iter) first_copy = [s.copy() for s in first_part] # gh-5901 reports sets changing after next partition is yielded assert first_copy[0] == first_part[0] second_part = next(parts_iter) assert first_copy[0] == first_part[0] def test_undirected_selfloops(): G = nx.karate_club_graph() expected_partition = nx.community.louvain_communities(G, seed=2, weight=None) part = [ {0, 1, 2, 3, 7, 9, 11, 12, 13, 17, 19, 21}, {16, 4, 5, 6, 10}, {23, 25, 27, 28, 24, 31}, {32, 33, 8, 14, 15, 18, 20, 22, 26, 29, 30}, ] assert expected_partition == part G.add_weighted_edges_from([(i, i, i * 1000) for i in range(9)]) # large self-loop weight impacts partition partition = nx.community.louvain_communities(G, seed=2, weight="weight") assert part != partition # small self-loop weights aren't enough to impact partition in this graph partition = nx.community.louvain_communities(G, seed=2, weight=None) assert part == partition def test_directed_selfloops(): G = nx.DiGraph() G.add_nodes_from(range(11)) G_edges = [ (0, 2), (0, 1), (1, 0), (2, 1), (2, 0), (3, 4), (4, 3), (7, 8), (8, 7), (9, 10), (10, 9), ] G.add_edges_from(G_edges) G_expected_partition = nx.community.louvain_communities(G, seed=123, weight=None) G.add_weighted_edges_from([(i, i, i * 1000) for i in range(3)]) # large self-loop weight impacts partition G_partition = nx.community.louvain_communities(G, seed=123, weight="weight") assert G_partition != G_expected_partition # small self-loop weights aren't enough to impact partition in this graph G_partition = nx.community.louvain_communities(G, seed=123, weight=None) assert G_partition == G_expected_partition def test_directed_partition(): """ Test 2 cases that were looping infinitely from issues #5175 and #5704 """ G = nx.DiGraph() H = nx.DiGraph() G.add_nodes_from(range(10)) H.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) G_edges = [ (0, 2), (0, 1), (1, 0), (2, 1), (2, 0), (3, 4), (4, 3), (7, 8), (8, 7), (9, 10), (10, 9), ] H_edges = [ (1, 2), (1, 6), (1, 9), (2, 3), (2, 4), (2, 5), (3, 4), (4, 3), (4, 5), (5, 4), (6, 7), (6, 8), (9, 10), (9, 11), (10, 11), (11, 10), ] G.add_edges_from(G_edges) H.add_edges_from(H_edges) G_expected_partition = [{0, 1, 2}, {3, 4}, {5}, {6}, {8, 7}, {9, 10}] G_partition = nx.community.louvain_communities(G, seed=123, weight=None) H_expected_partition = [{2, 3, 4, 5}, {8, 1, 6, 7}, {9, 10, 11}] H_partition = nx.community.louvain_communities(H, seed=123, weight=None) assert G_partition == G_expected_partition assert H_partition == H_expected_partition def test_none_weight_param(): G = nx.karate_club_graph() nx.set_edge_attributes( G, {edge: i * i for i, edge in enumerate(G.edges)}, name="foo" ) part = [ {0, 1, 2, 3, 7, 9, 11, 12, 13, 17, 19, 21}, {16, 4, 5, 6, 10}, {23, 25, 27, 28, 24, 31}, {32, 33, 8, 14, 15, 18, 20, 22, 26, 29, 30}, ] partition1 = nx.community.louvain_communities(G, weight=None, seed=2) partition2 = nx.community.louvain_communities(G, weight="foo", seed=2) partition3 = nx.community.louvain_communities(G, weight="weight", seed=2) assert part == partition1 assert part != partition2 assert part != partition3 assert partition2 != partition3 def test_quality(): G = nx.LFR_benchmark_graph( 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 ) H = nx.gn_graph(200, seed=1234) I = nx.MultiGraph(G) J = nx.MultiDiGraph(H) partition = nx.community.louvain_communities(G) partition2 = nx.community.louvain_communities(H) partition3 = nx.community.louvain_communities(I) partition4 = nx.community.louvain_communities(J) quality = nx.community.partition_quality(G, partition)[0] quality2 = nx.community.partition_quality(H, partition2)[0] quality3 = nx.community.partition_quality(I, partition3)[0] quality4 = nx.community.partition_quality(J, partition4)[0] assert quality >= 0.65 assert quality2 >= 0.65 assert quality3 >= 0.65 assert quality4 >= 0.65 def test_multigraph(): G = nx.karate_club_graph() H = nx.MultiGraph(G) G.add_edge(0, 1, weight=10) H.add_edge(0, 1, weight=9) G.add_edge(0, 9, foo=20) H.add_edge(0, 9, foo=20) partition1 = nx.community.louvain_communities(G, seed=1234) partition2 = nx.community.louvain_communities(H, seed=1234) partition3 = nx.community.louvain_communities(H, weight="foo", seed=1234) assert partition1 == partition2 != partition3 def test_resolution(): G = nx.LFR_benchmark_graph( 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 ) partition1 = nx.community.louvain_communities(G, resolution=0.5, seed=12) partition2 = nx.community.louvain_communities(G, seed=12) partition3 = nx.community.louvain_communities(G, resolution=2, seed=12) assert len(partition1) <= len(partition2) <= len(partition3) def test_threshold(): G = nx.LFR_benchmark_graph( 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 ) partition1 = nx.community.louvain_communities(G, threshold=0.3, seed=2) partition2 = nx.community.louvain_communities(G, seed=2) mod1 = nx.community.modularity(G, partition1) mod2 = nx.community.modularity(G, partition2) assert mod1 <= mod2 def test_empty_graph(): G = nx.Graph() G.add_nodes_from(range(5)) expected = [{0}, {1}, {2}, {3}, {4}] assert nx.community.louvain_communities(G) == expected def test_max_level(): G = nx.LFR_benchmark_graph( 250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10 ) parts_iter = nx.community.louvain_partitions(G, seed=42) for max_level, expected in enumerate(parts_iter, 1): partition = nx.community.louvain_communities(G, max_level=max_level, seed=42) assert partition == expected assert max_level > 1 # Ensure we are actually testing max_level # max_level is an upper limit; it's okay if we stop before it's hit. partition = nx.community.louvain_communities(G, max_level=max_level + 1, seed=42) assert partition == expected with pytest.raises( ValueError, match="max_level argument must be a positive integer" ): nx.community.louvain_communities(G, max_level=0)