Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions _nx_parallel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ def get_info():
'get_chunks : str, function (default = "chunks")': "A function that takes in an iterable of all the nodes as input and returns an iterable `node_chunks`. The default chunking is done by slicing the `G.nodes` into `n_jobs` number of chunks."
},
},
"latapy_clustering": {
"url": "https://github.com/networkx/nx-parallel/blob/main/nx_parallel/algorithms/bipartite/cluster.py#L10",
"additional_docs": "In the parallel implementation we divide the nodes into chunks and compute the bipartite clustering coefficient for all `node_chunk` in parallel.",
"additional_parameters": {
'get_chunks : str, function (default = "chunks")': "A function that takes in an iterable of all the nodes as input and returns an iterable `node_chunks`. The default chunking is done by slicing the `G.nodes` (or `nodes`) into `n_jobs` number of chunks."
},
},
"local_efficiency": {
"url": "https://github.com/networkx/nx-parallel/blob/main/nx_parallel/algorithms/efficiency_measures.py#L11",
"additional_docs": "The parallel computation is implemented by dividing the nodes into chunks and then computing and adding global efficiencies of all node in all chunks, in parallel, and then adding all these sums and dividing by the total number of nodes at the end.",
Expand Down
1 change: 1 addition & 0 deletions nx_parallel/algorithms/bipartite/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .cluster import *
from .redundancy import *
64 changes: 64 additions & 0 deletions nx_parallel/algorithms/bipartite/cluster.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from joblib import Parallel, delayed
from networkx.algorithms.bipartite.cluster import modes
import networkx as nx
import nx_parallel as nxp

__all__ = ["latapy_clustering", "clustering"]


@nxp._configure_if_nx_active()
def latapy_clustering(G, nodes=None, mode="dot", get_chunks="chunks"):
"""In the parallel implementation we divide the nodes into chunks and compute
the bipartite clustering coefficient for all `node_chunk` in parallel.

networkx.bipartite.latapy_clustering : https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.bipartite.cluster.latapy_clustering.html

Parameters
----------
get_chunks : str, function (default = "chunks")
A function that takes in an iterable of all the nodes as input and returns
an iterable `node_chunks`. The default chunking is done by slicing the
`G.nodes` (or `nodes`) into `n_jobs` number of chunks.
"""

def _process_chunk(chunk):
ccs = {}
for v in chunk:
cc = 0.0
nbrs2 = {u for nbr in G[v] for u in G[nbr]} - {v}
for u in nbrs2:
cc += cc_func(set(G[u]), set(G[v]))
if cc > 0.0: # len(nbrs2)>0
cc /= len(nbrs2)
ccs[v] = cc
return ccs

if hasattr(G, "graph_object"):
G = G.graph_object

if not nx.algorithms.bipartite.is_bipartite(G):
raise nx.NetworkXError("Graph is not bipartite")

try:
cc_func = modes[mode]
except KeyError as err:
raise nx.NetworkXError(
"Mode for bipartite clustering must be: dot, min or max"
) from err

if nodes is None:
nodes = G
n_jobs = nxp.get_n_jobs()
if get_chunks == "chunks":
node_chunks = nxp.chunks(nodes, n_jobs)
else:
node_chunks = get_chunks(nodes)
results = Parallel()(delayed(_process_chunk)(chunk) for chunk in node_chunks)
clusterings = {}
for result in results:
clusterings.update(result)

return clusterings


clustering = latapy_clustering
1 change: 1 addition & 0 deletions nx_parallel/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
ALGORITHMS = [
# Bipartite
"node_redundancy",
"latapy_clustering",
# Isolates
"number_of_isolates",
# Vitality
Expand Down
5 changes: 5 additions & 0 deletions nx_parallel/tests/test_get_chunks.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,16 @@ def random_chunking(nodes):
"v_structures",
"colliders",
]
bipartite_funcs = [
"latapy_clustering",
]

if func in tournament_funcs:
G = nx.tournament.random_tournament(15, seed=42)
elif func in dag_funcs:
G = nx.gn_graph(25, seed=42, create_using=nx.DiGraph)
elif func in bipartite_funcs:
G = nx.bipartite.random_graph(20, 25, 0.6, seed=42, directed=True)
else:
G = nx.fast_gnp_random_graph(
40, 0.6, seed=42, directed=func in not_implemented_undirected
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 16 additions & 14 deletions timing/new_heatmaps/timing_individual_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

seed = random.Random(42)
tournament_funcs = ["is_reachable", "is_strongly_connected"]
bipartite_funcs = ["node_redundancy"]
bipartite_funcs = ["node_redundancy", "latapy_clustering"]
community_funcs = [
"ra_index_soundarajan_hopcroft",
"cn_soundarajan_hopcroft",
Expand Down Expand Up @@ -58,19 +58,21 @@ def record_result(stdTime, parallelTime, row, col):
G = nx.bipartite.random_graph(
n[ind], m[ind], p, directed=True, seed=seed
)
for cur_node in G.nodes:
neighbors = set(G.neighbors(cur_node))
# have atleast 2 outgoing edges
while len(neighbors) < 2:
new_neighbor = seed.choice(
[
node
for node in G.nodes
if node != cur_node and node not in neighbors
]
)
G.add_edge(cur_node, new_neighbor)
neighbors.add(new_neighbor)
A, B = range(n[ind]), range(n[ind], n[ind] + m[ind])
for source_group, target_group in [(A, B), (B, A)]:
for cur_node in source_group:
neighbors = set(G.neighbors(cur_node))
# have atleast 2 outgoing edges
while len(neighbors) < 2:
new_neighbor = seed.choice(
[
node
for node in target_group
if node not in neighbors
]
)
G.add_edge(cur_node, new_neighbor)
neighbors.add(new_neighbor)
else:
print(f"Number of Nodes: {num}")
G = nx.fast_gnp_random_graph(
Expand Down
Loading