forked from rapidsai/cugraph
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
louvain_communities
to cugraph-nx (rapidsai#3803)
See: rapidsai#3773 Possible follow-up tasks: - Update to use threshold parameter exposed from C++ (rapidsai#3792) - Add `max_level` argument to networkx implementation - ~Or, add `max_level` as extra`cugraph_nx`-specific argument~ (**done**) - Update PLC to handle empty graphs gracefully (rapidsai#3804) - Update PLC to handle directed graphs - Add `louvain_partitions` (needs added to PLC) - https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.community.louvain.louvain_partitions.html This is passing many networkx tests. I don't have this as draft, b/c it's usable (and I would argue) mergable as is. Authors: - Erik Welch (https://github.com/eriknw) Approvers: - Rick Ratzel (https://github.com/rlratzel) URL: rapidsai#3803
- Loading branch information
Showing
11 changed files
with
224 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
python/cugraph-nx/cugraph_nx/algorithms/community/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Copyright (c) 2023, 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. | ||
from .louvain import * |
56 changes: 56 additions & 0 deletions
56
python/cugraph-nx/cugraph_nx/algorithms/community/louvain.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Copyright (c) 2023, 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 sys | ||
|
||
import pylibcugraph as plc | ||
|
||
from cugraph_nx.convert import _to_undirected_graph | ||
from cugraph_nx.utils import _groupby, networkx_algorithm, not_implemented_for | ||
|
||
__all__ = ["louvain_communities"] | ||
|
||
|
||
@not_implemented_for("directed") | ||
@networkx_algorithm(extra_params="max_level") | ||
def louvain_communities( | ||
G, weight="weight", resolution=1, threshold=0.0000001, seed=None, *, max_level=None | ||
): | ||
"""`threshold` and `seed` parameters are currently ignored. | ||
Extra parameter: `max_level` controls the maximum number of levels of the algorithm. | ||
""" | ||
# NetworkX allows both directed and undirected, but cugraph only allows undirected. | ||
G = _to_undirected_graph(G, weight) | ||
if G.row_indices.size == 0: | ||
# TODO: PLC doesn't handle empty graphs gracefully! | ||
return [{key} for key in G._nodeiter_to_iter(range(len(G)))] | ||
if max_level is None: | ||
max_level = sys.maxsize | ||
vertices, clusters, modularity = plc.louvain( | ||
resource_handle=plc.ResourceHandle(), | ||
graph=G._get_plc_graph(), | ||
max_level=max_level, # TODO: add this parameter to NetworkX | ||
resolution=resolution, | ||
# threshold=threshold, # TODO: add this parameter to PLC | ||
do_expensive_check=False, | ||
) | ||
groups = _groupby(clusters, vertices) | ||
return [set(G._nodearray_to_list(node_ids)) for node_ids in groups.values()] | ||
|
||
|
||
@louvain_communities._can_run | ||
def _( | ||
G, weight="weight", resolution=1, threshold=0.0000001, seed=None, *, max_level=None | ||
): | ||
# NetworkX allows both directed and undirected, but cugraph only allows undirected. | ||
return not G.is_directed() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# Copyright (c) 2023, 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 cupy as cp | ||
|
||
__all__ = ["_groupby"] | ||
|
||
|
||
def _groupby(groups: cp.ndarray, values: cp.ndarray) -> dict[int, cp.ndarray]: | ||
"""Perform a groupby operation given an array of group IDs and array of values. | ||
Parameters | ||
---------- | ||
groups : cp.ndarray | ||
Array that holds the group IDs. | ||
Group IDs are assumed to be consecutive integers from 0. | ||
values : cp.ndarray | ||
Array of values to be grouped according to groups. | ||
Must be the same size as groups array. | ||
Returns | ||
------- | ||
dict with group IDs as keys and cp.ndarray as values. | ||
""" | ||
# It would actually be easy to support groups that aren't consecutive integers, | ||
# but let's wait until we need it to implement it. | ||
sorted_groups = cp.argsort(groups) | ||
sorted_values = values[sorted_groups] | ||
rv = {} | ||
start = 0 | ||
for i, end in enumerate( | ||
[*(cp.nonzero(cp.diff(groups[sorted_groups]))[0] + 1).tolist(), groups.size] | ||
): | ||
rv[i] = sorted_values[start:end] | ||
start = end | ||
return rv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters