diff --git a/_nx_cugraph/__init__.py b/_nx_cugraph/__init__.py index 6b905e8db..e37daad0a 100644 --- a/_nx_cugraph/__init__.py +++ b/_nx_cugraph/__init__.py @@ -114,6 +114,7 @@ "katz_centrality", "krackhardt_kite_graph", "ladder_graph", + "leiden_communities", "les_miserables_graph", "lollipop_graph", "louvain_communities", @@ -234,6 +235,9 @@ "katz_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.", }, + "leiden_communities": { + "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.", + }, "louvain_communities": { "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.", }, diff --git a/nx_cugraph/algorithms/community/__init__.py b/nx_cugraph/algorithms/community/__init__.py index 51a4f5c19..a9c745a2e 100644 --- a/nx_cugraph/algorithms/community/__init__.py +++ b/nx_cugraph/algorithms/community/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -10,4 +10,5 @@ # 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 .leiden import * from .louvain import * diff --git a/nx_cugraph/algorithms/community/leiden.py b/nx_cugraph/algorithms/community/leiden.py new file mode 100644 index 000000000..6005bdcae --- /dev/null +++ b/nx_cugraph/algorithms/community/leiden.py @@ -0,0 +1,52 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +import numpy as np +import pylibcugraph as plc + +from nx_cugraph.convert import _to_undirected_graph +from nx_cugraph.utils import ( + _dtype_param, + _get_float_dtype, + _groupby, + _seed_to_int, + networkx_algorithm, + not_implemented_for, +) + +__all__ = ["leiden_communities"] + + +@not_implemented_for("directed") +@networkx_algorithm(extra_params=_dtype_param, version_added="25.02", _plc="leiden") +def leiden_communities( + G, weight="weight", resolution=1, max_level=None, seed=None, *, dtype=None +): + # Warning: this API is experimental and may change. It is not yet in NetworkX. + # See: https://github.com/networkx/networkx/pull/7743 + seed = _seed_to_int(seed) + G = _to_undirected_graph(G, weight, 1, np.float32) + dtype = _get_float_dtype(dtype, graph=G, weight=weight) + if max_level is None or max_level < 0: + max_level = 500 + node_ids, clusters, modularity = plc.leiden( + resource_handle=plc.ResourceHandle(), + random_state=seed, + graph=G._get_plc_graph(weight, 1, dtype), + max_level=max_level, + resolution=resolution, + theta=1, # TODO: expose theta as a backend-only parameter once it's used + do_expensive_check=False, + ) + groups = _groupby(clusters, node_ids, groups_are_canonical=True) + return [set(G._nodearray_to_list(ids)) for ids in groups.values()] diff --git a/nx_cugraph/tests/test_leiden.py b/nx_cugraph/tests/test_leiden.py new file mode 100644 index 000000000..4fae29c3c --- /dev/null +++ b/nx_cugraph/tests/test_leiden.py @@ -0,0 +1,22 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +import nx_cugraph as nxcg + + +def test_leiden_karate(): + # Basic smoke test; if something here changes, we want to know! + G = nxcg.karate_club_graph() + leiden = nxcg.community.leiden_communities(G, seed=123) + louvain = nxcg.community.louvain_communities(G, seed=123) + assert leiden == louvain