Skip to content

Commit

Permalink
Merge branch 'branch-24.02' into is_tree
Browse files Browse the repository at this point in the history
  • Loading branch information
eriknw committed Jan 19, 2024
2 parents 591fd2c + 52ab54f commit 7dbbafc
Show file tree
Hide file tree
Showing 17 changed files with 599 additions and 55 deletions.
6 changes: 3 additions & 3 deletions cpp/include/cugraph/mtmg/resource_manager.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* 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.
Expand Down Expand Up @@ -106,9 +106,9 @@ class resource_manager_t {
auto per_device_it = per_device_rmm_resources_.insert(
std::pair{global_rank, std::make_shared<rmm::mr::cuda_memory_resource>()});
#else
auto const [free, total] = rmm::detail::available_device_memory();
auto const [free, total] = rmm::available_device_memory();
auto const min_alloc =
rmm::detail::align_down(std::min(free, total / 6), rmm::detail::CUDA_ALLOCATION_ALIGNMENT);
rmm::align_down(std::min(free, total / 6), rmm::CUDA_ALLOCATION_ALIGNMENT);

auto per_device_it = per_device_rmm_resources_.insert(
std::pair{global_rank,
Expand Down
7 changes: 3 additions & 4 deletions cpp/tests/utilities/base_fixture.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2023, NVIDIA CORPORATION.
* Copyright (c) 2020-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.
Expand Down Expand Up @@ -73,9 +73,8 @@ inline auto make_pool()
// run more than 2 tests in parallel at the same time. Changes to this value could
// effect the maximum amount of parallel tests, and therefore `tests/CMakeLists.txt`
// `_CUGRAPH_TEST_PERCENT` default value will need to be audited.
auto const [free, total] = rmm::detail::available_device_memory();
auto const min_alloc =
rmm::detail::align_down(std::min(free, total / 6), rmm::detail::CUDA_ALLOCATION_ALIGNMENT);
auto const [free, total] = rmm::available_device_memory();
auto const min_alloc = rmm::align_down(std::min(free, total / 6), rmm::CUDA_ALLOCATION_ALIGNMENT);
return rmm::mr::make_owning_wrapper<rmm::mr::pool_memory_resource>(make_cuda(), min_alloc);
}

Expand Down
10 changes: 10 additions & 0 deletions python/nx-cugraph/_nx_cugraph/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"functions": {
# BEGIN: functions
"ancestors",
"average_clustering",
"barbell_graph",
"betweenness_centrality",
"bfs_edges",
Expand All @@ -41,6 +42,7 @@
"caveman_graph",
"chvatal_graph",
"circular_ladder_graph",
"clustering",
"complete_bipartite_graph",
"complete_graph",
"complete_multipartite_graph",
Expand Down Expand Up @@ -69,6 +71,7 @@
"icosahedral_graph",
"in_degree_centrality",
"is_arborescence",
"is_bipartite",
"is_branching",
"is_connected",
"is_forest",
Expand All @@ -95,17 +98,21 @@
"number_weakly_connected_components",
"octahedral_graph",
"out_degree_centrality",
"overall_reciprocity",
"pagerank",
"pappus_graph",
"path_graph",
"petersen_graph",
"reciprocity",
"sedgewick_maze_graph",
"single_source_shortest_path_length",
"single_target_shortest_path_length",
"star_graph",
"strongly_connected_components",
"tadpole_graph",
"tetrahedral_graph",
"transitivity",
"triangles",
"trivial_graph",
"truncated_cube_graph",
"truncated_tetrahedron_graph",
Expand All @@ -117,11 +124,13 @@
},
"extra_docstrings": {
# BEGIN: extra_docstrings
"average_clustering": "Directed graphs and `weight` parameter are not yet 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.",
"bfs_successors": "`sort_neighbors` parameter is not yet supported.",
"bfs_tree": "`sort_neighbors` parameter is not yet supported.",
"clustering": "Directed graphs and `weight` parameter are not yet supported.",
"edge_betweenness_centrality": "`weight` parameter is not yet supported, and RNG with seed may be different.",
"eigenvector_centrality": "`nstart` parameter is not used, but it is checked for validity.",
"from_pandas_edgelist": "cudf.DataFrame inputs also supported; value columns with str is unsuppported.",
Expand All @@ -133,6 +142,7 @@
"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.",
"transitivity": "Directed graphs are not yet supported.",
# END: extra_docstrings
},
"extra_parameters": {
Expand Down
14 changes: 7 additions & 7 deletions python/nx-cugraph/lint.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023, NVIDIA CORPORATION.
# Copyright (c) 2023-2024, NVIDIA CORPORATION.
#
# https://pre-commit.com/
#
Expand Down Expand Up @@ -36,7 +36,7 @@ repos:
- id: autoflake
args: [--in-place]
- repo: https://github.com/pycqa/isort
rev: 5.12.0
rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/asottile/pyupgrade
Expand All @@ -45,23 +45,23 @@ repos:
- id: pyupgrade
args: [--py39-plus]
- repo: https://github.com/psf/black
rev: 23.11.0
rev: 23.12.1
hooks:
- id: black
# - id: black-jupyter
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.7
rev: v0.1.13
hooks:
- id: ruff
args: [--fix-only, --show-fixes] # --unsafe-fixes]
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
rev: 7.0.0
hooks:
- id: flake8
args: ['--per-file-ignores=_nx_cugraph/__init__.py:E501', '--extend-ignore=SIM105'] # Why is this necessary?
additional_dependencies: &flake8_dependencies
# These versions need updated manually
- flake8==6.1.0
- flake8==7.0.0
- flake8-bugbear==23.12.2
- flake8-simplify==0.21.0
- repo: https://github.com/asottile/yesqa
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.1.7
rev: v0.1.13
hooks:
- id: ruff
- repo: https://github.com/pre-commit/pre-commit-hooks
Expand Down
5 changes: 4 additions & 1 deletion python/nx-cugraph/nx_cugraph/algorithms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,23 @@
from . import (
bipartite,
centrality,
cluster,
community,
components,
link_analysis,
shortest_paths,
traversal,
tree,
)
from .bipartite import complete_bipartite_graph
from .bipartite import complete_bipartite_graph, is_bipartite
from .centrality import *
from .cluster import *
from .components import *
from .core import *
from .dag import *
from .isolate import *
from .link_analysis import *
from .reciprocity import *
from .shortest_paths import *
from .traversal import *
from .tree.recognition import *
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 .basic import *
from .generators import *
31 changes: 31 additions & 0 deletions python/nx-cugraph/nx_cugraph/algorithms/bipartite/basic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 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 cupy as cp

from nx_cugraph.algorithms.cluster import _triangles
from nx_cugraph.convert import _to_graph
from nx_cugraph.utils import networkx_algorithm

__all__ = [
"is_bipartite",
]


@networkx_algorithm(plc="triangle_count", version_added="24.02")
def is_bipartite(G):
G = _to_graph(G)
# Counting triangles may not be the fastest way to do this, but it is simple.
node_ids, triangles, is_single_node = _triangles(
G, None, symmetrize="union" if G.is_directed() else None
)
return int(cp.count_nonzero(triangles)) == 0
136 changes: 136 additions & 0 deletions python/nx-cugraph/nx_cugraph/algorithms/cluster.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# 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 cupy as cp
import pylibcugraph as plc

from nx_cugraph.convert import _to_undirected_graph
from nx_cugraph.utils import networkx_algorithm, not_implemented_for

__all__ = [
"triangles",
"average_clustering",
"clustering",
"transitivity",
]


def _triangles(G, nodes, symmetrize=None):
if nodes is not None:
if is_single_node := (nodes in G):
nodes = [nodes if G.key_to_id is None else G.key_to_id[nodes]]
else:
nodes = list(nodes)
nodes = G._list_to_nodearray(nodes)
else:
is_single_node = False
if len(G) == 0:
return None, None, is_single_node
node_ids, triangles = plc.triangle_count(
resource_handle=plc.ResourceHandle(),
graph=G._get_plc_graph(symmetrize=symmetrize),
start_list=nodes,
do_expensive_check=False,
)
return node_ids, triangles, is_single_node


@not_implemented_for("directed")
@networkx_algorithm(plc="triangle_count", version_added="24.02")
def triangles(G, nodes=None):
G = _to_undirected_graph(G)
node_ids, triangles, is_single_node = _triangles(G, nodes)
if len(G) == 0:
return {}
if is_single_node:
return int(triangles[0])
return G._nodearrays_to_dict(node_ids, triangles)


@not_implemented_for("directed")
@networkx_algorithm(is_incomplete=True, plc="triangle_count", version_added="24.02")
def clustering(G, nodes=None, weight=None):
"""Directed graphs and `weight` parameter are not yet supported."""
G = _to_undirected_graph(G)
node_ids, triangles, is_single_node = _triangles(G, nodes)
if len(G) == 0:
return {}
if is_single_node:
numer = int(triangles[0])
if numer == 0:
return 0
degree = int((G.src_indices == nodes).sum())
return 2 * numer / (degree * (degree - 1))
degrees = G._degrees_array(ignore_selfloops=True)[node_ids]
denom = degrees * (degrees - 1)
results = 2 * triangles / denom
results = cp.where(denom, results, 0) # 0 where we divided by 0
return G._nodearrays_to_dict(node_ids, results)


@clustering._can_run
def _(G, nodes=None, weight=None):
return weight is None and not G.is_directed()


@not_implemented_for("directed")
@networkx_algorithm(is_incomplete=True, plc="triangle_count", version_added="24.02")
def average_clustering(G, nodes=None, weight=None, count_zeros=True):
"""Directed graphs and `weight` parameter are not yet supported."""
G = _to_undirected_graph(G)
node_ids, triangles, is_single_node = _triangles(G, nodes)
if len(G) == 0:
raise ZeroDivisionError
degrees = G._degrees_array(ignore_selfloops=True)[node_ids]
if not count_zeros:
mask = triangles != 0
triangles = triangles[mask]
if triangles.size == 0:
raise ZeroDivisionError
degrees = degrees[mask]
denom = degrees * (degrees - 1)
results = 2 * triangles / denom
if count_zeros:
results = cp.where(denom, results, 0) # 0 where we divided by 0
return float(results.mean())


@average_clustering._can_run
def _(G, nodes=None, weight=None, count_zeros=True):
return weight is None and not G.is_directed()


@not_implemented_for("directed")
@networkx_algorithm(is_incomplete=True, plc="triangle_count", version_added="24.02")
def transitivity(G):
"""Directed graphs are not yet supported."""
G = _to_undirected_graph(G)
if len(G) == 0:
return 0
node_ids, triangles = plc.triangle_count(
resource_handle=plc.ResourceHandle(),
graph=G._get_plc_graph(),
start_list=None,
do_expensive_check=False,
)
numer = int(triangles.sum())
if numer == 0:
return 0
degrees = G._degrees_array(ignore_selfloops=True)[node_ids]
denom = int((degrees * (degrees - 1)).sum())
return 2 * numer / denom


@transitivity._can_run
def _(G):
# Is transitivity supposed to work on directed graphs?
return not G.is_directed()
Loading

0 comments on commit 7dbbafc

Please sign in to comment.