diff --git a/benchmarks/cugraph/pytest-based/bench_algos.py b/benchmarks/cugraph/pytest-based/bench_algos.py index 457906eed12..ae5f2e225b3 100644 --- a/benchmarks/cugraph/pytest-based/bench_algos.py +++ b/benchmarks/cugraph/pytest-based/bench_algos.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION. +# SPDX-FileCopyrightText: Copyright (c) 2020-2026, NVIDIA CORPORATION. # SPDX-License-Identifier: Apache-2.0 import pytest @@ -197,31 +197,31 @@ def dataset(request, rmm_config): @pytest.fixture(scope="module") def edgelist(request, dataset): df = dataset.get_edgelist() - return df + yield df @pytest.fixture(scope="module") def graph(request, dataset): G = dataset.get_graph() - return G + yield G @pytest.fixture(scope="module") def unweighted_graph(request, dataset): G = dataset.get_graph(ignore_weights=True) - return G + yield G @pytest.fixture(scope="module") def directed_graph(request, dataset): G = dataset.get_graph(create_using=cugraph.Graph(directed=True)) - return G + yield G @pytest.fixture(scope="module") def transposed_graph(request, dataset): G = dataset.get_graph(store_transposed=True) - return G + yield G ############################################################################### diff --git a/conda/environments/all_cuda-129_arch-aarch64.yaml b/conda/environments/all_cuda-129_arch-aarch64.yaml index 02b6ba3c826..71632215415 100644 --- a/conda/environments/all_cuda-129_arch-aarch64.yaml +++ b/conda/environments/all_cuda-129_arch-aarch64.yaml @@ -55,7 +55,6 @@ dependencies: - pytest-benchmark - pytest-cov - pytest-xdist -- python-louvain - pytorch>=2.4.1 - raft-dask==26.6.*,>=0.0.0a0 - rapids-build-backend>=0.4.0,<0.5.0 diff --git a/conda/environments/all_cuda-129_arch-x86_64.yaml b/conda/environments/all_cuda-129_arch-x86_64.yaml index 8259a6b0922..9a6a15d5f26 100644 --- a/conda/environments/all_cuda-129_arch-x86_64.yaml +++ b/conda/environments/all_cuda-129_arch-x86_64.yaml @@ -55,7 +55,6 @@ dependencies: - pytest-benchmark - pytest-cov - pytest-xdist -- python-louvain - pytorch>=2.4.1 - raft-dask==26.6.*,>=0.0.0a0 - rapids-build-backend>=0.4.0,<0.5.0 diff --git a/conda/environments/all_cuda-131_arch-aarch64.yaml b/conda/environments/all_cuda-131_arch-aarch64.yaml index 8fdc36ae59e..b6eb6265579 100644 --- a/conda/environments/all_cuda-131_arch-aarch64.yaml +++ b/conda/environments/all_cuda-131_arch-aarch64.yaml @@ -55,7 +55,6 @@ dependencies: - pytest-benchmark - pytest-cov - pytest-xdist -- python-louvain - pytorch>=2.4.1 - raft-dask==26.6.*,>=0.0.0a0 - rapids-build-backend>=0.4.0,<0.5.0 diff --git a/conda/environments/all_cuda-131_arch-x86_64.yaml b/conda/environments/all_cuda-131_arch-x86_64.yaml index e453bf42040..3c32269e95f 100644 --- a/conda/environments/all_cuda-131_arch-x86_64.yaml +++ b/conda/environments/all_cuda-131_arch-x86_64.yaml @@ -55,7 +55,6 @@ dependencies: - pytest-benchmark - pytest-cov - pytest-xdist -- python-louvain - pytorch>=2.4.1 - raft-dask==26.6.*,>=0.0.0a0 - rapids-build-backend>=0.4.0,<0.5.0 diff --git a/dependencies.yaml b/dependencies.yaml index 4d49ccbdf4f..bf40451cd29 100755 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -495,7 +495,6 @@ dependencies: - networkx>=2.5.1 - *numpy - packaging - - python-louvain - scikit-learn>=0.23.1 test_python_pylibcugraph: common: diff --git a/python/cugraph/cugraph/tests/centrality/test_batch_betweenness_centrality_mg.py b/python/cugraph/cugraph/tests/centrality/test_batch_betweenness_centrality_mg.py deleted file mode 100644 index 4dc2f0c2218..00000000000 --- a/python/cugraph/cugraph/tests/centrality/test_batch_betweenness_centrality_mg.py +++ /dev/null @@ -1,83 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2021-2025, NVIDIA CORPORATION. -# SPDX-License-Identifier: Apache-2.0 - -import gc - -import pytest -import numpy as np - -from cugraph.dask.common.mg_utils import is_single_gpu -from cugraph.datasets import karate - -from test_betweenness_centrality import ( - calc_betweenness_centrality, - compare_scores, -) - -# ============================================================================= -# Parameters -# ============================================================================= -DATASETS = [karate] -DEFAULT_EPSILON = 0.0001 -IS_DIRECTED = [False, True] -ENDPOINTS = [False, True] -IS_NORMALIZED = [False, True] -RESULT_DTYPES = [np.float64] -SUBSET_SIZES = [4, None] -SUBSET_SEEDS = [42] -IS_WEIGHTED = [False, True] - - -# ============================================================================= -# Pytest Setup / Teardown - called for each test function -# ============================================================================= - - -def setup_function(): - gc.collect() - - -# ============================================================================= -# Tests -# ============================================================================= - - -@pytest.mark.mg -@pytest.mark.requires_nx(min_ver="3.5") -@pytest.mark.skipif(is_single_gpu(), reason="skipping MG testing on Single GPU system") -@pytest.mark.parametrize("dataset", DATASETS) -@pytest.mark.parametrize("directed", IS_DIRECTED) -@pytest.mark.parametrize("subset_size", SUBSET_SIZES) -@pytest.mark.parametrize("normalized", IS_NORMALIZED) -@pytest.mark.parametrize("weight", [None]) -@pytest.mark.parametrize("endpoints", ENDPOINTS) -@pytest.mark.parametrize("subset_seed", SUBSET_SEEDS) -@pytest.mark.parametrize("result_dtype", RESULT_DTYPES) -def test_mg_betweenness_centrality( - dataset, - directed, - subset_size, - normalized, - weight, - endpoints, - subset_seed, - result_dtype, - dask_client, -): - sorted_df = calc_betweenness_centrality( - dataset, - directed=directed, - normalized=normalized, - k=subset_size, - weight=weight, - endpoints=endpoints, - seed=subset_seed, - result_dtype=result_dtype, - multi_gpu_batch=True, - ) - compare_scores( - sorted_df, - first_key="cu_bc", - second_key="ref_bc", - epsilon=DEFAULT_EPSILON, - ) diff --git a/python/cugraph/cugraph/tests/centrality/test_batch_edge_betweenness_centrality_mg.py b/python/cugraph/cugraph/tests/centrality/test_batch_edge_betweenness_centrality_mg.py deleted file mode 100644 index de896c1fe1c..00000000000 --- a/python/cugraph/cugraph/tests/centrality/test_batch_edge_betweenness_centrality_mg.py +++ /dev/null @@ -1,74 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2019-2025, NVIDIA CORPORATION. -# SPDX-License-Identifier: Apache-2.0 - -import gc - -import pytest -import numpy as np - -from cugraph.dask.common.mg_utils import is_single_gpu -from cugraph.datasets import karate, netscience - -from test_edge_betweenness_centrality import ( - calc_edge_betweenness_centrality, - compare_scores, -) - -# ============================================================================= -# Parameters -# ============================================================================= -DATASETS = [karate, netscience] -IS_DIRECTED = [True, False] -IS_NORMALIZED = [True, False] -DEFAULT_EPSILON = 0.0001 -SUBSET_SIZES = [4, None] -RESULT_DTYPES = [np.float32, np.float64] - - -# ============================================================================= -# Pytest Setup / Teardown - called for each test function -# ============================================================================= - - -def setup_function(): - gc.collect() - - -# ============================================================================= -# Tests -# ============================================================================= - - -# FIXME: Fails for directed = False(bc score twice as much) and normalized = True. -@pytest.mark.mg -@pytest.mark.requires_nx(min_ver="3.5") -@pytest.mark.skipif(is_single_gpu(), reason="skipping MG testing on Single GPU system") -@pytest.mark.parametrize("dataset", DATASETS) -@pytest.mark.parametrize("directed", IS_DIRECTED) -@pytest.mark.parametrize("subset_size", SUBSET_SIZES) -@pytest.mark.parametrize("normalized", IS_NORMALIZED) -@pytest.mark.parametrize("result_dtype", RESULT_DTYPES) -def test_mg_edge_betweenness_centrality( - dataset, - directed, - subset_size, - normalized, - result_dtype, - dask_client, -): - sorted_df = calc_edge_betweenness_centrality( - dataset, - directed=directed, - normalized=normalized, - k=subset_size, - weight=None, - seed=42, - result_dtype=result_dtype, - multi_gpu_batch=True, - ) - compare_scores( - sorted_df, - first_key="cu_bc", - second_key="ref_bc", - epsilon=DEFAULT_EPSILON, - ) diff --git a/python/cugraph/cugraph/tests/community/test_louvain.py b/python/cugraph/cugraph/tests/community/test_louvain.py index 41fc3fe04f1..f12ae837caa 100644 --- a/python/cugraph/cugraph/tests/community/test_louvain.py +++ b/python/cugraph/cugraph/tests/community/test_louvain.py @@ -1,31 +1,17 @@ -# SPDX-FileCopyrightText: Copyright (c) 2019-2025, NVIDIA CORPORATION. +# SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION. # SPDX-License-Identifier: Apache-2.0 import gc import pytest -import networkx as nx import cugraph import cupyx import cudf -from cugraph.testing import utils, UNDIRECTED_DATASETS +from cugraph.testing import UNDIRECTED_DATASETS from cugraph.datasets import karate_asymmetric -try: - import community -except ModuleNotFoundError: - pytest.exit( - "community module not found\n" - "The python-louvain module needs to be installed\n" - "please run `pip install python-louvain`" - ) - - -print("Networkx version : {} ".format(nx.__version__)) - - # ============================================================================= # Pytest Setup / Teardown - called for each test function # ============================================================================= @@ -42,40 +28,16 @@ def cugraph_call(graph_file, edgevals=False, directed=False): return parts, mod -def networkx_call(M): - # z = {k: 1.0/M.shape[0] for k in range(M.shape[0])} - Gnx = nx.from_pandas_edgelist( - M, source="0", target="1", edge_attr="weight", create_using=nx.Graph() - ) - parts = community.best_partition(Gnx) - - return parts - - +# The goal is to just test that the code runs and returns a result. +# The C/C++ test perform a check for accuracy, but the python test +# is not designed to be a 1:1 comparison with the C/C++ test. @pytest.mark.sg @pytest.mark.parametrize("graph_file", UNDIRECTED_DATASETS) def test_louvain(graph_file): - dataset_path = graph_file.get_path() - M = utils.read_csv_for_nx(dataset_path) cu_parts, cu_mod = cugraph_call(graph_file, edgevals=True) - nx_parts = networkx_call(M) - - # Calculating modularity scores for comparison - Gnx = nx.from_pandas_edgelist( - M, source="0", target="1", edge_attr="weight", create_using=nx.Graph() - ) - - cu_parts = cu_parts.to_pandas() - cu_map = dict(zip(cu_parts["vertex"], cu_parts["partition"])) - - assert set(nx_parts.keys()) == set(cu_map.keys()) - - cu_mod_nx = community.modularity(cu_map, Gnx) - nx_mod = community.modularity(nx_parts, Gnx) - assert len(cu_parts) == len(nx_parts) - assert cu_mod > (0.82 * nx_mod) - assert abs(cu_mod - cu_mod_nx) < 0.0001 + assert len(cu_parts) > 0 + assert cu_mod > 0.0 @pytest.mark.sg diff --git a/python/cugraph/cugraph/tests/sampling/test_egonet_mg.py b/python/cugraph/cugraph/tests/sampling/test_egonet_mg.py index 480b5f6c76f..a3c419bbd1f 100644 --- a/python/cugraph/cugraph/tests/sampling/test_egonet_mg.py +++ b/python/cugraph/cugraph/tests/sampling/test_egonet_mg.py @@ -1,10 +1,11 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022-2025, NVIDIA CORPORATION. +# SPDX-FileCopyrightText: Copyright (c) 2022-2026, NVIDIA CORPORATION. # SPDX-License-Identifier: Apache-2.0 import gc import pytest +import cudf import cugraph import dask_cudf import cugraph.dask as dcg @@ -12,7 +13,8 @@ from cugraph.dask.common.mg_utils import is_single_gpu from pylibcugraph.testing import gen_fixture_params_product from cudf.testing.testing import assert_frame_equal, assert_series_equal - +from pylibcugraph import ego_graph as pylibcugraph_ego_graph +from pylibcugraph import ResourceHandle # ============================================================================= # Pytest Setup / Teardown - called for each test function @@ -70,13 +72,46 @@ def input_expected_output(input_combo): input_data_path, directed=directed, edgevals=True ) - sg_cugraph_ego_graphs = cugraph.batched_ego_graphs(G, seeds=seeds, radius=radius) + if isinstance(seeds, (int, list)): + seeds = cudf.Series(seeds) + if isinstance(seeds, cudf.Series): + if G.renumbered is True: + seeds = G.lookup_internal_vertex_id(seeds) + elif isinstance(seeds, cudf.DataFrame): + if G.renumbered is True: + seeds = G.lookup_internal_vertex_id(seeds, seeds.columns) + + # Match the seed to the vertex dtype + n_type = G.edgelist.edgelist_df["src"].dtype + n = seeds.astype(n_type) + do_expensive_check = False + + source, destination, weight, offset = pylibcugraph_ego_graph( + resource_handle=ResourceHandle(), + graph=G._plc_graph, + source_vertices=n, + radius=radius, + do_expensive_check=do_expensive_check, + ) + + df = cudf.DataFrame() + df["src"] = source + df["dst"] = destination + if weight is not None: + df["weight"] = weight + + if G.renumbered: + df, _ = G.unrenumber(df, "src", get_column_names=True) + df, _ = G.unrenumber(df, "dst", get_column_names=True) + + offset = cudf.Series(offset) + sg_cugraph_ego_graphs = (df, offset) # Save the results back to the input_combo dictionary to prevent redundant # cuGraph runs. Other tests using the input_combo fixture will look for # them, and if not present they will have to re-run the same cuGraph call. - input_combo["sg_cugraph_results"] = sg_cugraph_ego_graphs + chunksize = dcg.get_chunksize(input_data_path) ddf = dask_cudf.read_csv( input_data_path, diff --git a/python/cugraph/pyproject.toml b/python/cugraph/pyproject.toml index f6515477779..9fb4fa26e1d 100644 --- a/python/cugraph/pyproject.toml +++ b/python/cugraph/pyproject.toml @@ -59,7 +59,6 @@ test = [ "pytest-benchmark", "pytest-cov", "pytest-xdist", - "python-louvain", "scikit-learn>=0.23.1", "scipy", ] # This list was generated by `rapids-dependency-file-generator`. To make changes, edit ../../dependencies.yaml and run `rapids-dependency-file-generator`.