Skip to content

Commit

Permalink
nx-cugraph: add more shortest path algorithms (#4199)
Browse files Browse the repository at this point in the history
This begins by adding more unweighted shortest path algorithms. Next we'll do weighted via `sssp`, then generic.

Note that there are some performance improvements that can be made:
- add bidirectional search between source and target
  - for `bidirectional_shortest_path` and `has_path`
- alternatively, perform `bfs` from `source` until `target` is reached
- run `all_pairs*` in batched groups

Authors:
  - Erik Welch (https://github.com/eriknw)
  - Ralph Liu (https://github.com/nv-rliu)

Approvers:
  - Brad Rees (https://github.com/BradReesWork)
  - Rick Ratzel (https://github.com/rlratzel)
  - Don Acosta (https://github.com/acostadon)

URL: #4199
  • Loading branch information
eriknw committed Mar 13, 2024
1 parent 6c88281 commit 6b28aef
Show file tree
Hide file tree
Showing 17 changed files with 723 additions and 83 deletions.
25 changes: 20 additions & 5 deletions python/nx-cugraph/README.md
Expand Up @@ -95,8 +95,6 @@ Below is the list of algorithms that are currently supported in nx-cugraph.

<pre>
<a href="https://networkx.org/documentation/stable/reference/algorithms/bipartite.html#module-networkx.algorithms.bipartite">bipartite</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/bipartite.html#module-networkx.algorithms.bipartite.basic">basic</a>
│ └─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.bipartite.basic.is_bipartite.html#networkx.algorithms.bipartite.basic.is_bipartite">is_bipartite</a>
└─ <a href="https://networkx.org/documentation/stable/reference/algorithms/bipartite.html#module-networkx.algorithms.bipartite.generators">generators</a>
└─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.bipartite.generators.complete_bipartite_graph.html#networkx.algorithms.bipartite.generators.complete_bipartite_graph">complete_bipartite_graph</a>
<a href="https://networkx.org/documentation/stable/reference/algorithms/centrality.html#module-networkx.algorithms.centrality">centrality</a>
Expand Down Expand Up @@ -152,9 +150,26 @@ Below is the list of algorithms that are currently supported in nx-cugraph.
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.reciprocity.overall_reciprocity.html#networkx.algorithms.reciprocity.overall_reciprocity">overall_reciprocity</a>
└─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.reciprocity.reciprocity.html#networkx.algorithms.reciprocity.reciprocity">reciprocity</a>
<a href="https://networkx.org/documentation/stable/reference/algorithms/shortest_paths.html">shortest_paths</a>
└─ <a href="https://networkx.org/documentation/stable/reference/algorithms/shortest_paths.html#module-networkx.algorithms.shortest_paths.unweighted">unweighted</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.unweighted.single_source_shortest_path_length.html#networkx.algorithms.shortest_paths.unweighted.single_source_shortest_path_length">single_source_shortest_path_length</a>
└─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.unweighted.single_target_shortest_path_length.html#networkx.algorithms.shortest_paths.unweighted.single_target_shortest_path_length">single_target_shortest_path_length</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/shortest_paths.html#module-networkx.algorithms.shortest_paths.generic">generic</a>
│ ├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.generic.has_path.html#networkx.algorithms.shortest_paths.generic.has_path">has_path</a>
│ ├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.generic.shortest_path.html#networkx.algorithms.shortest_paths.generic.shortest_path">shortest_path</a>
│ └─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.generic.shortest_path_length.html#networkx.algorithms.shortest_paths.generic.shortest_path_length">shortest_path_length</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/shortest_paths.html#module-networkx.algorithms.shortest_paths.unweighted">unweighted</a>
│ ├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.unweighted.all_pairs_shortest_path.html#networkx.algorithms.shortest_paths.unweighted.all_pairs_shortest_path">all_pairs_shortest_path</a>
│ ├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.unweighted.all_pairs_shortest_path_length.html#networkx.algorithms.shortest_paths.unweighted.all_pairs_shortest_path_length">all_pairs_shortest_path_length</a>
│ ├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.unweighted.bidirectional_shortest_path.html#networkx.algorithms.shortest_paths.unweighted.bidirectional_shortest_path">bidirectional_shortest_path</a>
│ ├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.unweighted.single_source_shortest_path.html#networkx.algorithms.shortest_paths.unweighted.single_source_shortest_path">single_source_shortest_path</a>
│ ├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.unweighted.single_source_shortest_path_length.html#networkx.algorithms.shortest_paths.unweighted.single_source_shortest_path_length">single_source_shortest_path_length</a>
│ ├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.unweighted.single_target_shortest_path.html#networkx.algorithms.shortest_paths.unweighted.single_target_shortest_path">single_target_shortest_path</a>
│ └─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.unweighted.single_target_shortest_path_length.html#networkx.algorithms.shortest_paths.unweighted.single_target_shortest_path_length">single_target_shortest_path_length</a>
└─ <a href="https://networkx.org/documentation/stable/reference/algorithms/shortest_paths.html#module-networkx.algorithms.shortest_paths.weighted">weighted</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.weighted.all_pairs_bellman_ford_path.html#networkx.algorithms.shortest_paths.weighted.all_pairs_bellman_ford_path">all_pairs_bellman_ford_path</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.weighted.all_pairs_bellman_ford_path_length.html#networkx.algorithms.shortest_paths.weighted.all_pairs_bellman_ford_path_length">all_pairs_bellman_ford_path_length</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.weighted.bellman_ford_path.html#networkx.algorithms.shortest_paths.weighted.bellman_ford_path">bellman_ford_path</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.weighted.bellman_ford_path_length.html#networkx.algorithms.shortest_paths.weighted.bellman_ford_path_length">bellman_ford_path_length</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.weighted.single_source_bellman_ford.html#networkx.algorithms.shortest_paths.weighted.single_source_bellman_ford">single_source_bellman_ford</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.weighted.single_source_bellman_ford_path.html#networkx.algorithms.shortest_paths.weighted.single_source_bellman_ford_path">single_source_bellman_ford_path</a>
└─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.weighted.single_source_bellman_ford_path_length.html#networkx.algorithms.shortest_paths.weighted.single_source_bellman_ford_path_length">single_source_bellman_ford_path_length</a>
<a href="https://networkx.org/documentation/stable/reference/algorithms/traversal.html">traversal</a>
└─ <a href="https://networkx.org/documentation/stable/reference/algorithms/traversal.html#module-networkx.algorithms.traversal.breadth_first_search">breadth_first_search</a>
├─ <a href="https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.traversal.breadth_first_search.bfs_edges.html#networkx.algorithms.traversal.breadth_first_search.bfs_edges">bfs_edges</a>
Expand Down
52 changes: 51 additions & 1 deletion python/nx-cugraph/_nx_cugraph/__init__.py
Expand Up @@ -33,15 +33,22 @@
# "description": "TODO",
"functions": {
# BEGIN: functions
"all_pairs_bellman_ford_path",
"all_pairs_bellman_ford_path_length",
"all_pairs_shortest_path",
"all_pairs_shortest_path_length",
"ancestors",
"average_clustering",
"barbell_graph",
"bellman_ford_path",
"bellman_ford_path_length",
"betweenness_centrality",
"bfs_edges",
"bfs_layers",
"bfs_predecessors",
"bfs_successors",
"bfs_tree",
"bidirectional_shortest_path",
"bull_graph",
"caveman_graph",
"chvatal_graph",
Expand Down Expand Up @@ -70,14 +77,14 @@
"from_scipy_sparse_array",
"frucht_graph",
"generic_bfs_edges",
"has_path",
"heawood_graph",
"hits",
"house_graph",
"house_x_graph",
"icosahedral_graph",
"in_degree_centrality",
"is_arborescence",
"is_bipartite",
"is_branching",
"is_connected",
"is_forest",
Expand Down Expand Up @@ -110,7 +117,14 @@
"reciprocity",
"reverse",
"sedgewick_maze_graph",
"shortest_path",
"shortest_path_length",
"single_source_bellman_ford",
"single_source_bellman_ford_path",
"single_source_bellman_ford_path_length",
"single_source_shortest_path",
"single_source_shortest_path_length",
"single_target_shortest_path",
"single_target_shortest_path_length",
"star_graph",
"tadpole_graph",
Expand All @@ -128,7 +142,11 @@
},
"additional_docs": {
# BEGIN: additional_docs
"all_pairs_bellman_ford_path": "Negative cycles are not yet supported. ``NotImplementedError`` will be raised if there are negative edge weights. We plan to support negative edge weights soon. Also, callable ``weight`` argument is not supported.",
"all_pairs_bellman_ford_path_length": "Negative cycles are not yet supported. ``NotImplementedError`` will be raised if there are negative edge weights. We plan to support negative edge weights soon. Also, callable ``weight`` argument is not supported.",
"average_clustering": "Directed graphs and `weight` parameter are not yet supported.",
"bellman_ford_path": "Negative cycles are not yet supported. ``NotImplementedError`` will be raised if there are negative edge weights. We plan to support negative edge weights soon. Also, callable ``weight`` argument is not supported.",
"bellman_ford_path_length": "Negative cycles are not yet supported. ``NotImplementedError`` will be raised if there are negative edge weights. We plan to support negative edge weights soon. Also, callable ``weight`` argument is not supported.",
"betweenness_centrality": "`weight` parameter is not yet supported, and RNG with seed may be different.",
"bfs_edges": "`sort_neighbors` parameter is not yet supported.",
"bfs_predecessors": "`sort_neighbors` parameter is not yet supported.",
Expand All @@ -147,11 +165,28 @@
"katz_centrality": "`nstart` isn't used (but is checked), and `normalized=False` is not supported.",
"louvain_communities": "`seed` parameter is currently ignored, and self-loops are not yet supported.",
"pagerank": "`dangling` parameter is not supported, but it is checked for validity.",
"shortest_path": "Negative weights are not yet supported, and method is ununsed.",
"shortest_path_length": "Negative weights are not yet supported, and method is ununsed.",
"single_source_bellman_ford": "Negative cycles are not yet supported. ``NotImplementedError`` will be raised if there are negative edge weights. We plan to support negative edge weights soon. Also, callable ``weight`` argument is not supported.",
"single_source_bellman_ford_path": "Negative cycles are not yet supported. ``NotImplementedError`` will be raised if there are negative edge weights. We plan to support negative edge weights soon. Also, callable ``weight`` argument is not supported.",
"single_source_bellman_ford_path_length": "Negative cycles are not yet supported. ``NotImplementedError`` will be raised if there are negative edge weights. We plan to support negative edge weights soon. Also, callable ``weight`` argument is not supported.",
"transitivity": "Directed graphs are not yet supported.",
# END: additional_docs
},
"additional_parameters": {
# BEGIN: additional_parameters
"all_pairs_bellman_ford_path": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
"all_pairs_bellman_ford_path_length": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
"bellman_ford_path": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
"bellman_ford_path_length": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
"eigenvector_centrality": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
Expand All @@ -169,6 +204,21 @@
"pagerank": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
"shortest_path": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
"shortest_path_length": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
"single_source_bellman_ford": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
"single_source_bellman_ford_path": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
"single_source_bellman_ford_path_length": {
"dtype : dtype or None, optional": "The data type (np.float32, np.float64, or None) to use for the edge weights in the algorithm. If None, then dtype is determined by the edge values.",
},
# END: additional_parameters
},
}
Expand Down
4 changes: 2 additions & 2 deletions python/nx-cugraph/lint.yaml
Expand Up @@ -50,7 +50,7 @@ repos:
- id: black
# - id: black-jupyter
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.2
rev: v0.3.2
hooks:
- id: ruff
args: [--fix-only, --show-fixes] # --unsafe-fixes]
Expand All @@ -77,7 +77,7 @@ repos:
additional_dependencies: [tomli]
files: ^(nx_cugraph|docs)/
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.2
rev: v0.3.2
hooks:
- id: ruff
- repo: https://github.com/pre-commit/pre-commit-hooks
Expand Down
2 changes: 1 addition & 1 deletion python/nx-cugraph/nx_cugraph/algorithms/__init__.py
Expand Up @@ -22,7 +22,7 @@
traversal,
tree,
)
from .bipartite import complete_bipartite_graph, is_bipartite
from .bipartite import complete_bipartite_graph
from .centrality import *
from .cluster import *
from .components import *
Expand Down
Expand Up @@ -10,5 +10,4 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from .basic import *
from .generators import *
31 changes: 0 additions & 31 deletions python/nx-cugraph/nx_cugraph/algorithms/bipartite/basic.py

This file was deleted.

Expand Up @@ -36,17 +36,12 @@ def eigenvector_centrality(
G, max_iter=100, tol=1.0e-6, nstart=None, weight=None, *, dtype=None
):
"""`nstart` parameter is not used, but it is checked for validity."""
G = _to_graph(G, weight, np.float32)
G = _to_graph(G, weight, 1, np.float32)
if len(G) == 0:
raise nx.NetworkXPointlessConcept(
"cannot compute centrality for the null graph"
)
if dtype is not None:
dtype = _get_float_dtype(dtype)
elif weight in G.edge_values:
dtype = _get_float_dtype(G.edge_values[weight].dtype)
else:
dtype = np.float32
dtype = _get_float_dtype(dtype, graph=G, weight=weight)
if nstart is not None:
# Check if given nstart is valid even though we don't use it
nstart = G._dict_to_nodearray(nstart, dtype=dtype)
Expand Down
9 changes: 2 additions & 7 deletions python/nx-cugraph/nx_cugraph/algorithms/centrality/katz.py
Expand Up @@ -49,15 +49,10 @@ def katz_centrality(
# Redundant with the `_can_run` check below when being dispatched by NetworkX,
# but we raise here in case this funcion is called directly.
raise NotImplementedError("normalized=False is not supported.")
G = _to_graph(G, weight, np.float32)
G = _to_graph(G, weight, 1, np.float32)
if (N := len(G)) == 0:
return {}
if dtype is not None:
dtype = _get_float_dtype(dtype)
elif weight in G.edge_values:
dtype = _get_float_dtype(G.edge_values[weight].dtype)
else:
dtype = np.float32
dtype = _get_float_dtype(dtype, graph=G, weight=weight)
if nstart is not None:
# Check if given nstart is valid even though we don't use it
nstart = G._dict_to_nodearray(nstart, 0, dtype)
Expand Down
Expand Up @@ -46,15 +46,10 @@ def hits(
weight="weight",
dtype=None,
):
G = _to_graph(G, weight, np.float32)
G = _to_graph(G, weight, 1, np.float32)
if (N := len(G)) == 0:
return {}, {}
if dtype is not None:
dtype = _get_float_dtype(dtype)
elif weight in G.edge_values:
dtype = _get_float_dtype(G.edge_values[weight].dtype)
else:
dtype = np.float32
dtype = _get_float_dtype(dtype, graph=G, weight=weight)
if nstart is not None:
nstart = G._dict_to_nodearray(nstart, 0, dtype)
if max_iter <= 0:
Expand Down

0 comments on commit 6b28aef

Please sign in to comment.