From 41d62bc995230a00bc826267a4615388f31c1047 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Thu, 23 May 2024 09:27:51 -0700 Subject: [PATCH 01/23] update docstring --- python/cugraph/cugraph/community/ktruss_subgraph.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/cugraph/cugraph/community/ktruss_subgraph.py b/python/cugraph/cugraph/community/ktruss_subgraph.py index 1799c50252f..625054b4cbb 100644 --- a/python/cugraph/cugraph/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/community/ktruss_subgraph.py @@ -58,8 +58,6 @@ def k_truss( """ Returns the K-Truss subgraph of a graph for a specific k. - NOTE: this function is currently not available on CUDA 11.4 systems. - The k-truss of a graph is a subgraph where each edge is part of at least (k−2) triangles. K-trusses are used for finding tighlty knit groups of vertices in a graph. A k-truss is a relaxation of a k-clique in the graph From 6ccfac3eb3cc96976aed9cf8ba14191c5d065718 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Thu, 23 May 2024 09:34:31 -0700 Subject: [PATCH 02/23] update docstring --- .../cugraph/community/ktruss_subgraph.py | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/python/cugraph/cugraph/community/ktruss_subgraph.py b/python/cugraph/cugraph/community/ktruss_subgraph.py index 625054b4cbb..c92d0d94deb 100644 --- a/python/cugraph/cugraph/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/community/ktruss_subgraph.py @@ -34,24 +34,6 @@ networkx = import_optional("networkx") -# FIXME: special case for ktruss on CUDA 11.4: an 11.4 bug causes ktruss to -# crash in that environment. Allow ktruss to import on non-11.4 systems, but -# raise an exception if ktruss is directly imported on 11.4. -def _ensure_compatible_cuda_version(): - try: - cuda_version = cuda.runtime.get_version() - except cuda.cudadrv.runtime.CudaRuntimeAPIError: - cuda_version = "n/a" - - unsupported_cuda_version = (11, 4) - - if cuda_version == unsupported_cuda_version: - ver_string = ".".join([str(n) for n in unsupported_cuda_version]) - raise NotImplementedError( - "k_truss is not currently supported in CUDA" f" {ver_string} environments." - ) - - def k_truss( G: Union[Graph, "networkx.Graph"], k: int ) -> Union[Graph, "networkx.Graph"]: @@ -87,9 +69,6 @@ def k_truss( >>> k_subgraph = cugraph.k_truss(G, 3) """ - - _ensure_compatible_cuda_version() - G, isNx = ensure_cugraph_obj_for_nx(G) if isNx is True: @@ -175,8 +154,6 @@ def ktruss_subgraph( >>> k_subgraph = cugraph.ktruss_subgraph(G, 3, use_weights=False) """ - _ensure_compatible_cuda_version() - KTrussSubgraph = Graph() if G.is_directed(): raise ValueError("input graph must be undirected") From 4e33a25e4de3bd20bb1daf9284df1b972fdf155a Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Thu, 23 May 2024 09:37:43 -0700 Subject: [PATCH 03/23] add mg implementation of K-Truss --- python/cugraph/cugraph/dask/__init__.py | 1 + .../cugraph/dask/community/__init__.py | 1 + .../cugraph/dask/community/ktruss_subgraph.py | 115 ++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 python/cugraph/cugraph/dask/community/ktruss_subgraph.py diff --git a/python/cugraph/cugraph/dask/__init__.py b/python/cugraph/cugraph/dask/__init__.py index a6958aaaf49..c533e9ae53f 100644 --- a/python/cugraph/cugraph/dask/__init__.py +++ b/python/cugraph/cugraph/dask/__init__.py @@ -21,6 +21,7 @@ from .community.triangle_count import triangle_count from .community.egonet import ego_graph from .community.induced_subgraph import induced_subgraph +from .community.ktruss_subgraph import ktruss_subgraph from .centrality.katz_centrality import katz_centrality from .components.connectivity import weakly_connected_components from .sampling.uniform_neighbor_sample import uniform_neighbor_sample diff --git a/python/cugraph/cugraph/dask/community/__init__.py b/python/cugraph/cugraph/dask/community/__init__.py index 657d9df101b..9acf08c337c 100644 --- a/python/cugraph/cugraph/dask/community/__init__.py +++ b/python/cugraph/cugraph/dask/community/__init__.py @@ -15,3 +15,4 @@ from .triangle_count import triangle_count from .induced_subgraph import induced_subgraph from .leiden import leiden +from .ktruss_subgraph import ktruss_subgraph diff --git a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py new file mode 100644 index 00000000000..63ff509624e --- /dev/null +++ b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py @@ -0,0 +1,115 @@ +# Copyright (c) 2022-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 dask.distributed import wait, default_client + +import cugraph.dask.comms.comms as Comms +import dask_cudf +import cudf +import cupy as cp + +from pylibcugraph import ResourceHandle, k_truss_subgraph as pylibcugraph_k_truss_subgraph + + +def _call_k_truss_subgraph( + sID, + mg_graph_x, + k, + do_expensive_check, +): + + return pylibcugraph_k_truss_subgraph( + resource_handle=ResourceHandle(Comms.get_handle(sID).getHandle()), + graph=mg_graph_x, + k=k, + do_expensive_check=do_expensive_check, + ) + + +def convert_to_cudf(cp_arrays: cp.ndarray) -> cudf.DataFrame: + cp_src, cp_dst, cp_weight = cp_arrays + + df = cudf.DataFrame() + df["src"] = cp_src + df["dst"] = cp_dst + if cp_weight is not None: + df["weight"] = cp_weight + + + return df + + +def k_truss_subgraph(input_graph, k: int) -> dask_cudf.DataFrame: + """ + Returns the K-Truss subgraph of a graph for a specific k. + + The k-truss of a graph is a subgraph where each edge is part of at least + (k−2) triangles. K-trusses are used for finding tighlty knit groups of + vertices in a graph. A k-truss is a relaxation of a k-clique in the graph + and was define in [1]. Finding cliques is computationally demanding and + finding the maximal k-clique is known to be NP-Hard. + + Parameters + ---------- + G : cuGraph.Graph or networkx.Graph + cuGraph graph descriptor with connectivity information. k-Trusses are + defined for only undirected graphs as they are defined for + undirected triangle in a graph. + + k : int + The desired k to be used for extracting the k-truss subgraph. + + + Returns + ------- + k_truss_edge_lists : dask_cudf.DataFrame + Distributed GPU data frame containing all sources identifiers, + destination identifiers, edge weights belonging to the Truss + """ + if input_graph.is_directed(): + raise ValueError("input graph must be undirected") + # Initialize dask client + client = default_client() + + do_expensive_check = False + + result = [ + client.submit( + _call_k_truss_subgraph, + Comms.get_session_id(), + input_graph._plc_graph[w], + k, + do_expensive_check, + workers=[w], + allow_other_workers=False, + ) + for w in Comms.get_workers() + ] + wait(result) + + cudf_result = [client.submit(convert_to_cudf, cp_arrays) for cp_arrays in result] + + wait(cudf_result) + + ddf = dask_cudf.from_delayed(cudf_result).persist() + wait(ddf) + # Wait until the inactive futures are released + wait([(r.release(), c_r.release()) for r, c_r in zip(result, cudf_result)]) + + if input_graph.renumbered: + ddf = input_graph.unrenumber(ddf, "src") + ddf = input_graph.unrenumber(ddf, "dst") + + return ddf From ab143fb2af56bf124e4f91ae35e41a6c39624d48 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Thu, 23 May 2024 09:38:04 -0700 Subject: [PATCH 04/23] update docstrings --- python/pylibcugraph/pylibcugraph/k_truss_subgraph.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pylibcugraph/pylibcugraph/k_truss_subgraph.pyx b/python/pylibcugraph/pylibcugraph/k_truss_subgraph.pyx index 6e4cd2e282a..9ea533c9f28 100644 --- a/python/pylibcugraph/pylibcugraph/k_truss_subgraph.pyx +++ b/python/pylibcugraph/pylibcugraph/k_truss_subgraph.pyx @@ -65,7 +65,7 @@ def k_truss_subgraph(ResourceHandle resource_handle, Handle to the underlying device resources needed for referencing data and running algorithms. - graph : SGGraph + graph : SGGraph or MGGraph The input graph. k: size_t From 50ba897f4ef1ccf8d47c751c7b320d575182054c Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Thu, 23 May 2024 09:39:21 -0700 Subject: [PATCH 05/23] update docstrings --- python/cugraph/cugraph/dask/community/ktruss_subgraph.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py index 63ff509624e..b79b07c23ab 100644 --- a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py @@ -63,10 +63,10 @@ def k_truss_subgraph(input_graph, k: int) -> dask_cudf.DataFrame: Parameters ---------- - G : cuGraph.Graph or networkx.Graph - cuGraph graph descriptor with connectivity information. k-Trusses are - defined for only undirected graphs as they are defined for - undirected triangle in a graph. + input_graph : cugraph.Graph + Graph or matrix object, which should contain the connectivity + information. Edge weights, if present, should be single or double + precision floating point values k : int The desired k to be used for extracting the k-truss subgraph. From 9a1cb679b93324714b1f113fc006bfa03feb6a49 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Thu, 23 May 2024 09:41:51 -0700 Subject: [PATCH 06/23] add type annotation --- python/cugraph/cugraph/dask/community/ktruss_subgraph.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py index b79b07c23ab..4a6b7fc3c2d 100644 --- a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py @@ -19,16 +19,17 @@ import dask_cudf import cudf import cupy as cp +from typing import Tuple from pylibcugraph import ResourceHandle, k_truss_subgraph as pylibcugraph_k_truss_subgraph def _call_k_truss_subgraph( - sID, + sID: bytes, mg_graph_x, - k, - do_expensive_check, -): + k: int, + do_expensive_check: bool, +) -> Tuple[cp.ndarray, cp.ndarray, cp.ndarray]: return pylibcugraph_k_truss_subgraph( resource_handle=ResourceHandle(Comms.get_handle(sID).getHandle()), From bbeece97b1c597bfa99b0f12a1aae7861f035b8e Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Thu, 23 May 2024 09:42:24 -0700 Subject: [PATCH 07/23] fix style --- python/cugraph/cugraph/dask/community/ktruss_subgraph.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py index 4a6b7fc3c2d..2b137fabea1 100644 --- a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py @@ -48,7 +48,6 @@ def convert_to_cudf(cp_arrays: cp.ndarray) -> cudf.DataFrame: if cp_weight is not None: df["weight"] = cp_weight - return df From d4c45758466c4e8582628225c1bb30c2e01a2d34 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Thu, 23 May 2024 10:18:12 -0700 Subject: [PATCH 08/23] add tests for mg k-truss --- .../community/test_k_truss_subgraph_mg.py | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py diff --git a/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py b/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py new file mode 100644 index 00000000000..7ec5b93d9e7 --- /dev/null +++ b/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py @@ -0,0 +1,109 @@ +# Copyright (c) 2022-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 gc + +import pytest + +import cugraph +import cugraph.dask as dcg +from cudf.testing.testing import assert_frame_equal +from cugraph.dask.common.mg_utils import is_single_gpu +from cugraph.datasets import karate, dolphins, email_Eu_core + + +# ============================================================================= +# Pytest Setup / Teardown - called for each test function +# ============================================================================= + + +def setup_function(): + gc.collect() + + +# ============================================================================= +# Parameters +# ============================================================================= + + +DATASETS = [karate, dolphins, email_Eu_core] +IS_DIRECTED = [True, False] +K_VALUE = [4, 6, 8] + + +# ============================================================================= +# Helper functions +# ============================================================================= + + +def get_sg_graph(dataset, directed): + G = dataset.get_graph(create_using=cugraph.Graph(directed=directed)) + + return G + + +def get_mg_graph(dataset, directed): + ddf = dataset.get_dask_edgelist() + dg = cugraph.Graph(directed=directed) + dg.from_dask_cudf_edgelist( + ddf, + source="src", + destination="dst", + edge_attr="wgt", + renumber=True, + store_transposed=True, + ) + + return dg + + +# ============================================================================= +# Tests +# ============================================================================= + + +@pytest.mark.mg +@pytest.mark.skipif(is_single_gpu(), reason="skipping MG testing on Single GPU system") +@pytest.mark.parametrize("dataset", DATASETS) +@pytest.mark.parametrize("is_directed", IS_DIRECTED) +@pytest.mark.parametrize("k", K_VALUE) +def test_mg_k_truss_subgraph( + dask_client, benchmark, dataset, is_directed, k +): + # Create SG and MG Graphs + g = get_sg_graph(dataset, is_directed) + dg = get_mg_graph(dataset, is_directed) + + sg_k_truss_subgraph = cugraph.k_truss_subgraph(g, k=k) + result_k_truss_subgraph = benchmark( + dcg.k_truss_subgraph, + dg, + k + ) + + mg_df = result_k_truss_subgraph + + if len(mg_df) != 0 and len(sg_k_truss_subgraph.input_df) != 0: + # FIXME: 'edges()' or 'view_edgelist()' takes half the edges out if + # 'directed=False'. + sg_result = sg_k_truss_subgraph.input_df + + sg_df = sg_result.sort_values(["src", "dst"]).reset_index(drop=True) + mg_df = mg_df.compute().sort_values(["src", "dst"]).reset_index(drop=True) + + assert_frame_equal(sg_df, mg_df, check_dtype=False, check_like=True) + + else: + # There is no edge left when extracting the K-Truss + assert len(sg_k_truss_subgraph.input_df) == 0 + assert len(mg_df) == 0 From 557f6d120946cd80d1096a99328e9166001981d6 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Thu, 23 May 2024 10:18:41 -0700 Subject: [PATCH 09/23] handle edge case --- python/cugraph/cugraph/dask/community/ktruss_subgraph.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py index 2b137fabea1..5552e932584 100644 --- a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py @@ -43,8 +43,9 @@ def convert_to_cudf(cp_arrays: cp.ndarray) -> cudf.DataFrame: cp_src, cp_dst, cp_weight = cp_arrays df = cudf.DataFrame() - df["src"] = cp_src - df["dst"] = cp_dst + if cp_src is not None: + df["src"] = cp_src + df["dst"] = cp_dst if cp_weight is not None: df["weight"] = cp_weight From dd0ceacda148298948e92fbf16ece7b92451ac6e Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 15 Jul 2024 01:18:40 -0700 Subject: [PATCH 10/23] fix style --- .../cugraph/cugraph/dask/community/ktruss_subgraph.py | 7 +++++-- .../tests/community/test_k_truss_subgraph_mg.py | 10 ++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py index 5552e932584..c0592324e79 100644 --- a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2023, NVIDIA CORPORATION. +# Copyright (c) 2022-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. @@ -21,7 +21,10 @@ import cupy as cp from typing import Tuple -from pylibcugraph import ResourceHandle, k_truss_subgraph as pylibcugraph_k_truss_subgraph +from pylibcugraph import ( + ResourceHandle, + k_truss_subgraph as pylibcugraph_k_truss_subgraph, +) def _call_k_truss_subgraph( diff --git a/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py b/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py index 7ec5b93d9e7..8f47b00074c 100644 --- a/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py +++ b/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py @@ -77,19 +77,13 @@ def get_mg_graph(dataset, directed): @pytest.mark.parametrize("dataset", DATASETS) @pytest.mark.parametrize("is_directed", IS_DIRECTED) @pytest.mark.parametrize("k", K_VALUE) -def test_mg_k_truss_subgraph( - dask_client, benchmark, dataset, is_directed, k -): +def test_mg_k_truss_subgraph(dask_client, benchmark, dataset, is_directed, k): # Create SG and MG Graphs g = get_sg_graph(dataset, is_directed) dg = get_mg_graph(dataset, is_directed) sg_k_truss_subgraph = cugraph.k_truss_subgraph(g, k=k) - result_k_truss_subgraph = benchmark( - dcg.k_truss_subgraph, - dg, - k - ) + result_k_truss_subgraph = benchmark(dcg.k_truss_subgraph, dg, k) mg_df = result_k_truss_subgraph From c3b1bab4d551f49dd3298fd2e1fc3ebebcd7cda5 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Sun, 28 Jul 2024 22:08:34 -0700 Subject: [PATCH 11/23] fix style --- python/cugraph/cugraph/community/ktruss_subgraph.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/cugraph/cugraph/community/ktruss_subgraph.py b/python/cugraph/cugraph/community/ktruss_subgraph.py index c92d0d94deb..18d4840afa7 100644 --- a/python/cugraph/cugraph/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/community/ktruss_subgraph.py @@ -22,7 +22,6 @@ from pylibcugraph import ResourceHandle import warnings -from numba import cuda import cudf from cugraph.utilities.utils import import_optional From 9a865d1a15df4110ed9af89ecbc6b1f35e74de2c Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Sun, 28 Jul 2024 22:14:24 -0700 Subject: [PATCH 12/23] update copyright --- python/cugraph/cugraph/community/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/cugraph/cugraph/community/__init__.py b/python/cugraph/cugraph/community/__init__.py index 78491b383f2..9dc0038908b 100644 --- a/python/cugraph/cugraph/community/__init__.py +++ b/python/cugraph/cugraph/community/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2023, NVIDIA CORPORATION. +# Copyright (c) 2019-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 From 8695e1fd603ebd2193b900dd28a7e6f240dcfd66 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Sun, 28 Jul 2024 22:59:05 -0700 Subject: [PATCH 13/23] update copyright --- python/cugraph/cugraph/dask/community/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/cugraph/cugraph/dask/community/__init__.py b/python/cugraph/cugraph/dask/community/__init__.py index 9acf08c337c..9b5301d0e42 100644 --- a/python/cugraph/cugraph/dask/community/__init__.py +++ b/python/cugraph/cugraph/dask/community/__init__.py @@ -1,4 +1,4 @@ -# 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. # You may obtain a copy of the License at From ef32a63793d3ea8f5b6e20974ee13925c998114f Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 29 Jul 2024 11:15:43 -0700 Subject: [PATCH 14/23] follow PEP8 when ordering imports --- python/cugraph/cugraph/community/ktruss_subgraph.py | 13 ++++++------- .../cugraph/dask/community/ktruss_subgraph.py | 8 ++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/python/cugraph/cugraph/community/ktruss_subgraph.py b/python/cugraph/cugraph/community/ktruss_subgraph.py index 18d4840afa7..9a8100b3fe9 100644 --- a/python/cugraph/cugraph/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/community/ktruss_subgraph.py @@ -11,18 +11,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -from cugraph.structure.graph_classes import Graph from typing import Union + +import warnings +import cudf +from pylibcugraph import k_truss_subgraph as pylibcugraph_k_truss_subgraph +from pylibcugraph import ResourceHandle +from cugraph.structure.graph_classes import Graph from cugraph.utilities import ( ensure_cugraph_obj_for_nx, cugraph_to_nx, ) - -from pylibcugraph import k_truss_subgraph as pylibcugraph_k_truss_subgraph -from pylibcugraph import ResourceHandle -import warnings - -import cudf from cugraph.utilities.utils import import_optional # FIXME: the networkx.Graph type used in the type annotation for diff --git a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py index c0592324e79..fba8dabbc42 100644 --- a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py @@ -13,18 +13,18 @@ # limitations under the License. # -from dask.distributed import wait, default_client +from typing import Tuple -import cugraph.dask.comms.comms as Comms -import dask_cudf import cudf import cupy as cp -from typing import Tuple +from dask.distributed import wait, default_client +import dask_cudf from pylibcugraph import ( ResourceHandle, k_truss_subgraph as pylibcugraph_k_truss_subgraph, ) +import cugraph.dask.comms.comms as Comms def _call_k_truss_subgraph( From 81eee49fc63fcb2c32779eb55d4a8a539ed83c13 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 29 Jul 2024 11:23:46 -0700 Subject: [PATCH 15/23] udpate docstrings --- .../cugraph/cugraph/community/ktruss_subgraph.py | 10 +++++----- .../cugraph/dask/community/ktruss_subgraph.py | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/python/cugraph/cugraph/community/ktruss_subgraph.py b/python/cugraph/cugraph/community/ktruss_subgraph.py index 9a8100b3fe9..9777799a0b1 100644 --- a/python/cugraph/cugraph/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/community/ktruss_subgraph.py @@ -38,11 +38,11 @@ def k_truss( """ Returns the K-Truss subgraph of a graph for a specific k. - The k-truss of a graph is a subgraph where each edge is part of at least - (k−2) triangles. K-trusses are used for finding tighlty knit groups of - vertices in a graph. A k-truss is a relaxation of a k-clique in the graph - and was define in [1]. Finding cliques is computationally demanding and - finding the maximal k-clique is known to be NP-Hard. + The k-truss of a graph is a subgraph where each edge is incident to at + least (k−2) triangles. K-trusses are used for finding tighlty knit groups + of vertices in a graph. A k-truss is a relaxation of a k-clique in the graph. + Finding cliques is computationally demanding and finding the maximal + k-clique is known to be NP-Hard. Parameters ---------- diff --git a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py index fba8dabbc42..4ac1e15db53 100644 --- a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2024, NVIDIA CORPORATION. +# 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. @@ -59,11 +59,11 @@ def k_truss_subgraph(input_graph, k: int) -> dask_cudf.DataFrame: """ Returns the K-Truss subgraph of a graph for a specific k. - The k-truss of a graph is a subgraph where each edge is part of at least - (k−2) triangles. K-trusses are used for finding tighlty knit groups of - vertices in a graph. A k-truss is a relaxation of a k-clique in the graph - and was define in [1]. Finding cliques is computationally demanding and - finding the maximal k-clique is known to be NP-Hard. + The k-truss of a graph is a subgraph where each edge is incident to at + least (k−2) triangles. K-trusses are used for finding tighlty knit groups + of vertices in a graph. A k-truss is a relaxation of a k-clique in the graph. + Finding cliques is computationally demanding and finding the maximal + k-clique is known to be NP-Hard. Parameters ---------- @@ -79,8 +79,8 @@ def k_truss_subgraph(input_graph, k: int) -> dask_cudf.DataFrame: Returns ------- k_truss_edge_lists : dask_cudf.DataFrame - Distributed GPU data frame containing all sources identifiers, - destination identifiers, edge weights belonging to the Truss + Distributed GPU data frame containing all source identifiers, + destination identifiers, and edge weights belonging to the truss """ if input_graph.is_directed(): raise ValueError("input graph must be undirected") From b36320dba14e17b4915226409fa8405e5e012acb Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 29 Jul 2024 13:13:42 -0700 Subject: [PATCH 16/23] remove deprecated parameter --- .../cugraph/cugraph/community/ktruss_subgraph.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/python/cugraph/cugraph/community/ktruss_subgraph.py b/python/cugraph/cugraph/community/ktruss_subgraph.py index 9777799a0b1..c9d91b76280 100644 --- a/python/cugraph/cugraph/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/community/ktruss_subgraph.py @@ -134,12 +134,6 @@ def ktruss_subgraph( k : int The desired k to be used for extracting the k-truss subgraph. - use_weights : bool, optional (default=True) - Whether the output should contain the edge weights if G has them. - - Deprecated: If 'weights' were passed at the graph creation, they will - be used. - Returns ------- G_truss : cuGraph.Graph @@ -156,14 +150,6 @@ def ktruss_subgraph( if G.is_directed(): raise ValueError("input graph must be undirected") - if use_weights: - warning_msg = ( - "The use_weights flag is deprecated " - "and will be removed in the next release. if weights " - "were passed at the graph creation, they will be used." - ) - warnings.warn(warning_msg, FutureWarning) - sources, destinations, edge_weights, _ = pylibcugraph_k_truss_subgraph( resource_handle=ResourceHandle(), graph=G._plc_graph, From 372b812fc378151dd4137e328a0912ca73d5dac7 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 29 Jul 2024 13:16:28 -0700 Subject: [PATCH 17/23] remove outdated tests --- .../tests/community/test_k_truss_subgraph.py | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/python/cugraph/cugraph/tests/community/test_k_truss_subgraph.py b/python/cugraph/cugraph/tests/community/test_k_truss_subgraph.py index 063d7fc735f..bbd2866b5df 100644 --- a/python/cugraph/cugraph/tests/community/test_k_truss_subgraph.py +++ b/python/cugraph/cugraph/tests/community/test_k_truss_subgraph.py @@ -20,7 +20,6 @@ import cugraph from cugraph.testing import utils from cugraph.datasets import polbooks, karate_asymmetric -from numba import cuda # ============================================================================= @@ -67,32 +66,7 @@ def compare_k_truss(k_truss_cugraph, k, ground_truth_file): return True -__cuda_version = cuda.runtime.get_version() -__unsupported_cuda_version = (11, 4) - - -# FIXME: remove when ktruss is supported on CUDA 11.4 -@pytest.mark.sg -def test_unsupported_cuda_version(): - """ - Ensures the proper exception is raised when ktruss is called in an - unsupported env, and not when called in a supported env. - """ - k = 5 - - G = polbooks.get_graph(download=True) - if __cuda_version == __unsupported_cuda_version: - with pytest.raises(NotImplementedError): - cugraph.k_truss(G, k) - else: - cugraph.k_truss(G, k) - - @pytest.mark.sg -@pytest.mark.skipif( - (__cuda_version == __unsupported_cuda_version), - reason="skipping on unsupported CUDA " f"{__unsupported_cuda_version} environment.", -) @pytest.mark.parametrize("_, nx_ground_truth", utils.DATASETS_KTRUSS) def test_ktruss_subgraph_Graph(_, nx_ground_truth): @@ -104,10 +78,6 @@ def test_ktruss_subgraph_Graph(_, nx_ground_truth): @pytest.mark.sg -@pytest.mark.skipif( - (__cuda_version == __unsupported_cuda_version), - reason="skipping on unsupported CUDA " f"{__unsupported_cuda_version} environment.", -) def test_ktruss_subgraph_Graph_nx(): k = 5 dataset_path = polbooks.get_path() @@ -122,10 +92,6 @@ def test_ktruss_subgraph_Graph_nx(): @pytest.mark.sg -@pytest.mark.skipif( - (__cuda_version == __unsupported_cuda_version), - reason="skipping on unsupported CUDA " f"{__unsupported_cuda_version} environment.", -) def test_ktruss_subgraph_directed_Graph(): k = 5 edgevals = True From 9bc610beb36d7bd8c2a7c9b622dbd62ef93bf5d3 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 29 Jul 2024 13:53:25 -0700 Subject: [PATCH 18/23] fix typo --- python/cugraph/cugraph/dask/community/ktruss_subgraph.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py index 4ac1e15db53..5f9d4bc895f 100644 --- a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py @@ -43,7 +43,7 @@ def _call_k_truss_subgraph( def convert_to_cudf(cp_arrays: cp.ndarray) -> cudf.DataFrame: - cp_src, cp_dst, cp_weight = cp_arrays + cp_src, cp_dst, cp_weight, _ = cp_arrays df = cudf.DataFrame() if cp_src is not None: @@ -55,7 +55,7 @@ def convert_to_cudf(cp_arrays: cp.ndarray) -> cudf.DataFrame: return df -def k_truss_subgraph(input_graph, k: int) -> dask_cudf.DataFrame: +def ktruss_subgraph(input_graph, k: int) -> dask_cudf.DataFrame: """ Returns the K-Truss subgraph of a graph for a specific k. From 84efc9e786a0776e5f37d0e571050da71711d302 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 29 Jul 2024 13:54:57 -0700 Subject: [PATCH 19/23] add tests for directed graphs --- .../community/test_k_truss_subgraph_mg.py | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py b/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py index 8f47b00074c..97192e2b109 100644 --- a/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py +++ b/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py @@ -18,8 +18,7 @@ import cugraph import cugraph.dask as dcg from cudf.testing.testing import assert_frame_equal -from cugraph.dask.common.mg_utils import is_single_gpu -from cugraph.datasets import karate, dolphins, email_Eu_core +from cugraph.datasets import karate, dolphins, netscience # ============================================================================= @@ -36,7 +35,7 @@ def setup_function(): # ============================================================================= -DATASETS = [karate, dolphins, email_Eu_core] +DATASETS = [karate, dolphins, netscience] IS_DIRECTED = [True, False] K_VALUE = [4, 6, 8] @@ -73,31 +72,34 @@ def get_mg_graph(dataset, directed): @pytest.mark.mg -@pytest.mark.skipif(is_single_gpu(), reason="skipping MG testing on Single GPU system") @pytest.mark.parametrize("dataset", DATASETS) @pytest.mark.parametrize("is_directed", IS_DIRECTED) @pytest.mark.parametrize("k", K_VALUE) -def test_mg_k_truss_subgraph(dask_client, benchmark, dataset, is_directed, k): +def test_mg_ktruss_subgraph(dask_client, benchmark, dataset, is_directed, k): # Create SG and MG Graphs g = get_sg_graph(dataset, is_directed) dg = get_mg_graph(dataset, is_directed) - sg_k_truss_subgraph = cugraph.k_truss_subgraph(g, k=k) - result_k_truss_subgraph = benchmark(dcg.k_truss_subgraph, dg, k) + if is_directed: + with pytest.raises(ValueError): + result_ktruss_subgraph = benchmark(dcg.ktruss_subgraph, dg, k) + else: + sg_ktruss_subgraph = cugraph.ktruss_subgraph(g, k=k) + result_ktruss_subgraph = benchmark(dcg.ktruss_subgraph, dg, k) - mg_df = result_k_truss_subgraph + mg_df = result_ktruss_subgraph - if len(mg_df) != 0 and len(sg_k_truss_subgraph.input_df) != 0: - # FIXME: 'edges()' or 'view_edgelist()' takes half the edges out if - # 'directed=False'. - sg_result = sg_k_truss_subgraph.input_df + if len(mg_df) != 0 and len(sg_ktruss_subgraph.input_df) != 0: + # FIXME: 'edges()' or 'view_edgelist()' takes half the edges out if + # 'directed=False'. + sg_result = sg_ktruss_subgraph.input_df - sg_df = sg_result.sort_values(["src", "dst"]).reset_index(drop=True) - mg_df = mg_df.compute().sort_values(["src", "dst"]).reset_index(drop=True) + sg_df = sg_result.sort_values(["src", "dst"]).reset_index(drop=True) + mg_df = mg_df.compute().sort_values(["src", "dst"]).reset_index(drop=True) - assert_frame_equal(sg_df, mg_df, check_dtype=False, check_like=True) + assert_frame_equal(sg_df, mg_df, check_dtype=False, check_like=True) - else: - # There is no edge left when extracting the K-Truss - assert len(sg_k_truss_subgraph.input_df) == 0 - assert len(mg_df) == 0 + else: + # There is no edge left when extracting the K-Truss + assert len(sg_ktruss_subgraph.input_df) == 0 + assert len(mg_df) == 0 From 235ab8b7dbe1c86f230a25af11ccc59638f285d3 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 29 Jul 2024 13:56:54 -0700 Subject: [PATCH 20/23] fix style --- python/cugraph/cugraph/community/ktruss_subgraph.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/cugraph/cugraph/community/ktruss_subgraph.py b/python/cugraph/cugraph/community/ktruss_subgraph.py index c9d91b76280..bcf8527e17b 100644 --- a/python/cugraph/cugraph/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/community/ktruss_subgraph.py @@ -13,7 +13,6 @@ from typing import Union -import warnings import cudf from pylibcugraph import k_truss_subgraph as pylibcugraph_k_truss_subgraph from pylibcugraph import ResourceHandle From 10c2a6dd3550a95216cd8ab35d115dfc896bf648 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 29 Jul 2024 14:01:43 -0700 Subject: [PATCH 21/23] update copyright --- .../cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py b/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py index 97192e2b109..12e5146c2de 100644 --- a/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py +++ b/python/cugraph/cugraph/tests/community/test_k_truss_subgraph_mg.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2024, NVIDIA CORPORATION. +# 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 From 5c3ae0adb10085eeff64a608a6914441b61a8e73 Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 29 Jul 2024 14:02:33 -0700 Subject: [PATCH 22/23] fix typo --- python/cugraph/cugraph/dask/community/ktruss_subgraph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py index 5f9d4bc895f..2ecca069ea5 100644 --- a/python/cugraph/cugraph/dask/community/ktruss_subgraph.py +++ b/python/cugraph/cugraph/dask/community/ktruss_subgraph.py @@ -80,7 +80,7 @@ def ktruss_subgraph(input_graph, k: int) -> dask_cudf.DataFrame: ------- k_truss_edge_lists : dask_cudf.DataFrame Distributed GPU data frame containing all source identifiers, - destination identifiers, and edge weights belonging to the truss + destination identifiers, and edge weights belonging to the truss. """ if input_graph.is_directed(): raise ValueError("input graph must be undirected") From b4d64f267773180dd1a76fc6596de4300366b13c Mon Sep 17 00:00:00 2001 From: jnke2016 Date: Mon, 29 Jul 2024 14:07:49 -0700 Subject: [PATCH 23/23] update copyright change --- python/cugraph/cugraph/community/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/cugraph/cugraph/community/__init__.py b/python/cugraph/cugraph/community/__init__.py index 9dc0038908b..78491b383f2 100644 --- a/python/cugraph/cugraph/community/__init__.py +++ b/python/cugraph/cugraph/community/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2024, NVIDIA CORPORATION. +# Copyright (c) 2019-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