From c2f94eba673167a22399aa0dfa6ba24140148ee1 Mon Sep 17 00:00:00 2001 From: Akshita Sure Date: Fri, 22 Aug 2025 19:06:32 +0530 Subject: [PATCH 1/6] added should_run to run when nodes is None --- nx_parallel/algorithms/cluster.py | 2 +- nx_parallel/tests/test_should_run.py | 13 +++++++++++++ nx_parallel/utils/should_run_policies.py | 7 +++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/nx_parallel/algorithms/cluster.py b/nx_parallel/algorithms/cluster.py index 7fe1e0d4..82c18e85 100644 --- a/nx_parallel/algorithms/cluster.py +++ b/nx_parallel/algorithms/cluster.py @@ -72,7 +72,7 @@ def _compute_clustering_chunk(node_iter_chunk): return clustering -@nxp._configure_if_nx_active() +@nxp._configure_if_nx_active(should_run=nxp.should_run_if_nodes_none) def triangles(G, nodes=None, get_chunks="chunks"): """The nodes are chunked into `node_chunks` and for all `node_chunks` the number of triangles that include a node as one vertex is computed diff --git a/nx_parallel/tests/test_should_run.py b/nx_parallel/tests/test_should_run.py index 2b853aa9..314a5113 100644 --- a/nx_parallel/tests/test_should_run.py +++ b/nx_parallel/tests/test_should_run.py @@ -52,6 +52,19 @@ def dummy_if_large(G): assert dummy_if_large.should_run(largeG) +def test_should_run_if_nodes_none(): + @nxp._configure_if_nx_active(should_run=nxp.should_run_if_nodes_none) + def dummy_nodes_none(G, nodes=None): + pass + + G = nx.fast_gnp_random_graph(20, 0.6, seed=42) + assert ( + dummy_nodes_none.should_run(G, nodes=[1, 3]) + == "`nodes` should be None for parallel execution" + ) + assert dummy_nodes_none.should_run(G) + + @pytest.mark.parametrize("func_name", get_functions_with_should_run()) def test_should_run(func_name): tournament_funcs = [ diff --git a/nx_parallel/utils/should_run_policies.py b/nx_parallel/utils/should_run_policies.py index 19a5eb20..17376ca8 100644 --- a/nx_parallel/utils/should_run_policies.py +++ b/nx_parallel/utils/should_run_policies.py @@ -5,6 +5,7 @@ "default_should_run", "should_skip_parallel", "should_run_if_large", + "should_run_if_nodes_none", ] @@ -24,3 +25,9 @@ def default_should_run(*_): if n_jobs in (None, 0, 1): return "Parallel backend requires `n_jobs` > 1 to run" return True + + +def should_run_if_nodes_none(G, nodes=None, *_): + if nodes is None: + return True + return "`nodes` should be None for parallel execution" From 20243d3cc082de1be88eb6942b6cc05a709860c1 Mon Sep 17 00:00:00 2001 From: Dan Schult Date: Fri, 29 Aug 2025 15:38:31 -0400 Subject: [PATCH 2/6] Merge conflicts in nx_parallel/tests/test_should_run.py --- nx_parallel/tests/test_should_run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nx_parallel/tests/test_should_run.py b/nx_parallel/tests/test_should_run.py index a9c16a5b..46a07ec9 100644 --- a/nx_parallel/tests/test_should_run.py +++ b/nx_parallel/tests/test_should_run.py @@ -64,7 +64,7 @@ def dummy_nodes_none(G, nodes=None): ) assert dummy_nodes_none.should_run(G) - + def test_should_run_if_sparse(): @nxp._configure_if_nx_active(should_run=nxp.should_run_if_sparse) def dummy_if_sparse(G): From 1ddd33f87eb79379e5a53bfa9fd57f3046f35326 Mon Sep 17 00:00:00 2001 From: Akshita <145579024+akshitasure12@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:35:21 +0530 Subject: [PATCH 3/6] improve wording Co-authored-by: Dan Schult --- nx_parallel/tests/test_should_run.py | 2 +- nx_parallel/utils/should_run_policies.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nx_parallel/tests/test_should_run.py b/nx_parallel/tests/test_should_run.py index 46a07ec9..d897073e 100644 --- a/nx_parallel/tests/test_should_run.py +++ b/nx_parallel/tests/test_should_run.py @@ -60,7 +60,7 @@ def dummy_nodes_none(G, nodes=None): G = nx.fast_gnp_random_graph(20, 0.6, seed=42) assert ( dummy_nodes_none.should_run(G, nodes=[1, 3]) - == "`nodes` should be None for parallel execution" + == "Parallel execution only supported when `nodes` is None" ) assert dummy_nodes_none.should_run(G) diff --git a/nx_parallel/utils/should_run_policies.py b/nx_parallel/utils/should_run_policies.py index 454fe0cd..e898ca40 100644 --- a/nx_parallel/utils/should_run_policies.py +++ b/nx_parallel/utils/should_run_policies.py @@ -31,7 +31,7 @@ def default_should_run(*_): def should_run_if_nodes_none(G, nodes=None, *_): if nodes is None: return True - return "`nodes` should be None for parallel execution" + return "Parallel execution only supported when `nodes` is None" def should_run_if_sparse(G, *args, threshold=0.3, **kwargs): From 5bbfd4566d330b635534819fd5a6e62f9fe338ec Mon Sep 17 00:00:00 2001 From: Akshita Sure Date: Sat, 30 Aug 2025 14:38:40 +0530 Subject: [PATCH 4/6] remove handling for nodes is not None case --- _nx_parallel/__init__.py | 4 ++-- nx_parallel/algorithms/cluster.py | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/_nx_parallel/__init__.py b/_nx_parallel/__init__.py index 41599298..e3723d2c 100644 --- a/_nx_parallel/__init__.py +++ b/_nx_parallel/__init__.py @@ -91,7 +91,7 @@ def get_info(): }, }, "average_clustering": { - "url": "https://github.com/networkx/nx-parallel/blob/main/nx_parallel/algorithms/cluster.py#L213", + "url": "https://github.com/networkx/nx-parallel/blob/main/nx_parallel/algorithms/cluster.py#L207", "additional_docs": "The nodes are chunked into `node_chunks` and then the average clustering coefficient for all `node_chunks` is computed in parallel over `n_jobs` number of CPU cores.", "additional_parameters": { 'get_chunks : str, function (default = "chunks")': "A function that takes in a list of all the nodes (or nbunch) as input and returns an iterable `node_chunks`. The default chunking is done by slicing the `nodes` into `n_jobs` number of chunks." @@ -119,7 +119,7 @@ def get_info(): }, }, "clustering": { - "url": "https://github.com/networkx/nx-parallel/blob/main/nx_parallel/algorithms/cluster.py#L146", + "url": "https://github.com/networkx/nx-parallel/blob/main/nx_parallel/algorithms/cluster.py#L140", "additional_docs": "The nodes are chunked into `node_chunks` and then the clustering coefficient for all `node_chunks` is computed in parallel over `n_jobs` number of CPU cores.", "additional_parameters": { 'get_chunks : str, function (default = "chunks")': "A function that takes in a list of all the nodes (or nbunch) as input and returns an iterable `node_chunks`. The default chunking is done by slicing the `nodes` into `n_jobs` number of chunks." diff --git a/nx_parallel/algorithms/cluster.py b/nx_parallel/algorithms/cluster.py index 9fc90e3c..d4c738ee 100644 --- a/nx_parallel/algorithms/cluster.py +++ b/nx_parallel/algorithms/cluster.py @@ -111,12 +111,6 @@ def _compute_triangles_chunk(node_iter_chunk, later_nbrs): if hasattr(G, "graph_object"): G = G.graph_object - # Use parallel version only if nodes is None (i.e., all nodes requested) - if nodes is not None: - if nodes in G: - return next(_triangles_and_degree_iter(G, nodes))[2] // 2 - return {v: t // 2 for v, d, t, _ in _triangles_and_degree_iter(G, nodes)} - # Use parallel version for all nodes in G nodes = list(G) From fc85411c6dba28950d108056f4d1f5a53cf0a254 Mon Sep 17 00:00:00 2001 From: Akshita Sure Date: Sat, 30 Aug 2025 21:38:16 +0530 Subject: [PATCH 5/6] revert to including case: node is not none --- _nx_parallel/__init__.py | 4 ++-- nx_parallel/algorithms/cluster.py | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/_nx_parallel/__init__.py b/_nx_parallel/__init__.py index e3723d2c..41599298 100644 --- a/_nx_parallel/__init__.py +++ b/_nx_parallel/__init__.py @@ -91,7 +91,7 @@ def get_info(): }, }, "average_clustering": { - "url": "https://github.com/networkx/nx-parallel/blob/main/nx_parallel/algorithms/cluster.py#L207", + "url": "https://github.com/networkx/nx-parallel/blob/main/nx_parallel/algorithms/cluster.py#L213", "additional_docs": "The nodes are chunked into `node_chunks` and then the average clustering coefficient for all `node_chunks` is computed in parallel over `n_jobs` number of CPU cores.", "additional_parameters": { 'get_chunks : str, function (default = "chunks")': "A function that takes in a list of all the nodes (or nbunch) as input and returns an iterable `node_chunks`. The default chunking is done by slicing the `nodes` into `n_jobs` number of chunks." @@ -119,7 +119,7 @@ def get_info(): }, }, "clustering": { - "url": "https://github.com/networkx/nx-parallel/blob/main/nx_parallel/algorithms/cluster.py#L140", + "url": "https://github.com/networkx/nx-parallel/blob/main/nx_parallel/algorithms/cluster.py#L146", "additional_docs": "The nodes are chunked into `node_chunks` and then the clustering coefficient for all `node_chunks` is computed in parallel over `n_jobs` number of CPU cores.", "additional_parameters": { 'get_chunks : str, function (default = "chunks")': "A function that takes in a list of all the nodes (or nbunch) as input and returns an iterable `node_chunks`. The default chunking is done by slicing the `nodes` into `n_jobs` number of chunks." diff --git a/nx_parallel/algorithms/cluster.py b/nx_parallel/algorithms/cluster.py index d4c738ee..9fc90e3c 100644 --- a/nx_parallel/algorithms/cluster.py +++ b/nx_parallel/algorithms/cluster.py @@ -111,6 +111,12 @@ def _compute_triangles_chunk(node_iter_chunk, later_nbrs): if hasattr(G, "graph_object"): G = G.graph_object + # Use parallel version only if nodes is None (i.e., all nodes requested) + if nodes is not None: + if nodes in G: + return next(_triangles_and_degree_iter(G, nodes))[2] // 2 + return {v: t // 2 for v, d, t, _ in _triangles_and_degree_iter(G, nodes)} + # Use parallel version for all nodes in G nodes = list(G) From 975b8deb6ffb626f6b4852788248cd1b8b85e232 Mon Sep 17 00:00:00 2001 From: Dan Schult Date: Sun, 21 Sep 2025 22:59:44 -0400 Subject: [PATCH 6/6] whitespace --- nx_parallel/utils/should_run_policies.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nx_parallel/utils/should_run_policies.py b/nx_parallel/utils/should_run_policies.py index 5902c7f6..97ecc2ef 100644 --- a/nx_parallel/utils/should_run_policies.py +++ b/nx_parallel/utils/should_run_policies.py @@ -37,11 +37,6 @@ def should_run_if_nodes_none(G, nodes=None, *_): return "Parallel execution only supported when `nodes` is None" -def should_run_if_sparse(G, *args, threshold=0.3, **kwargs): - if hasattr(G, "graph_object"): - G = G.graph_object - - def should_run_if_sparse(threshold=0.3): def wrapper(G, *_): if hasattr(G, "graph_object"):