diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 9ff575865e3..96e491f4cb4 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -33,6 +33,3 @@ ENV SCCACHE_REGION="us-east-2"
ENV SCCACHE_BUCKET="rapids-sccache-devs"
ENV AWS_ROLE_ARN="arn:aws:iam::279114543810:role/nv-gha-token-sccache-devs"
ENV HISTFILE="/home/coder/.cache/._bash_history"
-
-# cugraph_pyg's setup.py needs this defined when building in a conda env
-ENV CUDA_HOME="${CUDA_HOME:-/home/coder/.conda/envs/$DEFAULT_CONDA_ENV}"
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 7558b4c0d7b..739996a264c 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -113,22 +113,3 @@ jobs:
sha: ${{ inputs.sha }}
date: ${{ inputs.date }}
package-name: cugraph
- wheel-build-cugraph-equivariant:
- secrets: inherit
- uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@branch-25.02
- with:
- build_type: ${{ inputs.build_type || 'branch' }}
- branch: ${{ inputs.branch }}
- sha: ${{ inputs.sha }}
- date: ${{ inputs.date }}
- script: ci/build_wheel_cugraph-equivariant.sh
- wheel-publish-cugraph-equivariant:
- needs: wheel-build-cugraph-equivariant
- secrets: inherit
- uses: rapidsai/shared-workflows/.github/workflows/wheels-publish.yaml@branch-25.02
- with:
- build_type: ${{ inputs.build_type || 'branch' }}
- branch: ${{ inputs.branch }}
- sha: ${{ inputs.sha }}
- date: ${{ inputs.date }}
- package-name: cugraph-equivariant
diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml
index 2fdc9e5198d..bb2a5ebc6ce 100644
--- a/.github/workflows/pr.yaml
+++ b/.github/workflows/pr.yaml
@@ -25,8 +25,6 @@ jobs:
- wheel-tests-pylibcugraph
- wheel-build-cugraph
- wheel-tests-cugraph
- - wheel-build-cugraph-equivariant
- - wheel-tests-cugraph-equivariant
- devcontainer
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/pr-builder.yaml@branch-25.02
@@ -161,21 +159,6 @@ jobs:
with:
build_type: pull-request
script: ci/test_wheel_cugraph.sh
- wheel-build-cugraph-equivariant:
- secrets: inherit
- uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@branch-25.02
- with:
- build_type: pull-request
- script: ci/build_wheel_cugraph-equivariant.sh
- wheel-tests-cugraph-equivariant:
- needs: [wheel-build-cugraph-equivariant, changed-files]
- secrets: inherit
- uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@branch-25.02
- if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python
- with:
- build_type: pull-request
- script: ci/test_wheel_cugraph-equivariant.sh
- matrix_filter: map(select(.ARCH == "amd64"))
devcontainer:
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/build-in-devcontainer.yaml@branch-25.02
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index b0a05ce4eb7..4aa698c987f 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -58,13 +58,3 @@ jobs:
date: ${{ inputs.date }}
sha: ${{ inputs.sha }}
script: ci/test_wheel_cugraph.sh
- wheel-tests-cugraph-equivariant:
- secrets: inherit
- uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@branch-25.02
- with:
- build_type: nightly
- branch: ${{ inputs.branch }}
- date: ${{ inputs.date }}
- sha: ${{ inputs.sha }}
- script: ci/test_wheel_cugraph-equivariant.sh
- matrix_filter: map(select(.ARCH == "amd64"))
diff --git a/.gitignore b/.gitignore
index 2fea1022910..9480c2618bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -78,9 +78,6 @@ datasets/*
!datasets/karate-disjoint.csv
!datasets/netscience.csv
-# nx-cugraph side effects
-python/nx-cugraph/objects.inv
-
.pydevproject
# Jupyter Notebooks
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index b5fbcf9ad42..4bb037b5fda 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -19,7 +19,6 @@ repos:
language_version: python3
args: [--target-version=py310]
files: ^(python/.*|benchmarks/.*)$
- exclude: ^python/nx-cugraph/
- repo: https://github.com/PyCQA/flake8
rev: 7.1.1
hooks:
@@ -59,23 +58,3 @@ repos:
hooks:
- id: rapids-dependency-file-generator
args: ["--clean"]
- - repo: local
- hooks:
- - id: nx-cugraph-meta-data-update
- name: nx-cugraph meta-data updater
- entry: bash -c "PYTHONPATH=./python/nx-cugraph python ./python/nx-cugraph/_nx_cugraph/__init__.py"
- files: ^python/nx-cugraph/
- types: [python]
- language: python
- pass_filenames: false
- additional_dependencies: ["networkx>=3.4"]
- - repo: local
- hooks:
- - id: nx-cugraph-readme-update
- name: nx-cugraph README updater
- entry: bash -c "PYTHONPATH=./python/nx-cugraph python ./python/nx-cugraph/scripts/update_readme.py ./python/nx-cugraph/README.md"
- files: ^python/nx-cugraph/
- types_or: [python, markdown]
- language: python
- pass_filenames: false
- additional_dependencies: ["networkx>=3.4"]
diff --git a/README.md b/README.md
index 8026e4feb64..857406075e0 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@
-----
## News
-___NEW!___ _[nx-cugraph](./python/nx-cugraph/README.md)_, a NetworkX backend that provides GPU acceleration to NetworkX with zero code change.
+___NEW!___ _[nx-cugraph](https://rapids.ai/nx-cugraph/)_, a NetworkX backend that provides GPU acceleration to NetworkX with zero code change.
```
> pip install nx-cugraph-cu11 --extra-index-url https://pypi.nvidia.com
> export NETWORKX_AUTOMATIC_BACKENDS=cugraph
@@ -62,9 +62,8 @@ That's it. NetworkX now leverages cuGraph for accelerated graph algorithms.
- [External Data Types](./readme_pages/data_types.md)
- [pylibcugraph](./readme_pages/pylibcugraph.md)
- [libcugraph (C/C++/CUDA)](./readme_pages/libcugraph.md)
- - [nx-cugraph](./python/nx-cugraph/README.md)
+ - [nx-cugraph](https://rapids.ai/nx-cugraph/)
- [cugraph-service](./readme_pages/cugraph_service.md)
- - [cugraph-dgl](./readme_pages/cugraph_dgl.md)
- [cugraph-ops](./readme_pages/cugraph_ops.md)
- API Docs
- Python
@@ -127,7 +126,7 @@ df_page.sort_values('pagerank', ascending=False).head(10)
* ArangoDB - a free and open-source native multi-model database system - https://www.arangodb.com/
* CuPy - "NumPy/SciPy-compatible Array Library for GPU-accelerated Computing with Python" - https://cupy.dev/
* Memgraph - In-memory Graph database - https://memgraph.com/
-* NetworkX (via [nx-cugraph](./python/nx-cugraph/README.md) backend) - an extremely popular, free and open-source package for the creation, manipulation, and study of the structure, dynamics, and functions of complex networks - https://networkx.org/
+* NetworkX (via [nx-cugraph](https://rapids.ai/nx-cugraph/) backend) - an extremely popular, free and open-source package for the creation, manipulation, and study of the structure, dynamics, and functions of complex networks - https://networkx.org/
* PyGraphistry - free and open-source GPU graph ETL, AI, and visualization, including native RAPIDS & cuGraph support - http://github.com/graphistry/pygraphistry
* ScanPy - a scalable toolkit for analyzing single-cell gene expression data - https://scanpy.readthedocs.io/en/stable/
diff --git a/benchmarks/nx-cugraph/pytest-based/README.md b/benchmarks/nx-cugraph/pytest-based/README.md
deleted file mode 100644
index 414a22171a0..00000000000
--- a/benchmarks/nx-cugraph/pytest-based/README.md
+++ /dev/null
@@ -1,49 +0,0 @@
-## `nx-cugraph` Benchmarks
-
-### Overview
-
-This directory contains a set of scripts designed to benchmark NetworkX with the `nx-cugraph` backend and deliver a report that summarizes the speed-up and runtime deltas over default NetworkX.
-
-Our current benchmarks provide the following datasets:
-
-| Dataset | Nodes | Edges | Directed |
-| -------- | ------- | ------- | ------- |
-| netscience | 1,461 | 5,484 | Yes |
-| email-Eu-core | 1,005 | 25,571 | Yes |
-| amazon0302 | 262,111 | 1,234,877 | Yes |
-| cit-Patents | 3,774,768 | 16,518,948 | Yes |
-| hollywood | 1,139,905 | 57,515,616 | No |
-| soc-LiveJournal1 | 4,847,571 | 68,993,773 | Yes |
-
-
-
-### Scripts
-
-#### 1. `run-main-benchmarks.sh`
-This script allows users to run a small set of commonly-used algorithms across multiple datasets and backends. All results are stored inside a sub-directory (`logs/`) and output files are named based on the combination of parameters for that benchmark.
-
-NOTE:
- - If running with all algorithms and datasets using NetworkX without an accelerated backend, this script may take a few hours to finish running.
- - The `betweenness_centrality` benchmark will run with values `[10, 20, 50, 100, 500, 1000]` by default. You can specify only specific k-values to be run by editing `bc_k_values` (line 46) to be passed as a [pytest keyword object](https://docs.pytest.org/en/6.2.x/usage.html#specifying-tests-selecting-tests).
-
-**Usage:**
- - Run with `--cpu-only`:
- ```bash
- ./run-main-benchmarks.sh --cpu-only
- ```
- - Run with `--gpu-only`:
- ```bash
- ./run-main-benchmarks.sh --gpu-only
- ```
- - Run without any arguments (all backends):
- ```bash
- ./run-main-benchmarks.sh
- ```
-
-#### 2. `create_results_summary_page.py`
-This script is designed to be run after `run-main-benchmarks.sh` in order to generate an HTML page displaying a results table comparing default NetworkX to nx-cugraph. The script also provides information about the current system, so it should be run on the machine on which benchmarks were run.
-
-**Usage:**
- ```bash
- python create_results_summary_page.py > report.html
- ```
diff --git a/benchmarks/nx-cugraph/pytest-based/bench_algos.py b/benchmarks/nx-cugraph/pytest-based/bench_algos.py
deleted file mode 100644
index 8852ed2a875..00000000000
--- a/benchmarks/nx-cugraph/pytest-based/bench_algos.py
+++ /dev/null
@@ -1,985 +0,0 @@
-# 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
-#
-# 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 random
-
-import networkx as nx
-import pandas as pd
-import pytest
-from cugraph import datasets
-import nx_cugraph as nxcg
-
-# Attempt to import the NetworkX dispatching module, which is only needed when
-# testing with NX <3.2 in order to dynamically switch backends. NX >=3.2 allows
-# the backend to be specified directly in the API call.
-try:
- from networkx.classes import backends # NX <3.2
-except ImportError:
- backends = None
-
-
-################################################################################
-# Fixtures and params
-
-# See https://pytest-benchmark.readthedocs.io/en/latest/glossary.html for how
-# these variables are used.
-rounds = 1
-iterations = 1
-warmup_rounds = 1
-
-# FIXME: Add this to cugraph.datasets. This is done here so these benchmarks
-# can be run without requiring an updated cugraph install. This temporarily
-# adds a dataset based on an Amazon product co-purchasing network.
-amazon0302_metadata = """
-name: amazon0302
-description:
- Network was collected by crawling Amazon website. It is based on Customers Who Bought This Item Also Bought feature of the Amazon website. If a product i is frequently co-purchased with product j, the graph contains a directed edge from i to j. The data was collected in March 02 2003.
-author: J. Leskovec, L. Adamic and B. Adamic
-refs: J. Leskovec, L. Adamic and B. Adamic. The Dynamics of Viral Marketing. ACM Transactions on the Web (ACM TWEB), 1(1), 2007.
-delim: "\t"
-header: 3
-col_names:
- - FromNodeId
- - ToNodeId
-col_types:
- - int32
- - int32
-has_loop: false
-is_directed: true
-is_multigraph: false
-is_symmetric: false
-number_of_edges: 1234877
-number_of_nodes: 262111
-url: https://snap.stanford.edu/data/amazon0302.txt.gz
-"""
-amazon0302_metadata_file_name = datasets.default_download_dir.path / "amazon0302.yaml"
-if not amazon0302_metadata_file_name.exists():
- amazon0302_metadata_file_name.parent.mkdir(parents=True, exist_ok=True)
- with open(amazon0302_metadata_file_name, "w") as f:
- f.write(amazon0302_metadata)
-
-amazon0302_dataset = datasets.Dataset(amazon0302_metadata_file_name)
-amazon0302_dataset.metadata["file_type"] = ".gz"
-
-dataset_param_values = [
- # name: karate, nodes: 34, edges: 156
- pytest.param(datasets.karate, marks=[pytest.mark.small, pytest.mark.undirected]),
- # name: netscience, nodes: 1461, edges: 5484
- pytest.param(datasets.netscience, marks=[pytest.mark.small, pytest.mark.directed]),
- # name: email-Eu-core, nodes: 1005, edges: 25571
- pytest.param(
- datasets.email_Eu_core, marks=[pytest.mark.small, pytest.mark.directed]
- ),
- # name: amazon0302, nodes: 262111, edges: 1234877
- pytest.param(amazon0302_dataset, marks=[pytest.mark.medium, pytest.mark.directed]),
- # name: cit-Patents, nodes: 3774768, edges: 16518948
- pytest.param(
- datasets.cit_patents, marks=[pytest.mark.medium, pytest.mark.directed]
- ),
- # name: hollywood, nodes: 1139905, edges: 57515616
- pytest.param(
- datasets.hollywood, marks=[pytest.mark.medium, pytest.mark.undirected]
- ),
- # name: soc-LiveJournal1, nodes: 4847571, edges: 68993773
- pytest.param(
- datasets.soc_livejournal, marks=[pytest.mark.medium, pytest.mark.directed]
- ),
- # name: europe_osm, nodes: 50912018, edges: 54054660
- pytest.param(
- datasets.europe_osm, marks=[pytest.mark.large, pytest.mark.undirected]
- ),
-]
-
-backend_param_values = ["cugraph", "cugraph-preconverted", None]
-
-
-def setup_module(module):
- """
- Trivial conversion call to force various one-time CUDA initialization
- operations to happen outside of benchmarks.
- """
- G = nx.karate_club_graph()
- nxcg.from_networkx(G)
-
-
-# Test IDs are generated using the lambda assigned to the ids arg to provide an
-# easier-to-read name. This is especially helpful for Dataset objs (see
-# https://docs.pytest.org/en/stable/reference/reference.html#pytest-fixture)
-@pytest.fixture(
- scope="module", params=dataset_param_values, ids=lambda ds: f"ds={str(ds)}"
-)
-def graph_obj(request):
- """
- Returns a NX Graph or DiGraph obj from the dataset instance parameter.
- """
- dataset = request.param
- return nx_graph_from_dataset(dataset)
-
-
-@pytest.fixture(
- scope="module",
- params=backend_param_values,
- ids=lambda backend: f"backend={backend}",
-)
-def backend(request):
- """
- Returns the backend name to use. This is done as a fixture for consistency
- and simplicity when creating benchmarks (no need to mark the benchmark as
- parametrized).
- """
- return request.param
-
-
-################################################################################
-# Helpers
-def nx_graph_from_dataset(dataset_obj):
- """
- Read the dataset specified by the dataset_obj and create and return a
- nx.Graph or nx.DiGraph instance based on the dataset is_directed metadata.
- """
- create_using = nx.DiGraph if dataset_obj.metadata["is_directed"] else nx.Graph
- names = dataset_obj.metadata["col_names"]
- pandas_edgelist = dataset_obj.get_edgelist(download=True, reader="pandas")
- G = nx.from_pandas_edgelist(
- pandas_edgelist, source=names[0], target=names[1], create_using=create_using
- )
- return G
-
-
-def get_legacy_backend_wrapper(backend_name):
- """
- Returns a callable that wraps an algo function with either the default
- dispatcher (which dispatches based on input graph type), or the "testing"
- dispatcher (which autoconverts and unconditionally dispatches).
- This is only supported for NetworkX <3.2
- """
- backends.plugin_name = "cugraph"
- orig_dispatch = backends._dispatch
- testing_dispatch = backends.test_override_dispatch
-
- if backend_name == "cugraph":
- dispatch = testing_dispatch
- else:
- dispatch = orig_dispatch
-
- def wrap_callable_for_dispatch(func, exhaust_returned_iterator=False):
- # Networkx <3.2 registers functions when the dispatch decorator is
- # applied (called) and errors if re-registered, so clear bookkeeping to
- # allow it to be called repeatedly.
- backends._registered_algorithms = {}
- actual_func = dispatch(func) # returns the func the dispatcher picks
-
- def wrapper(*args, **kwargs):
- retval = actual_func(*args, **kwargs)
- if exhaust_returned_iterator:
- retval = list(retval)
- return retval
-
- return wrapper
-
- return wrap_callable_for_dispatch
-
-
-def get_backend_wrapper(backend_name):
- """
- Returns a callable that wraps an algo function in order to set the
- "backend" kwarg on it.
- This is only supported for NetworkX >= 3.2
- """
-
- def wrap_callable_for_dispatch(func, exhaust_returned_iterator=False):
- def wrapper(*args, **kwargs):
- kwargs["backend"] = backend_name
- retval = func(*args, **kwargs)
- if exhaust_returned_iterator:
- retval = list(retval)
- return retval
-
- return wrapper
-
- return wrap_callable_for_dispatch
-
-
-@pytest.fixture(
- scope="module",
- params=backend_param_values,
- ids=lambda backend: f"backend={backend}",
-)
-def backend_wrapper(request):
- """
- Returns a callable that takes a function algo and wraps it in another
- function that calls the algo using the appropriate backend.
-
- For example: if the backend to test is "cugraph", this will return a
- function that calls nx.pagerank(..., backend='cugraph')
- """
- backend_name = request.param
- actual_backend_name = backend_name
-
- # Special case: cugraph-preconverted may be specified as a backend but this
- # name is reserved to indicate a cugraph backend is to be used with a
- # preconverted graph obj (rather than having the backend do the
- # conversion).
- if backend_name == "cugraph-preconverted":
- actual_backend_name = "cugraph"
-
- # NX <3.2 does not support the backends= kwarg, so the backend must be
- # enabled differently
- if backends is not None:
- wrapper = get_legacy_backend_wrapper(actual_backend_name)
- else:
- wrapper = get_backend_wrapper(actual_backend_name)
-
- wrapper.backend_name = backend_name
- return wrapper
-
-
-def get_graph_obj_for_benchmark(graph_obj, backend_wrapper):
- """
- Given a Graph object and a backend name, return a converted Graph or the
- original Graph object based on the backend to use.
-
- This is needed because some backend names are actually used as descriptions
- for combinations of backends and converted/non-converted graphs. For
- example, a benchmark may specify the "cugraph-preconverted" backend, which
- is not an installed backend but instead refers to the "cugraph" backend
- passed a NX Graph that has been converted to a nx-cugraph Graph object.
- """
- G = graph_obj
- if backend_wrapper.backend_name == "cugraph-preconverted":
- G = nxcg.from_networkx(G, preserve_all_attrs=True)
- return G
-
-
-def get_highest_degree_node(graph_obj):
- degrees = graph_obj.degree() # list of tuples of (node, degree)
- return max(degrees, key=lambda t: t[1])[0]
-
-
-def build_personalization_dict(pagerank_dict):
- """
- Returns a dictionary that can be used as the personalization value for a
- call to nx.pagerank(). The pagerank_dict passed in is used as the initial
- source of values for each node, and this function simply treats the list of
- dict values as two halves (halves A and B) and swaps them so (most if not
- all) nodes/keys are assigned a different value from the dictionary.
- """
- num_half = len(pagerank_dict) // 2
- A_half_items = list(pagerank_dict.items())[:num_half]
- B_half_items = list(pagerank_dict.items())[num_half:]
-
- # Support an odd number of items by initializing with B_half_items, which
- # will always be one bigger if the number of items is odd. This will leave
- # the one remainder (in the case of an odd number) unchanged.
- pers_dict = dict(B_half_items)
- pers_dict.update({A_half_items[i][0]: B_half_items[i][1] for i in range(num_half)})
- pers_dict.update({B_half_items[i][0]: A_half_items[i][1] for i in range(num_half)})
-
- return pers_dict
-
-
-################################################################################
-# Benchmarks
-def bench_from_networkx(benchmark, graph_obj):
- benchmark(nxcg.from_networkx, graph_obj)
-
-
-# normalized_param_values = [True, False]
-normalized_param_values = [True]
-k_param_values = [10, 20, 50, 100, 500, 1000]
-
-
-@pytest.mark.parametrize(
- "normalized", normalized_param_values, ids=lambda norm: f"{norm=}"
-)
-@pytest.mark.parametrize("k", k_param_values, ids=lambda k: f"{k=}")
-def bench_betweenness_centrality(benchmark, graph_obj, backend_wrapper, normalized, k):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- if k > G.number_of_nodes():
- pytest.skip(reason=f"{k=} > {G.number_of_nodes()=}")
-
- result = benchmark.pedantic(
- target=backend_wrapper(nx.betweenness_centrality),
- args=(G,),
- kwargs=dict(
- weight=None,
- normalized=normalized,
- k=k,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-@pytest.mark.parametrize(
- "normalized", normalized_param_values, ids=lambda norm: f"{norm=}"
-)
-@pytest.mark.parametrize("k", k_param_values, ids=lambda k: f"{k=}")
-def bench_edge_betweenness_centrality(
- benchmark, graph_obj, backend_wrapper, normalized, k
-):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
-
- if k > G.number_of_nodes():
- pytest.skip(reason=f"{k=} > {G.number_of_nodes()=}")
-
- result = benchmark.pedantic(
- target=backend_wrapper(nx.edge_betweenness_centrality),
- args=(G,),
- kwargs=dict(
- weight=None,
- normalized=normalized,
- k=k,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_louvain_communities(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- # DiGraphs are not supported
- if G.is_directed():
- G = G.to_undirected()
- result = benchmark.pedantic(
- target=backend_wrapper(nx.community.louvain_communities),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is list
-
-
-def bench_degree_centrality(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.degree_centrality),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_eigenvector_centrality(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.eigenvector_centrality),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-@pytest.mark.parametrize(
- "normalized", normalized_param_values, ids=lambda norm: f"{norm=}"
-)
-def bench_hits(benchmark, graph_obj, backend_wrapper, normalized):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.hits),
- args=(G,),
- kwargs=dict(
- normalized=normalized,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is tuple
- assert len(result) == 2
- assert type(result[0]) is dict
- assert type(result[1]) is dict
-
-
-def bench_in_degree_centrality(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.in_degree_centrality),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-@pytest.mark.parametrize(
- "normalized", normalized_param_values, ids=lambda norm: f"{norm=}"
-)
-def bench_katz_centrality(benchmark, graph_obj, backend_wrapper, normalized):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.katz_centrality),
- args=(G,),
- kwargs=dict(
- normalized=normalized,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_k_truss(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- # DiGraphs are not supported
- if G.is_directed():
- G = G.to_undirected()
- result = benchmark.pedantic(
- target=backend_wrapper(nx.k_truss),
- args=(G,),
- kwargs=dict(
- k=2,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- # Check that this at least appears to be some kind of NX-like Graph
- assert hasattr(result, "has_node")
-
-
-def bench_out_degree_centrality(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.out_degree_centrality),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_pagerank(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.pagerank),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_pagerank_personalized(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
-
- # FIXME: This will run for every combination of inputs, even if the
- # graph/dataset does not change. Ideally this is run once per
- # graph/dataset.
- pagerank_dict = nx.pagerank(G)
- personalization_dict = build_personalization_dict(pagerank_dict)
-
- result = benchmark.pedantic(
- target=backend_wrapper(nx.pagerank),
- args=(G,),
- kwargs={"personalization": personalization_dict},
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_shortest_path(benchmark, graph_obj, backend_wrapper):
- """
- This passes in the source node with the highest degree, but no target.
- """
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
-
- result = benchmark.pedantic(
- target=backend_wrapper(nx.shortest_path),
- args=(G,),
- kwargs=dict(
- source=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_single_source_shortest_path_length(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
-
- result = benchmark.pedantic(
- target=backend_wrapper(nx.single_source_shortest_path_length),
- args=(G,),
- kwargs=dict(
- source=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_single_target_shortest_path_length(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(
- nx.single_target_shortest_path_length, exhaust_returned_iterator=True
- ),
- args=(G,),
- kwargs=dict(
- target=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- # exhaust_returned_iterator=True forces the result to a list, but is not
- # needed for this algo in NX 3.3+ which returns a dict instead of an
- # iterator. Forcing to a list does not change the benchmark timing.
- assert type(result) is list
-
-
-def bench_ancestors(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.ancestors),
- args=(G,),
- kwargs=dict(
- source=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is set
-
-
-def bench_average_clustering(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- # DiGraphs are not supported by nx-cugraph
- if G.is_directed():
- G = G.to_undirected()
- result = benchmark.pedantic(
- target=backend_wrapper(nx.average_clustering),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is float
-
-
-def bench_generic_bfs_edges(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.generic_bfs_edges, exhaust_returned_iterator=True),
- args=(G,),
- kwargs=dict(
- source=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is list
-
-
-def bench_bfs_edges(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.bfs_edges, exhaust_returned_iterator=True),
- args=(G,),
- kwargs=dict(
- source=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is list
-
-
-def bench_bfs_layers(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.bfs_layers, exhaust_returned_iterator=True),
- args=(G,),
- kwargs=dict(
- sources=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is list
-
-
-def bench_bfs_predecessors(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.bfs_predecessors, exhaust_returned_iterator=True),
- args=(G,),
- kwargs=dict(
- source=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is list
-
-
-def bench_bfs_successors(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.bfs_successors, exhaust_returned_iterator=True),
- args=(G,),
- kwargs=dict(
- source=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is list
-
-
-def bench_bfs_tree(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.bfs_tree),
- args=(G,),
- kwargs=dict(
- source=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- # Check that this at least appears to be some kind of NX-like Graph
- assert hasattr(result, "has_node")
-
-
-def bench_clustering(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- # DiGraphs are not supported by nx-cugraph
- if G.is_directed():
- G = G.to_undirected()
- result = benchmark.pedantic(
- target=backend_wrapper(nx.clustering),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_core_number(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- # DiGraphs are not supported by nx-cugraph
- if G.is_directed():
- G = G.to_undirected()
- result = benchmark.pedantic(
- target=backend_wrapper(nx.core_number),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_descendants(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.descendants),
- args=(G,),
- kwargs=dict(
- source=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is set
-
-
-def bench_descendants_at_distance(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.descendants_at_distance),
- args=(G,),
- kwargs=dict(
- source=node,
- distance=1,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is set
-
-
-def bench_is_bipartite(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.is_bipartite),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is bool
-
-
-def bench_is_strongly_connected(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.is_strongly_connected),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is bool
-
-
-def bench_is_weakly_connected(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.is_weakly_connected),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is bool
-
-
-def bench_number_strongly_connected_components(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.number_strongly_connected_components),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is int
-
-
-def bench_number_weakly_connected_components(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.number_weakly_connected_components),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is int
-
-
-def bench_overall_reciprocity(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.overall_reciprocity),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is float
-
-
-def bench_reciprocity(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.reciprocity),
- args=(G,),
- kwargs=dict(
- nodes=node,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is float
-
-
-def bench_strongly_connected_components(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(
- nx.strongly_connected_components, exhaust_returned_iterator=True
- ),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is list
-
-
-def bench_transitivity(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- # DiGraphs are not supported by nx-cugraph
- if G.is_directed():
- G = G.to_undirected()
- result = benchmark.pedantic(
- target=backend_wrapper(nx.transitivity),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is float
-
-
-def bench_triangles(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- # DiGraphs are not supported
- if G.is_directed():
- G = G.to_undirected()
- result = benchmark.pedantic(
- target=backend_wrapper(nx.triangles),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is dict
-
-
-def bench_weakly_connected_components(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- result = benchmark.pedantic(
- target=backend_wrapper(
- nx.weakly_connected_components, exhaust_returned_iterator=True
- ),
- args=(G,),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert type(result) is list
-
-
-def bench_ego_graph(benchmark, graph_obj, backend_wrapper):
- G = get_graph_obj_for_benchmark(graph_obj, backend_wrapper)
- node = get_highest_degree_node(graph_obj)
- result = benchmark.pedantic(
- target=backend_wrapper(nx.ego_graph),
- args=(G,),
- kwargs=dict(
- n=node,
- radius=100,
- ),
- rounds=rounds,
- iterations=iterations,
- warmup_rounds=warmup_rounds,
- )
- assert isinstance(result, (nx.Graph, nxcg.Graph))
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_complete_bipartite_graph(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_connected_components(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_is_connected(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_node_connected_component(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_number_connected_components(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_is_isolate(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_isolates(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_number_of_isolates(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_complement(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_reverse(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_is_arborescence(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_is_branching(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_is_forest(benchmark, graph_obj, backend_wrapper):
- pass
-
-
-@pytest.mark.skip(reason="benchmark not implemented")
-def bench_is_tree(benchmark, graph_obj, backend_wrapper):
- pass
diff --git a/benchmarks/nx-cugraph/pytest-based/create_results_summary_page.py b/benchmarks/nx-cugraph/pytest-based/create_results_summary_page.py
deleted file mode 100644
index e4aff10f0a5..00000000000
--- a/benchmarks/nx-cugraph/pytest-based/create_results_summary_page.py
+++ /dev/null
@@ -1,293 +0,0 @@
-# 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 re
-import pathlib
-import json
-import platform
-import psutil
-import socket
-import subprocess
-
-
-def get_formatted_time_value(time):
- res = ""
- if time < 1:
- if time < 0.001:
- units = "us"
- time *= 1e6
- else:
- units = "ms"
- time *= 1e3
- else:
- units = "s"
- return f"{time:.3f}{units}"
-
-
-def get_all_benchmark_info():
- benchmarks = {}
- # Populate benchmarks dir from .json files
- for json_file in logs_dir.glob("*.json"):
- try:
- data = json.loads(open(json_file).read())
- except json.decoder.JSONDecodeError:
- continue
-
- for benchmark_run in data["benchmarks"]:
- # example name: "bench_triangles[ds=netscience-backend=cugraph-preconverted]"
- name = benchmark_run["name"]
-
- algo_name = name.split("[")[0]
- if algo_name.startswith("bench_"):
- algo_name = algo_name[6:]
- # special case for betweenness_centrality
- match = k_patt.match(name)
- if match is not None:
- algo_name += f", k={match.group(1)}"
-
- match = dataset_patt.match(name)
- if match is None:
- raise RuntimeError(
- f"benchmark name {name} in file {json_file} has an unexpected format"
- )
- dataset = match.group(1)
- if dataset.endswith("-backend"):
- dataset = dataset[:-8]
-
- match = backend_patt.match(name)
- if match is None:
- raise RuntimeError(
- f"benchmark name {name} in file {json_file} has an unexpected format"
- )
- backend = match.group(1)
- if backend == "None":
- backend = "networkx"
-
- runtime = benchmark_run["stats"]["mean"]
- benchmarks.setdefault(algo_name, {}).setdefault(backend, {})[
- dataset
- ] = runtime
- return benchmarks
-
-
-def compute_perf_vals(cugraph_runtime, networkx_runtime):
- speedup_string = f"{networkx_runtime / cugraph_runtime:.3f}X"
- delta = networkx_runtime - cugraph_runtime
- if abs(delta) < 1:
- if abs(delta) < 0.001:
- units = "us"
- delta *= 1e6
- else:
- units = "ms"
- delta *= 1e3
- else:
- units = "s"
- delta_string = f"{delta:.3f}{units}"
-
- return (speedup_string, delta_string)
-
-
-def get_mem_info():
- return round(psutil.virtual_memory().total / (1024**3), 2)
-
-
-def get_cuda_version():
- output = subprocess.check_output("nvidia-smi", shell=True).decode()
- try:
- return next(
- line.split("CUDA Version: ")[1].split()[0]
- for line in output.splitlines()
- if "CUDA Version" in line
- )
- except subprocess.CalledProcessError:
- return "Failed to get CUDA version."
-
-
-def get_first_gpu_info():
- try:
- gpu_info = (
- subprocess.check_output(
- "nvidia-smi --query-gpu=name,memory.total,memory.free,memory.used --format=csv,noheader",
- shell=True,
- )
- .decode()
- .strip()
- )
- if gpu_info:
- gpus = gpu_info.split("\n")
- num_gpus = len(gpus)
- first_gpu = gpus[0] # Get the information for the first GPU
- gpu_name, mem_total, _, _ = first_gpu.split(",")
- return f"{num_gpus} x {gpu_name.strip()} ({round(int(mem_total.strip().split()[0]) / (1024), 2)} GB)"
- else:
- print("No GPU found or unable to query GPU details.")
- except subprocess.CalledProcessError:
- print("Failed to execute nvidia-smi. No GPU information available.")
-
-
-def get_system_info():
- print('
')
- print(f"
Hostname: {socket.gethostname()}
")
- print(
- f'
Operating System: {platform.system()} {platform.release()}
'
- )
- print(f'
Kernel Version : {platform.version()}
')
- with open("/proc/cpuinfo") as f:
- print(
- f'
CPU: {next(line.strip().split(": ")[1] for line in f if "model name" in line)} ({psutil.cpu_count(logical=False)} cores)
'
- )
- print(f'
Memory: {get_mem_info()} GB
')
- print(f"
GPU: {get_first_gpu_info()}
")
- print(f"
CUDA Version: {get_cuda_version()}
")
-
-
-if __name__ == "__main__":
- logs_dir = pathlib.Path("logs")
-
- dataset_patt = re.compile(".*ds=([\w-]+).*")
- backend_patt = re.compile(".*backend=(\w+).*")
- k_patt = re.compile(".*k=(\d+).*")
-
- # Organize all benchmark runs by the following hierarchy: algo -> backend -> dataset
- benchmarks = get_all_benchmark_info()
-
- # dump HTML table
- ordered_datasets = [
- "netscience",
- "email_Eu_core",
- "amazon0302",
- "cit-patents",
- "hollywood",
- "soc-livejournal1",
- ]
- # dataset, # Node, # Edge, Directed info
- dataset_meta = {
- "netscience": ["1,461", "5,484", "Yes"],
- "email_Eu_core": ["1,005", "25,571", "Yes"],
- "amazon0302": ["262,111", "1,234,877", "Yes"],
- "cit-patents": ["3,774,768", "16,518,948", "Yes"],
- "hollywood": ["1,139,905", "57,515,616", "No"],
- "soc-livejournal1": ["4,847,571", "68,993,773", "Yes"],
- }
-
- print(
- """
-
-
-
-
-
-
-
- Dataset Nodes Edges Directed | """
- )
- for ds in ordered_datasets:
- print(
- f" {ds} {dataset_meta[ds][0]} {dataset_meta[ds][1]} {dataset_meta[ds][2]}
| "
- )
- print(
- """
-
-
- """
- )
- for algo_name in sorted(benchmarks):
- algo_runs = benchmarks[algo_name]
- print(" ")
- print(f" {algo_name} | ")
- # Proceed only if any results are present for both cugraph and NX
- if "cugraph" in algo_runs and "networkx" in algo_runs:
- cugraph_algo_runs = algo_runs["cugraph"]
- networkx_algo_runs = algo_runs["networkx"]
- datasets_in_both = set(cugraph_algo_runs).intersection(networkx_algo_runs)
-
- # populate the table with speedup results for each dataset in the order
- # specified in ordered_datasets. If results for a run using a dataset
- # are not present for both cugraph and NX, output an empty cell.
- for dataset in ordered_datasets:
- if dataset in datasets_in_both:
- cugraph_runtime = cugraph_algo_runs[dataset]
- networkx_runtime = networkx_algo_runs[dataset]
- (speedup, runtime_delta) = compute_perf_vals(
- cugraph_runtime=cugraph_runtime,
- networkx_runtime=networkx_runtime,
- )
- nx_formatted = get_formatted_time_value(networkx_runtime)
- cg_formatted = get_formatted_time_value(cugraph_runtime)
- print(
- f" {nx_formatted} / {cg_formatted} {speedup} {runtime_delta} | "
- )
- else:
- print(f" | ")
-
- # If a comparison between cugraph and NX cannot be made, output empty cells
- # for each dataset
- else:
- for _ in range(len(ordered_datasets)):
- print(" | ")
- print("
")
- print(
- """
- \n
-
-
-
Table Format:
-
- - NetworkX time / nx-cugraph time
- - Speed-up of using nx-cugraph
- - Time-delta
-
-
"""
- )
- get_system_info()
- print("""
\n
\n""")
diff --git a/benchmarks/nx-cugraph/pytest-based/run-2402.sh b/benchmarks/nx-cugraph/pytest-based/run-2402.sh
deleted file mode 100755
index 44ed0bda43a..00000000000
--- a/benchmarks/nx-cugraph/pytest-based/run-2402.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2024, NVIDIA CORPORATION.
-#
-# Runs benchmarks for the 24.02 algos.
-# Pass either a or b or both. This is useful for separating batches of runs on different GPUs:
-# CUDA_VISIBLE_DEVICES=1 run-2402.sh b
-
-mkdir -p logs
-
-# benches="$benches ..." pattern is easy to comment out individual runs
-benches=
-
-while [[ $1 != "" ]]; do
- if [[ $1 == "a" ]]; then
- benches="$benches bench_ancestors"
- benches="$benches bench_average_clustering"
- benches="$benches bench_generic_bfs_edges"
- benches="$benches bench_bfs_edges"
- benches="$benches bench_bfs_layers"
- benches="$benches bench_bfs_predecessors"
- benches="$benches bench_bfs_successors"
- benches="$benches bench_bfs_tree"
- benches="$benches bench_clustering"
- benches="$benches bench_core_number"
- benches="$benches bench_descendants"
- elif [[ $1 == "b" ]]; then
- benches="$benches bench_descendants_at_distance"
- benches="$benches bench_is_bipartite"
- benches="$benches bench_is_strongly_connected"
- benches="$benches bench_is_weakly_connected"
- benches="$benches bench_number_strongly_connected_components"
- benches="$benches bench_number_weakly_connected_components"
- benches="$benches bench_overall_reciprocity"
- benches="$benches bench_reciprocity"
- benches="$benches bench_strongly_connected_components"
- benches="$benches bench_transitivity"
- benches="$benches bench_triangles"
- benches="$benches bench_weakly_connected_components"
- fi
- shift
-done
-
-for bench in $benches; do
- pytest -sv -k "soc-livejournal1" "bench_algos.py::$bench" 2>&1 | tee "logs/${bench}.log"
-done
diff --git a/benchmarks/nx-cugraph/pytest-based/run-main-benchmarks.sh b/benchmarks/nx-cugraph/pytest-based/run-main-benchmarks.sh
deleted file mode 100755
index 73c85000b0f..00000000000
--- a/benchmarks/nx-cugraph/pytest-based/run-main-benchmarks.sh
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/bin/bash
-# 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.
-
-
-# location to store datasets used for benchmarking
-export RAPIDS_DATASET_ROOT_DIR=${RAPIDS_DATASET_ROOT_DIR:-/datasets/cugraph}
-mkdir -p logs
-
-# list of algos, datasets, and back-ends to use in combinations
-algos="
- pagerank
- betweenness_centrality
- louvain
- shortest_path
- weakly_connected_components
- triangles
- bfs_predecessors
-"
-datasets="
- netscience
- email_Eu_core
- amazon0302
- cit-patents
- hollywood
- soc-livejournal
-"
-# None backend is default networkx
-# cugraph-preconvert backend is nx-cugraph
-backends="
- None
- cugraph-preconverted
-"
-
-# edit this directly to for pytest
-# e.g. -k "and not 100 and not 1000"
-bc_k_values=""
-
-# check for --cpu-only or --gpu-only args
-if [[ "$#" -eq 1 ]]; then
- case $1 in
- --cpu-only)
- backends="None"
- ;;
- --gpu-only)
- backends="cugraph-preconverted"
- ;;
- *)
- echo "Unknown option: $1"
- exit 1
- ;;
- esac
-fi
-
-for algo in $algos; do
- for dataset in $datasets; do
- for backend in $backends; do
- name="${backend}__${algo}__${dataset}"
- echo "Running: $backend, $dataset, bench_$algo"
-
- # uncomment to get command for reproducing test
- # echo "RUNNING: \"pytest -sv -k \"$backend and $dataset and bench_$algo $bc_k_values\" --benchmark-json=\"logs/${name}.json\" bench_algos.py"
-
- pytest -sv \
- -k "$backend and $dataset and bench_$algo $bc_k_values" \
- --benchmark-json="logs/${name}.json" \
- bench_algos.py 2>&1 | tee "logs/${name}.out"
- done
- done
-done
diff --git a/build.sh b/build.sh
index 29abd48166a..756045461dd 100755
--- a/build.sh
+++ b/build.sh
@@ -29,10 +29,6 @@ VALIDARGS="
pylibcugraph
cugraph
cugraph-service
- cugraph-pyg
- cugraph-dgl
- cugraph-equivariant
- nx-cugraph
cpp-mgtests
cpp-mtmgtests
docs
@@ -58,10 +54,6 @@ HELP="$0 [ ...] [ ...]
pylibcugraph - build the pylibcugraph Python package
cugraph - build the cugraph Python package
cugraph-service - build the cugraph-service_client and cugraph-service_server Python package
- cugraph-pyg - build the cugraph-pyg Python package
- cugraph-dgl - build the cugraph-dgl extensions for DGL
- cugraph-equivariant - build the cugraph-equivariant Python package
- nx-cugraph - build the nx-cugraph Python package
cpp-mgtests - build libcugraph and libcugraph_etl MG tests. Builds MPI communicator, adding MPI as a dependency.
cpp-mtmgtests - build libcugraph MTMG tests. Adds UCX as a dependency (temporary).
docs - build the docs
@@ -88,12 +80,10 @@ LIBCUGRAPH_ETL_BUILD_DIR=${LIBCUGRAPH_ETL_BUILD_DIR:=${REPODIR}/cpp/libcugraph_e
CUGRAPH_SERVICE_BUILD_DIRS="${REPODIR}/python/cugraph-service/server/build
${REPODIR}/python/cugraph-service/client/build
"
-CUGRAPH_DGL_BUILD_DIR=${REPODIR}/python/cugraph-dgl/build
BUILD_DIRS="${LIBCUGRAPH_BUILD_DIR}
${LIBCUGRAPH_ETL_BUILD_DIR}
${CUGRAPH_SERVICE_BUILD_DIRS}
- ${CUGRAPH_DGL_BUILD_DIR}
"
# Set defaults for vars modified by flags to this script
@@ -211,8 +201,7 @@ if hasArg uninstall; then
# FIXME: if multiple versions of these packages are installed, this only
# removes the latest one and leaves the others installed. build.sh uninstall
# can be run multiple times to remove all of them, but that is not obvious.
- pip uninstall -y pylibcugraph cugraph cugraph-service-client cugraph-service-server \
- cugraph-dgl cugraph-pyg cugraph-equivariant nx-cugraph
+ pip uninstall -y pylibcugraph cugraph cugraph-service-client cugraph-service-server
fi
if hasArg clean; then
@@ -330,42 +319,6 @@ if hasArg cugraph-service || hasArg all; then
fi
fi
-# Build and install the cugraph-pyg Python package
-if hasArg cugraph-pyg || hasArg all; then
- if hasArg --clean; then
- cleanPythonDir ${REPODIR}/python/cugraph-pyg
- else
- python ${PYTHON_ARGS_FOR_INSTALL} ${REPODIR}/python/cugraph-pyg
- fi
-fi
-
-# Install the cugraph-dgl extensions for DGL
-if hasArg cugraph-dgl || hasArg all; then
- if hasArg --clean; then
- cleanPythonDir ${REPODIR}/python/cugraph-dgl
- else
- python ${PYTHON_ARGS_FOR_INSTALL} ${REPODIR}/python/cugraph-dgl
- fi
-fi
-
-# Build and install the cugraph-equivariant Python package
-if hasArg cugraph-equivariant || hasArg all; then
- if hasArg --clean; then
- cleanPythonDir ${REPODIR}/python/cugraph-equivariant
- else
- python ${PYTHON_ARGS_FOR_INSTALL} ${REPODIR}/python/cugraph-equivariant
- fi
-fi
-
-# Build and install the nx-cugraph Python package
-if hasArg nx-cugraph || hasArg all; then
- if hasArg --clean; then
- cleanPythonDir ${REPODIR}/python/nx-cugraph
- else
- python ${PYTHON_ARGS_FOR_INSTALL} ${REPODIR}/python/nx-cugraph
- fi
-fi
-
# Build the docs
if hasArg docs || hasArg all; then
if [ ! -d ${LIBCUGRAPH_BUILD_DIR} ]; then
diff --git a/ci/build_docs.sh b/ci/build_docs.sh
index 01c573c96ca..2d7e90da8d0 100755
--- a/ci/build_docs.sh
+++ b/ci/build_docs.sh
@@ -48,7 +48,7 @@ rapids-mamba-retry install \
"libcugraph_etl=${RAPIDS_VERSION_MAJOR_MINOR}.*" \
"pylibcugraphops=${RAPIDS_VERSION_MAJOR_MINOR}.*" \
"pylibwholegraph=${RAPIDS_VERSION_MAJOR_MINOR}.*" \
- "pytorch>=2.3,<2.4" \
+ 'pytorch>=2.3' \
"cuda-version=${CONDA_CUDA_VERSION}"
export RAPIDS_DOCS_DIR="$(mktemp -d)"
diff --git a/ci/build_python.sh b/ci/build_python.sh
index 9a8f1227488..eab41f63da0 100755
--- a/ci/build_python.sh
+++ b/ci/build_python.sh
@@ -50,9 +50,4 @@ rapids-conda-retry mambabuild \
--channel "${RAPIDS_CONDA_BLD_OUTPUT_DIR}" \
conda/recipes/cugraph-service
-rapids-conda-retry mambabuild \
- --no-test \
- --channel "${RAPIDS_CONDA_BLD_OUTPUT_DIR}" \
- conda/recipes/cugraph-equivariant
-
rapids-upload-conda-to-s3 python
diff --git a/ci/build_wheel.sh b/ci/build_wheel.sh
index 3c89d63538c..9a77e6b3021 100755
--- a/ci/build_wheel.sh
+++ b/ci/build_wheel.sh
@@ -29,27 +29,22 @@ python -m pip wheel \
sccache --show-adv-stats
-# pure-python packages should be marked as pure, and not have auditwheel run on them.
-if [[ ${package_name} == "cugraph-equivariant" ]]; then
- RAPIDS_PY_WHEEL_NAME="${package_name}_${RAPIDS_PY_CUDA_SUFFIX}" RAPIDS_PY_WHEEL_PURE="1" rapids-upload-wheels-to-s3 python dist
-else
- case "${RAPIDS_CUDA_VERSION}" in
- 12.*)
- EXCLUDE_ARGS=(
- --exclude "libcublas.so.12"
- --exclude "libcublasLt.so.12"
- --exclude "libcurand.so.10"
- --exclude "libcusolver.so.11"
- --exclude "libcusparse.so.12"
- --exclude "libnvJitLink.so.12"
- )
- ;;
- 11.*)
- EXCLUDE_ARGS=()
- ;;
- esac
-
- mkdir -p final_dist
- python -m auditwheel repair -w final_dist "${EXCLUDE_ARGS[@]}" dist/*
- RAPIDS_PY_WHEEL_NAME="${package_name}_${RAPIDS_PY_CUDA_SUFFIX}" rapids-upload-wheels-to-s3 python final_dist
-fi
+case "${RAPIDS_CUDA_VERSION}" in
+ 12.*)
+ EXCLUDE_ARGS=(
+ --exclude "libcublas.so.12"
+ --exclude "libcublasLt.so.12"
+ --exclude "libcurand.so.10"
+ --exclude "libcusolver.so.11"
+ --exclude "libcusparse.so.12"
+ --exclude "libnvJitLink.so.12"
+ )
+ ;;
+ 11.*)
+ EXCLUDE_ARGS=()
+ ;;
+esac
+
+mkdir -p final_dist
+python -m auditwheel repair -w final_dist "${EXCLUDE_ARGS[@]}" dist/*
+RAPIDS_PY_WHEEL_NAME="${package_name}_${RAPIDS_PY_CUDA_SUFFIX}" rapids-upload-wheels-to-s3 python final_dist
diff --git a/ci/build_wheel_cugraph-equivariant.sh b/ci/build_wheel_cugraph-equivariant.sh
deleted file mode 100755
index 2f270422f84..00000000000
--- a/ci/build_wheel_cugraph-equivariant.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2024, NVIDIA CORPORATION.
-
-set -euo pipefail
-
-package_dir="python/cugraph-equivariant"
-
-./ci/build_wheel.sh cugraph-equivariant ${package_dir}
-./ci/validate_wheel.sh ${package_dir} dist
diff --git a/ci/release/update-version.sh b/ci/release/update-version.sh
index be1988e31dd..961f7816caa 100755
--- a/ci/release/update-version.sh
+++ b/ci/release/update-version.sh
@@ -51,8 +51,6 @@ NEXT_UCXX_SHORT_TAG_PEP440=$(python -c "from packaging.version import Version; p
DEPENDENCIES=(
cudf
cugraph
- cugraph-dgl
- cugraph-pyg
cugraph-service-server
cugraph-service-client
cuxfilter
@@ -75,7 +73,7 @@ DEPENDENCIES=(
UCXX_DEPENDENCIES=(
ucx-py
)
-for FILE in dependencies.yaml conda/environments/*.yaml python/cugraph-{pyg,dgl}/conda/*.yaml; do
+for FILE in dependencies.yaml conda/environments/*.yaml; do
for DEP in "${DEPENDENCIES[@]}"; do
sed_runner "/-.* ${DEP}\(-cu[[:digit:]]\{2\}\)\{0,1\}==/ s/==.*/==${NEXT_SHORT_TAG_PEP440}.*,>=0.0.0a0/g" "${FILE}"
done
diff --git a/ci/run_cugraph_dgl_pytests.sh b/ci/run_cugraph_dgl_pytests.sh
deleted file mode 100755
index 83c26a57dc0..00000000000
--- a/ci/run_cugraph_dgl_pytests.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2024, NVIDIA CORPORATION.
-
-set -euo pipefail
-
-# Support invoking run_cugraph_dgl_pytests.sh outside the script directory
-cd "$(dirname "$(realpath "${BASH_SOURCE[0]}")")"/../python/cugraph-dgl/tests
-
-pytest --cache-clear --ignore=mg "$@" .
diff --git a/ci/run_cugraph_equivariant_pytests.sh b/ci/run_cugraph_equivariant_pytests.sh
deleted file mode 100755
index 5d5a5fb05c2..00000000000
--- a/ci/run_cugraph_equivariant_pytests.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2024, NVIDIA CORPORATION.
-
-set -euo pipefail
-
-# Support invoking run_cugraph_equivariant_pytests.sh outside the script directory
-cd "$(dirname "$(realpath "${BASH_SOURCE[0]}")")"/../python/cugraph-equivariant/cugraph_equivariant
-
-pytest --cache-clear "$@" .
diff --git a/ci/run_cugraph_pyg_pytests.sh b/ci/run_cugraph_pyg_pytests.sh
deleted file mode 100755
index fb27f16d79e..00000000000
--- a/ci/run_cugraph_pyg_pytests.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2024, NVIDIA CORPORATION.
-
-set -euo pipefail
-
-# Support invoking run_cugraph_pyg_pytests.sh outside the script directory
-cd "$(dirname "$(realpath "${BASH_SOURCE[0]}")")"/../python/cugraph-pyg/cugraph_pyg
-
-pytest --cache-clear --benchmark-disable "$@" .
-
-# Used to skip certain examples in CI due to memory limitations
-export CI_RUN=1
-
-# Test examples
-for e in "$(pwd)"/examples/*.py; do
- rapids-logger "running example $e"
- (yes || true) | python $e
-done
diff --git a/ci/test.sh b/ci/test.sh
index 884ed7ac881..8e19b6c8c18 100755
--- a/ci/test.sh
+++ b/ci/test.sh
@@ -99,13 +99,6 @@ if hasArg "--run-python-tests"; then
pytest -sv -m sg -m "managedmem_on and poolallocator_on and tiny" --benchmark-disable
echo "Ran Python benchmarks for cuGraph (running as tests) : return code was: $?, test script exit code is now: $EXITCODE"
- echo "Python pytest for cugraph_pyg (single-GPU only)..."
- conda list
- cd ${CUGRAPH_ROOT}/python/cugraph-pyg/cugraph_pyg
- # rmat is not tested because of MG testing
- pytest -sv -m sg --cache-clear --junitxml=${CUGRAPH_ROOT}/junit-cugraph-pytests.xml -v --cov-config=.coveragerc --cov=cugraph_pyg --cov-report=xml:${WORKSPACE}/python/cugraph_pyg/cugraph-coverage.xml --cov-report term --ignore=raft --benchmark-disable
- echo "Ran Python pytest for cugraph_pyg : return code was: $?, test script exit code is now: $EXITCODE"
-
echo "Python pytest for cugraph-service (single-GPU only)..."
cd ${CUGRAPH_ROOT}/python/cugraph-service
pytest -sv --cache-clear --junitxml=${CUGRAPH_ROOT}/junit-cugraph-service-pytests.xml --benchmark-disable -k "not mg" ./tests
diff --git a/ci/test_python.sh b/ci/test_python.sh
index a3a177dcfc6..646b61805cc 100755
--- a/ci/test_python.sh
+++ b/ci/test_python.sh
@@ -100,42 +100,5 @@ rapids-logger "pytest cugraph-service (single GPU)"
--cov-report=xml:"${RAPIDS_COVERAGE_DIR}/cugraph-service-coverage.xml" \
--cov-report=term
-# test cugraph-equivariant
-if [[ "${RAPIDS_CUDA_VERSION}" == "11.8.0" ]]; then
- if [[ "${RUNNER_ARCH}" != "ARM64" ]]; then
- rapids-mamba-retry env create --yes -f env.yaml -n test_cugraph_equivariant
- set +u
- conda activate test_cugraph_equivariant
- set -u
- rapids-mamba-retry install \
- --channel "${CPP_CHANNEL}" \
- --channel "${PYTHON_CHANNEL}" \
- --channel conda-forge \
- --channel nvidia \
- "cugraph-equivariant=${RAPIDS_VERSION_MAJOR_MINOR}.*"
- pip install e3nn==0.5.1
-
- rapids-print-env
-
- rapids-logger "pytest cugraph-equivariant"
- ./ci/run_cugraph_equivariant_pytests.sh \
- --junitxml="${RAPIDS_TESTS_DIR}/junit-cugraph-equivariant.xml" \
- --cov-config=../../.coveragerc \
- --cov=cugraph_equivariant \
- --cov-report=xml:"${RAPIDS_COVERAGE_DIR}/cugraph-equivariant-coverage.xml" \
- --cov-report=term
-
- # Reactivate the test environment back
- set +u
- conda deactivate
- conda activate test
- set -u
- else
- rapids-logger "skipping cugraph-equivariant pytest on ARM64"
- fi
-else
- rapids-logger "skipping cugraph-equivariant pytest on CUDA!=11.8"
-fi
-
rapids-logger "Test script exiting with value: $EXITCODE"
exit ${EXITCODE}
diff --git a/ci/test_wheel_cugraph-equivariant.sh b/ci/test_wheel_cugraph-equivariant.sh
deleted file mode 100755
index 3be1d578964..00000000000
--- a/ci/test_wheel_cugraph-equivariant.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2024, NVIDIA CORPORATION.
-
-set -eoxu pipefail
-
-package_name="cugraph-equivariant"
-
-mkdir -p ./dist
-RAPIDS_PY_CUDA_SUFFIX="$(rapids-wheel-ctk-name-gen ${RAPIDS_CUDA_VERSION})"
-
-# Download the cugraph-equivariant built in the previous step
-RAPIDS_PY_WHEEL_NAME="${package_name}_${RAPIDS_PY_CUDA_SUFFIX}" RAPIDS_PY_WHEEL_PURE="1" rapids-download-wheels-from-s3 ./dist
-
-# determine pytorch source
-PKG_CUDA_VER="$(echo ${CUDA_VERSION} | cut -d '.' -f1,2 | tr -d '.')"
-PKG_CUDA_VER_MAJOR=${PKG_CUDA_VER:0:2}
-if [[ "${PKG_CUDA_VER_MAJOR}" == "12" ]]; then
- PYTORCH_CUDA_VER="121"
-else
- PYTORCH_CUDA_VER=$PKG_CUDA_VER
-fi
-PYTORCH_URL="https://download.pytorch.org/whl/cu${PYTORCH_CUDA_VER}"
-
-# echo to expand wildcard before adding `[extra]` requires for pip
-python -m pip install \
- -v \
- --extra-index-url "${PYTORCH_URL}" \
- "$(echo ./dist/cugraph_equivariant_${RAPIDS_PY_CUDA_SUFFIX}*.whl)[test]" \
- 'e3nn' \
- 'torch>=2.3.0,<2.4'
-
-python -m pytest python/cugraph-equivariant/cugraph_equivariant/tests
diff --git a/conda/environments/all_cuda-118_arch-x86_64.yaml b/conda/environments/all_cuda-118_arch-x86_64.yaml
index 62e8aa355c3..5275d608440 100644
--- a/conda/environments/all_cuda-118_arch-x86_64.yaml
+++ b/conda/environments/all_cuda-118_arch-x86_64.yaml
@@ -4,7 +4,6 @@ channels:
- rapidsai
- rapidsai-nightly
- dask/label/dev
-- dglteam/label/th23_cu118
- conda-forge
- nvidia
dependencies:
@@ -34,7 +33,6 @@ dependencies:
- nbsphinx
- nccl>=2.19
- networkx>=2.5.1
-- networkx>=3.0
- ninja
- notebook>=0.5.0
- numba>=0.57
@@ -53,10 +51,9 @@ dependencies:
- pytest
- pytest-benchmark
- pytest-cov
-- pytest-mpl
- pytest-xdist
- python-louvain
-- pytorch>=2.3,<2.4.0a0
+- pytorch>=2.3
- raft-dask==25.2.*,>=0.0.0a0
- rapids-build-backend>=0.3.1,<0.4.0.dev0
- rapids-dask-dependency==25.2.*,>=0.0.0a0
diff --git a/conda/environments/all_cuda-125_arch-x86_64.yaml b/conda/environments/all_cuda-125_arch-x86_64.yaml
index f5345708dc8..33c9be9cdda 100644
--- a/conda/environments/all_cuda-125_arch-x86_64.yaml
+++ b/conda/environments/all_cuda-125_arch-x86_64.yaml
@@ -4,7 +4,6 @@ channels:
- rapidsai
- rapidsai-nightly
- dask/label/dev
-- dglteam/label/th23_cu118
- conda-forge
- nvidia
dependencies:
@@ -40,7 +39,6 @@ dependencies:
- nbsphinx
- nccl>=2.19
- networkx>=2.5.1
-- networkx>=3.0
- ninja
- notebook>=0.5.0
- numba>=0.57
@@ -58,10 +56,9 @@ dependencies:
- pytest
- pytest-benchmark
- pytest-cov
-- pytest-mpl
- pytest-xdist
- python-louvain
-- pytorch>=2.3,<2.4.0a0
+- pytorch>=2.3
- raft-dask==25.2.*,>=0.0.0a0
- rapids-build-backend>=0.3.1,<0.4.0.dev0
- rapids-dask-dependency==25.2.*,>=0.0.0a0
diff --git a/conda/recipes/cugraph-dgl/build.sh b/conda/recipes/cugraph-dgl/build.sh
deleted file mode 100644
index 14d29b7eab9..00000000000
--- a/conda/recipes/cugraph-dgl/build.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (c) 2022, NVIDIA CORPORATION.
-
-# This assumes the script is executed from the root of the repo directory
-
-./build.sh cugraph-dgl
diff --git a/conda/recipes/cugraph-dgl/meta.yaml b/conda/recipes/cugraph-dgl/meta.yaml
deleted file mode 100644
index 0383fc8adf8..00000000000
--- a/conda/recipes/cugraph-dgl/meta.yaml
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (c) 2023-2024, NVIDIA CORPORATION.
-
-{% set version = environ['RAPIDS_PACKAGE_VERSION'].lstrip('v') + environ.get('VERSION_SUFFIX', '') %}
-{% set minor_version = version.split('.')[0] + '.' + version.split('.')[1] %}
-{% set py_version = environ['CONDA_PY'] %}
-{% set date_string = environ['RAPIDS_DATE_STRING'] %}
-
-package:
- name: cugraph-dgl
- version: {{ version }}
-
-source:
- path: ../../..
-
-build:
- number: {{ GIT_DESCRIBE_NUMBER }}
- build:
- number: {{ GIT_DESCRIBE_NUMBER }}
- string: py{{ py_version }}_{{ date_string }}_{{ GIT_DESCRIBE_HASH }}_{{ GIT_DESCRIBE_NUMBER }}
-
-requirements:
- host:
- - python
- - rapids-build-backend>=0.3.1,<0.4.0.dev0
- - setuptools>=61.0.0
- run:
- - cugraph ={{ version }}
- - dgl >=2.4.0.th23.cu*
- - numba >=0.57
- - numpy >=1.23,<3.0a0
- - pylibcugraphops ={{ minor_version }}
- - tensordict >=0.1.2
- - python
- - pytorch >=2.3,<2.4.0a0
- - cupy >=12.0.0
-
-tests:
- imports:
- - cugraph_dgl
-
-about:
- home: https://rapids.ai/
- dev_url: https://github.com/rapidsai/cugraph
- license: Apache-2.0
- license_file: ../../../LICENSE
- summary: cuGraph library
diff --git a/conda/recipes/cugraph-equivariant/build.sh b/conda/recipes/cugraph-equivariant/build.sh
deleted file mode 100644
index f0ff1688b55..00000000000
--- a/conda/recipes/cugraph-equivariant/build.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (c) 2024, NVIDIA CORPORATION.
-
-# This assumes the script is executed from the root of the repo directory
-
-./build.sh cugraph-equivariant
diff --git a/conda/recipes/cugraph-equivariant/meta.yaml b/conda/recipes/cugraph-equivariant/meta.yaml
deleted file mode 100644
index 9dc9d51fa48..00000000000
--- a/conda/recipes/cugraph-equivariant/meta.yaml
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) 2024, NVIDIA CORPORATION.
-
-{% set version = environ['RAPIDS_PACKAGE_VERSION'].lstrip('v') + environ.get('VERSION_SUFFIX', '') %}
-{% set minor_version = version.split('.')[0] + '.' + version.split('.')[1] %}
-{% set py_version = environ['CONDA_PY'] %}
-{% set date_string = environ['RAPIDS_DATE_STRING'] %}
-
-package:
- name: cugraph-equivariant
- version: {{ version }}
-
-source:
- path: ../../..
-
-build:
- number: {{ GIT_DESCRIBE_NUMBER }}
- build:
- number: {{ GIT_DESCRIBE_NUMBER }}
- string: py{{ py_version }}_{{ date_string }}_{{ GIT_DESCRIBE_HASH }}_{{ GIT_DESCRIBE_NUMBER }}
-
-requirements:
- host:
- - python
- - rapids-build-backend>=0.3.1,<0.4.0.dev0
- - setuptools>=61.0.0
- run:
- - pylibcugraphops ={{ minor_version }}
- - python
-
-tests:
- imports:
- - cugraph_equivariant
-
-about:
- home: https://rapids.ai/
- dev_url: https://github.com/rapidsai/cugraph
- license: Apache-2.0
- license_file: ../../../LICENSE
- summary: GPU-accelerated equivariant convolutional layers.
diff --git a/conda/recipes/cugraph-pyg/build.sh b/conda/recipes/cugraph-pyg/build.sh
deleted file mode 100644
index ad2502985e5..00000000000
--- a/conda/recipes/cugraph-pyg/build.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-# Copyright (c) 2022, NVIDIA CORPORATION.
-
-# This assumes the script is executed from the root of the repo directory
-./build.sh cugraph-pyg --allgpuarch
diff --git a/conda/recipes/cugraph-pyg/conda_build_config.yaml b/conda/recipes/cugraph-pyg/conda_build_config.yaml
deleted file mode 100644
index 47d98b4800b..00000000000
--- a/conda/recipes/cugraph-pyg/conda_build_config.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (c) 2022, NVIDIA CORPORATION.
-
-c_compiler_version:
- - 11
-
-cxx_compiler_version:
- - 11
-
-cuda_compiler:
- - nvcc
-
-cmake_version:
- - ">=3.26.4,!=3.30.0"
-
-c_stdlib:
- - sysroot
-
-c_stdlib_version:
- - "2.17"
diff --git a/conda/recipes/cugraph-pyg/meta.yaml b/conda/recipes/cugraph-pyg/meta.yaml
deleted file mode 100644
index 7d3e503e23a..00000000000
--- a/conda/recipes/cugraph-pyg/meta.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (c) 2022-2024, NVIDIA CORPORATION.
-
-{% set version = environ['RAPIDS_PACKAGE_VERSION'].lstrip('v') + environ.get('VERSION_SUFFIX', '') %}
-{% set minor_version = version.split('.')[0] + '.' + version.split('.')[1] %}
-{% set py_version = environ['CONDA_PY'] %}
-{% set date_string = environ['RAPIDS_DATE_STRING'] %}
-
-package:
- name: cugraph-pyg
- version: {{ version }}
-
-source:
- path: ../../..
-
-build:
- number: {{ GIT_DESCRIBE_NUMBER }}
- string: py{{ py_version }}_{{ date_string }}_{{ GIT_DESCRIBE_HASH }}_{{ GIT_DESCRIBE_NUMBER }}
- script_env:
- - PARALLEL_LEVEL
-
-requirements:
- build:
- - {{ stdlib("c") }}
- host:
- - cython >=3.0.0
- - python
- - rapids-build-backend>=0.3.1,<0.4.0.dev0
- - setuptools>=61.0.0
- run:
- - rapids-dask-dependency ={{ minor_version }}
- - numba >=0.57
- - numpy >=1.23,<3.0a0
- - python
- - pytorch >=2.3,<2.4.0a0
- - cupy >=12.0.0
- - cugraph ={{ version }}
- - pylibcugraphops ={{ minor_version }}
- - tensordict >=0.1.2
- - pytorch_geometric >=2.5,<2.6
-
-tests:
- imports:
- - cugraph_pyg
-
-about:
- home: https://rapids.ai/
- dev_url: https://github.com/rapidsai/cugraph
- license: Apache-2.0
- license_file: ../../../LICENSE
- summary: cuGraph-pyg library
diff --git a/conda/recipes/nx-cugraph/build.sh b/conda/recipes/nx-cugraph/build.sh
deleted file mode 100644
index 26665c1e76a..00000000000
--- a/conda/recipes/nx-cugraph/build.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (c) 2023, NVIDIA CORPORATION.
-
-# This assumes the script is executed from the root of the repo directory
-
-./build.sh nx-cugraph
diff --git a/conda/recipes/nx-cugraph/meta.yaml b/conda/recipes/nx-cugraph/meta.yaml
deleted file mode 100644
index 263f53d9a8f..00000000000
--- a/conda/recipes/nx-cugraph/meta.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (c) 2023-2024, NVIDIA CORPORATION.
-
-{% set version = environ['RAPIDS_PACKAGE_VERSION'].lstrip('v') + environ.get('VERSION_SUFFIX', '') %}
-{% set minor_version = version.split('.')[0] + '.' + version.split('.')[1] %}
-{% set py_version = environ['CONDA_PY'] %}
-{% set date_string = environ['RAPIDS_DATE_STRING'] %}
-
-package:
- name: nx-cugraph
- version: {{ version }}
-
-source:
- path: ../../..
-
-build:
- number: {{ GIT_DESCRIBE_NUMBER }}
- string: py{{ py_version }}_{{ date_string }}_{{ GIT_DESCRIBE_HASH }}_{{ GIT_DESCRIBE_NUMBER }}
-
-requirements:
- host:
- - python
- - rapids-build-backend>=0.3.1,<0.4.0.dev0
- - setuptools>=61.0.0
- run:
- - pylibcugraph ={{ version }}
- - networkx >=3.0
- - cupy >=12.0.0
- - python
-
-tests:
- imports:
- - nx_cugraph
- commands:
- - pip check
- requires:
- - pip
-
-about:
- home: https://rapids.ai/
- dev_url: https://github.com/rapidsai/cugraph
- license: Apache-2.0
- license_file: ../../../LICENSE
- summary: cuGraph backend for GPU-accelerated NetworkX
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index 2cea2e504ab..65772b4f5dd 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -167,6 +167,7 @@ set(CUGRAPH_SOURCES
src/detail/groupby_and_count_mg_v64_e64.cu
src/detail/collect_comm_wrapper_mg_v32_e32.cu
src/detail/collect_comm_wrapper_mg_v64_e64.cu
+ src/sampling/detail/conversion_utilities.cu
src/sampling/random_walks_mg_v64_e64.cu
src/sampling/random_walks_mg_v32_e32.cu
src/community/detail/common_methods_mg_v64_e64.cu
@@ -264,10 +265,10 @@ set(CUGRAPH_SOURCES
src/sampling/detail/sample_edges_mg_v32_e32.cu
src/sampling/detail/shuffle_and_organize_output_mg_v64_e64.cu
src/sampling/detail/shuffle_and_organize_output_mg_v32_e32.cu
- src/sampling/neighbor_sampling_mg_v32_e32.cpp
- src/sampling/neighbor_sampling_mg_v64_e64.cpp
- src/sampling/neighbor_sampling_sg_v32_e32.cpp
- src/sampling/neighbor_sampling_sg_v64_e64.cpp
+ src/sampling/neighbor_sampling_mg_v32_e32.cu
+ src/sampling/neighbor_sampling_mg_v64_e64.cu
+ src/sampling/neighbor_sampling_sg_v32_e32.cu
+ src/sampling/neighbor_sampling_sg_v64_e64.cu
src/sampling/negative_sampling_sg_v32_e32.cu
src/sampling/negative_sampling_sg_v64_e64.cu
src/sampling/negative_sampling_mg_v32_e32.cu
@@ -537,6 +538,8 @@ add_library(cugraph_c
src/c_api/weakly_connected_components.cpp
src/c_api/strongly_connected_components.cpp
src/c_api/allgather.cpp
+ src/c_api/decompress_to_edgelist.cpp
+ src/c_api/edgelist.cpp
)
add_library(cugraph::cugraph_c ALIAS cugraph_c)
diff --git a/cpp/include/cugraph/detail/utility_wrappers.hpp b/cpp/include/cugraph/detail/utility_wrappers.hpp
index 3d99b85556b..b1afeafd66b 100644
--- a/cpp/include/cugraph/detail/utility_wrappers.hpp
+++ b/cpp/include/cugraph/detail/utility_wrappers.hpp
@@ -65,6 +65,48 @@ void uniform_random_fill(rmm::cuda_stream_view const& stream_view,
template
void scalar_fill(raft::handle_t const& handle, value_t* d_value, size_t size, value_t value);
+/**
+ * @brief Sort a device span
+ *
+ * @tparam value_t type of the value to operate on. Must be either int32_t or int64_t.
+ *
+ * @param [in] handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator,
+ * and handles to various CUDA libraries) to run graph algorithms.
+ * @param[out] values device span to sort
+ *
+ */
+template
+void sort_ints(raft::handle_t const& handle, raft::device_span values);
+
+/**
+ * @brief Keep unique element from a device span
+ *
+ * @tparam value_t type of the value to operate on. Must be either int32_t or int64_t.
+ *
+ * @param [in] handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator,
+ * and handles to various CUDA libraries) to run graph algorithms.
+ * @param[in] values device span of unique elements.
+ * @return the number of unique elements.
+ *
+ */
+template
+size_t unique_ints(raft::handle_t const& handle, raft::device_span values);
+
+/**
+ * @brief Increment the values of a device span by a constant value
+ *
+ * @tparam value_t type of the value to operate on. Must be either int32_t or int64_t.
+ *
+ * @param[out] values device span to update
+ * @param[in] value value to be added to each element of the buffer
+ * @param[in] stream_view stream view
+ *
+ */
+template
+void transform_increment_ints(raft::device_span values,
+ value_t value,
+ rmm::cuda_stream_view const& stream_view);
+
/**
* @brief Fill a buffer with a sequence of values
*
@@ -73,7 +115,7 @@ void scalar_fill(raft::handle_t const& handle, value_t* d_value, size_t size, va
*
* Similar to the function std::iota, wraps the function thrust::sequence
*
- * @tparam value_t type of the value to operate on
+ * @tparam value_t type of the value to operate on.
*
* @param[in] stream_view stream view
* @param[out] d_value device array to fill
diff --git a/cpp/include/cugraph/sampling_functions.hpp b/cpp/include/cugraph/sampling_functions.hpp
index 783cd3a7e2b..3d41e954416 100644
--- a/cpp/include/cugraph/sampling_functions.hpp
+++ b/cpp/include/cugraph/sampling_functions.hpp
@@ -43,6 +43,8 @@ enum class prior_sources_behavior_t { DEFAULT = 0, CARRY_OVER, EXCLUDE };
/**
* @brief Uniform Neighborhood Sampling.
*
+ * @deprecated Replaced with homogeneous_uniform_neighbor_sample
+ *
* This function traverses from a set of starting vertices, traversing outgoing edges and
* randomly selects from these outgoing neighbors to extract a subgraph.
*
@@ -53,19 +55,20 @@ enum class prior_sources_behavior_t { DEFAULT = 0, CARRY_OVER, EXCLUDE };
* encountered in. The label output (optional) identifes the vertex label. The offsets array
* (optional) will be described below and is dependent upon the input parameters.
*
- * If @p starting_vertex_labels is not specified then no organization is applied to the output, the
- * label and offsets values in the return set will be std::nullopt.
+ * If @p starting_vertex_label_offsets is not specified then no organization is applied to the
+ * output, the label and offsets values in the return set will be std::nullopt.
*
- * If @p starting_vertex_labels is specified and @p label_to_output_comm_rank is not specified then
- * the label output has values. This will also result in the output being sorted by vertex label.
- * The offsets array in the return will be a CSR-style offsets array to identify the beginning of
- * each label range in the data. `labels.size() == (offsets.size() - 1)`.
+ * If @p starting_vertex_label_offsets is specified and @p label_to_output_comm_rank is not
+ * specified then the label output has values. This will also result in the output being sorted by
+ * vertex label. The offsets array in the return will be a CSR-style offsets array to identify the
+ * beginning of each label range in the data. `labels.size() == (offsets.size() - 1)`.
*
- * If @p starting_vertex_labels is specified and @p label_to_output_comm_rank is specified then the
- * label output has values. This will also result in the output being sorted by vertex label. The
- * offsets array in the return will be a CSR-style offsets array to identify the beginning of each
- * label range in the data. `labels.size() == (offsets.size() - 1)`. Additionally, the data will
- * be shuffled so that all data with a particular label will be on the specified rank.
+ * If @p starting_vertex_label_offsets is specified and @p label_to_output_comm_rank is specified
+ * then the label output has values. This will also result in the output being sorted by vertex
+ * label. The offsets array in the return will be a CSR-style offsets array to identify the
+ * beginning of each label range in the data. `labels.size() == (offsets.size() - 1)`.
+ * Additionally, the data will be shuffled so that all data with a particular label will be on the
+ * specified rank.
*
* @tparam vertex_t Type of vertex identifiers. Needs to be an integral type.
* @tparam edge_t Type of edge identifiers. Needs to be an integral type.
@@ -83,8 +86,8 @@ enum class prior_sources_behavior_t { DEFAULT = 0, CARRY_OVER, EXCLUDE };
* @param edge_type_view Optional view object holding edge types for @p graph_view.
* @param starting_vertices Device span of starting vertex IDs for the sampling.
* In a multi-gpu context the starting vertices should be local to this GPU.
- * @param starting_vertex_labels Optional device span of labels associted with each starting vertex
- * for the sampling.
+ * @param starting_vertex_label_offsets Optional device span of labels associated with each starting
+ * vertex for the sampling.
* @param label_to_output_comm_rank Optional tuple of device spans mapping label to a particular
* output rank. Element 0 of the tuple identifes the label, Element 1 of the tuple identifies the
* output rank. The label span must be sorted in ascending order.
@@ -126,7 +129,7 @@ uniform_neighbor_sample(
std::optional> edge_id_view,
std::optional> edge_type_view,
raft::device_span starting_vertices,
- std::optional> starting_vertex_labels,
+ std::optional> starting_vertex_label_offsets,
std::optional, raft::device_span>>
label_to_output_comm_rank,
raft::host_span fan_out,
@@ -140,6 +143,8 @@ uniform_neighbor_sample(
/**
* @brief Biased Neighborhood Sampling.
*
+ * @deprecated Replaced with homogeneous_biased_neighbor_sample
+ *
* This function traverses from a set of starting vertices, traversing outgoing edges and
* randomly selects (with edge biases) from these outgoing neighbors to extract a subgraph.
*
@@ -150,24 +155,26 @@ uniform_neighbor_sample(
* encountered in. The label output (optional) identifes the vertex label. The offsets array
* (optional) will be described below and is dependent upon the input parameters.
*
- * If @p starting_vertex_labels is not specified then no organization is applied to the output, the
- * label and offsets values in the return set will be std::nullopt.
+ * If @p starting_vertex_label_offsets is not specified then no organization is applied to the
+ * output, the label and offsets values in the return set will be std::nullopt.
*
- * If @p starting_vertex_labels is specified and @p label_to_output_comm_rank is not specified then
- * the label output has values. This will also result in the output being sorted by vertex label.
- * The offsets array in the return will be a CSR-style offsets array to identify the beginning of
- * each label range in the data. `labels.size() == (offsets.size() - 1)`.
+ * If @p starting_vertex_label_offsets is specified and @p label_to_output_comm_rank is not
+ * specified then the label output has values. This will also result in the output being sorted by
+ * vertex label. The offsets array in the return will be a CSR-style offsets array to identify the
+ * beginning of each label range in the data. `labels.size() == (offsets.size() - 1)`.
*
- * If @p starting_vertex_labels is specified and @p label_to_output_comm_rank is specified then the
- * label output has values. This will also result in the output being sorted by vertex label. The
- * offsets array in the return will be a CSR-style offsets array to identify the beginning of each
- * label range in the data. `labels.size() == (offsets.size() - 1)`. Additionally, the data will
- * be shuffled so that all data with a particular label will be on the specified rank.
+ * If @p starting_vertex_label_offsets is specified and @p label_to_output_comm_rank is specified
+ * then the label output has values. This will also result in the output being sorted by vertex
+ * label. The offsets array in the return will be a CSR-style offsets array to identify the
+ * beginning of each label range in the data. `labels.size() == (offsets.size() - 1)`.
+ * Additionally, the data will be shuffled so that all data with a particular label will be on the
+ * specified rank.
*
* @tparam vertex_t Type of vertex identifiers. Needs to be an integral type.
* @tparam edge_t Type of edge identifiers. Needs to be an integral type.
* @tparam weight_t Type of edge weights. Needs to be a floating point type.
* @tparam edge_type_t Type of edge type. Needs to be an integral type.
+ * @tparam bias_t Type of bias. Needs to be an integral type.
* @tparam label_t Type of label. Needs to be an integral type.
* @tparam store_transposed Flag indicating whether sources (if false) or destinations (if
* true) are major indices
@@ -184,8 +191,8 @@ uniform_neighbor_sample(
* corresponding edge can never be selected.
* @param starting_vertices Device span of starting vertex IDs for the sampling.
* In a multi-gpu context the starting vertices should be local to this GPU.
- * @param starting_vertex_labels Optional device span of labels associted with each starting vertex
- * for the sampling.
+ * @param starting_vertex_label_offsets Optional device span of labels associated with each starting
+ * vertex for the sampling.
* @param label_to_output_comm_rank Optional tuple of device spans mapping label to a particular
* output rank. Element 0 of the tuple identifes the label, Element 1 of the tuple identifies the
* output rank. The label span must be sorted in ascending order.
@@ -229,7 +236,7 @@ biased_neighbor_sample(
std::optional> edge_type_view,
edge_property_view_t edge_bias_view,
raft::device_span starting_vertices,
- std::optional> starting_vertex_labels,
+ std::optional> starting_vertex_label_offsets,
std::optional, raft::device_span>>
label_to_output_comm_rank,
raft::host_span fan_out,
@@ -240,6 +247,349 @@ biased_neighbor_sample(
bool dedupe_sources = false,
bool do_expensive_check = false);
+struct sampling_flags_t {
+ /**
+ * Specifies how to handle prior sources. Default is DEFAULT.
+ */
+ prior_sources_behavior_t prior_sources_behavior{};
+
+ /**
+ * Specifies if the hop information should be returned. Default is false.
+ */
+ bool return_hops{false};
+
+ /**
+ * If true then if a vertex v appears as a destination in hop X multiple times
+ * with the same label, it will only be passed once (for each label) as a source
+ * for the next hop. Default is false.
+ */
+ bool dedupe_sources{false};
+
+ /**
+ * Specifies if random sampling is done with replacement
+ * (true) or without replacement (false). Default is true.
+ */
+ bool with_replacement{true};
+};
+
+/**
+ * @brief Homogeneous Uniform Neighborhood Sampling.
+ *
+ * This function traverses from a set of starting vertices, traversing outgoing edges and
+ * randomly selects (uniformly) from these outgoing neighbors to extract a subgraph.
+ * The branching out to select outgoing neighbors is performed with homogeneous fanouts
+ *
+ * Output from this function is a tuple of vectors (src, dst, weight, edge_id, edge_type, hop,
+ * offsets), identifying the randomly selected edges where the size of src, dst, weight, edge_id,
+ * edge_type and hop is the number of sampled edges while the size of the offsets vector is the
+ * number of labels + 1. src is the source vertex, dst is the destination vertex, weight
+ * (optional) is the edge weight, edge_id (optional) identifies the edge id, edge_type (optional)
+ * identifies the edge type, hop identifies which hop the edge was encountered in.
+ * The offsets array (optional) identifies the offset for each label.
+ *
+ * If @p label_to_output_comm_rank is specified then the data will be shuffled so that all entries
+ * for a particular label are returned on the specified rank.
+ *
+ * @tparam vertex_t Type of vertex identifiers. Needs to be an integral type.
+ * @tparam edge_t Type of edge identifiers. Needs to be an integral type.
+ * @tparam weight_t Type of edge weights. Needs to be a floating point type.
+ * @tparam edge_type_t Type of edge type. Needs to be an integral type.
+ * @tparam store_transposed Flag indicating whether sources (if false) or destinations (if
+ * true) are major indices
+ * @tparam multi_gpu Flag indicating whether template instantiation should target single-GPU (false)
+ * @param handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, and
+ * handles to various CUDA libraries) to run graph algorithms.
+ * @param rng_state A pre-initialized raft::RngState object for generating random numbers
+ * @param graph_view Graph View object to generate NBR Sampling on.
+ * @param edge_weight_view Optional view object holding edge weights for @p graph_view.
+ * @param edge_id_view Optional view object holding edge ids for @p graph_view.
+ * @param edge_type_view Optional view object holding edge types for @p graph_view.
+ * @param starting_vertices Device span of starting vertex IDs for the sampling.
+ * In a multi-gpu context the starting vertices should be local to this GPU.
+ * @param starting_vertex_label_offsets Optional device span of labels associated with each starting
+ * vertex for the sampling.
+ * @param label_to_output_comm_rank Optional device span identifying which rank should get sampling
+ * outputs of each vertex label. This should be the same on each rank.
+ * @param fan_out Host span defining branching out (fan-out) degree per source vertex for each
+ * level.
+ * @param flags A set of flags indicating which sampling features should be used.
+ * @param do_expensive_check A flag to run expensive checks for input arguments (if set to `true`).
+ * @return tuple device vectors (vertex_t source_vertex, vertex_t destination_vertex,
+ * optional weight_t weight, optional edge_t edge id, optional edge_type_t edge type,
+ * optional int32_t hop, optional label_t label, optional size_t offsets)
+ */
+
+template
+std::tuple,
+ rmm::device_uvector,
+ std::optional>,
+ std::optional>,
+ std::optional>,
+ std::optional>,
+ std::optional>>
+homogeneous_uniform_neighbor_sample(
+ raft::handle_t const& handle,
+ raft::random::RngState& rng_state,
+ graph_view_t const& graph_view,
+ std::optional> edge_weight_view,
+ std::optional> edge_id_view,
+ std::optional> edge_type_view,
+ raft::device_span starting_vertices,
+ std::optional> starting_vertex_label_offsets,
+ std::optional> label_to_output_comm_rank,
+ raft::host_span fan_out,
+ sampling_flags_t sampling_flags,
+ bool do_expensive_check = false);
+
+/**
+ * @brief Homogeneous Biased Neighborhood Sampling.
+ *
+ * This function traverses from a set of starting vertices, traversing outgoing edges and
+ * randomly selects (with edge biases) from these outgoing neighbors to extract a subgraph.
+ * The branching out to select outgoing neighbors is performed with homogeneous fanouts
+ *
+ * Output from this function is a tuple of vectors (src, dst, weight, edge_id, edge_type, hop,
+ * offsets), identifying the randomly selected edges where the size of src, dst, weight, edge_id,
+ * edge_type and hop is the number of sampled edges while the size of the offsets vector is the
+ * number of labels + 1. src is the source vertex, dst is the destination vertex, weight
+ * (optional) is the edge weight, edge_id (optional) identifies the edge id, edge_type (optional)
+ * identifies the edge type, hop identifies which hop the edge was encountered in.
+ * The offsets array (optional) identifies the offset for each label.
+ *
+ * If @p label_to_output_comm_rank is specified then the data will be shuffled so that all entries
+ * for a particular label are returned on the specified rank.
+ *
+ * @tparam vertex_t Type of vertex identifiers. Needs to be an integral type.
+ * @tparam edge_t Type of edge identifiers. Needs to be an integral type.
+ * @tparam weight_t Type of edge weights. Needs to be a floating point type.
+ * @tparam edge_type_t Type of edge type. Needs to be an integral type.
+ * @tparam bias_t Type of bias. Needs to be an integral type.
+ * @tparam store_transposed Flag indicating whether sources (if false) or destinations (if
+ * true) are major indices
+ * @tparam multi_gpu Flag indicating whether template instantiation should target single-GPU (false)
+ * @param handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, and
+ * handles to various CUDA libraries) to run graph algorithms.
+ * @param rng_state A pre-initialized raft::RngState object for generating random numbers
+ * @param graph_view Graph View object to generate NBR Sampling on.
+ * @param edge_weight_view Optional view object holding edge weights for @p graph_view.
+ * @param edge_id_view Optional view object holding edge ids for @p graph_view.
+ * @param edge_type_view Optional view object holding edge types for @p graph_view.
+ * @param edge_bias_view View object holding edge biases (to be used in biased sampling) for @p
+ * graph_view. Bias values should be non-negative and the sum of edge bias values from any vertex
+ * should not exceed std::numeric_limits::max(). 0 bias value indicates that the
+ * corresponding edge can never be selected.
+ * @param starting_vertices Device span of starting vertex IDs for the sampling.
+ * In a multi-gpu context the starting vertices should be local to this GPU.
+ * @param starting_vertex_label_offsets Optional device span of labels associated with each starting
+ * vertex for the sampling.
+ * @param label_to_output_comm_rank Optional device span identifying which rank should get sampling
+ * outputs of each vertex label. This should be the same on each rank.
+ * @param fan_out Host span defining branching out (fan-out) degree per source vertex for each
+ * level.
+ * @param flags A set of flags indicating which sampling features should be used.
+ * @param do_expensive_check A flag to run expensive checks for input arguments (if set to `true`).
+ * @return tuple device vectors (vertex_t source_vertex, vertex_t destination_vertex,
+ * optional weight_t weight, optional edge_t edge id, optional edge_type_t edge type,
+ * optional int32_t hop, optional label_t label, optional size_t offsets)
+ */
+
+template
+std::tuple,
+ rmm::device_uvector,
+ std::optional>,
+ std::optional>,
+ std::optional>,
+ std::optional>,
+ std::optional>>
+homogeneous_biased_neighbor_sample(
+ raft::handle_t const& handle,
+ raft::random::RngState& rng_state,
+ graph_view_t const& graph_view,
+ std::optional> edge_weight_view,
+ std::optional> edge_id_view,
+ std::optional> edge_type_view,
+ edge_property_view_t edge_bias_view,
+ raft::device_span starting_vertices,
+ std::optional> starting_vertex_label_offsets,
+ std::optional> label_to_output_comm_rank,
+ raft::host_span fan_out,
+ sampling_flags_t sampling_flags,
+ bool do_expensive_check = false);
+
+/**
+ * @brief Heterogeneous Uniform Neighborhood Sampling.
+ *
+ * This function traverses from a set of starting vertices, traversing outgoing edges and
+ * randomly selects (uniformly) from these outgoing neighbors to extract a subgraph.
+ * The branching out to select outgoing neighbors is performed with heterogeneous fanouts
+ * where the number of edge types is bigger than 1.
+ *
+ * Output from this function is a tuple of vectors (src, dst, weight, edge_id, edge_type, hop,
+ * offsets), identifying the randomly selected edges where the size of src, dst, weight, edge_id,
+ * edge_type and hop is the number of sampled edges while the size of the offsets vector is the
+ * number of labels + 1. src is the source vertex, dst is the destination vertex, weight
+ * (optional) is the edge weight, edge_id (optional) identifies the edge id, edge_type (optional)
+ * identifies the edge type, hop identifies which hop the edge was encountered in.
+ * The offsets array (optional) identifies the offset for each label.
+ *
+ * If @p label_to_output_comm_rank is specified then the data will be shuffled so that all entries
+ * for a particular label are returned on the specified rank.
+ *
+ * @tparam vertex_t Type of vertex identifiers. Needs to be an integral type.
+ * @tparam edge_t Type of edge identifiers. Needs to be an integral type.
+ * @tparam weight_t Type of edge weights. Needs to be a floating point type.
+ * @tparam edge_type_t Type of edge type. Needs to be an integral type.
+ * @tparam store_transposed Flag indicating whether sources (if false) or destinations (if
+ * true) are major indices
+ * @tparam multi_gpu Flag indicating whether template instantiation should target single-GPU (false)
+ * @param handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, and
+ * handles to various CUDA libraries) to run graph algorithms.
+ * @param rng_state A pre-initialized raft::RngState object for generating random numbers
+ * @param graph_view Graph View object to generate NBR Sampling on.
+ * @param edge_weight_view Optional view object holding edge weights for @p graph_view.
+ * @param edge_id_view Optional view object holding edge ids for @p graph_view.
+ * @param edge_type_view Optional view object holding edge types for @p graph_view.
+ * @param starting_vertices Device span of starting vertex IDs for the sampling.
+ * In a multi-gpu context the starting vertices should be local to this GPU.
+ * @param starting_vertex_label_offsets Optional device span of labels associated with each starting
+ * vertex for the sampling.
+ * @param label_to_output_comm_rank Optional device span identifying which rank should get sampling
+ * outputs of each vertex label. This should be the same on each rank.
+ * @param fan_out Host span defining branching out (fan-out) degree per source vertex for each
+ * level. The fanout value at hop x is given by the expression 'fanout[x*num_edge_types +
+ * edge_type_id]'
+ * @param num_edge_types Number of edge types where a value of 1 translates to homogeneous neighbor
+ * sample whereas a value greater than 1 translates to heterogeneous neighbor sample.
+ * @param flags A set of flags indicating which sampling features should be used.
+ * @param do_expensive_check A flag to run expensive checks for input arguments (if set to `true`).
+ * @return tuple device vectors (vertex_t source_vertex, vertex_t destination_vertex,
+ * optional weight_t weight, optional edge_t edge id, optional edge_type_t edge type,
+ * optional int32_t hop, optional label_t label, optional size_t offsets)
+ */
+template
+std::tuple,
+ rmm::device_uvector,
+ std::optional>,
+ std::optional>,
+ std::optional>,
+ std::optional>,
+ std::optional>>
+heterogeneous_uniform_neighbor_sample(
+ raft::handle_t const& handle,
+ raft::random::RngState& rng_state,
+ graph_view_t const& graph_view,
+ std::optional> edge_weight_view,
+ std::optional> edge_id_view,
+ std::optional> edge_type_view,
+ raft::device_span starting_vertices,
+ std::optional> starting_vertex_label_offsets,
+ std::optional> label_to_output_comm_rank,
+ raft::host_span fan_out,
+ edge_type_t num_edge_types,
+ sampling_flags_t sampling_flags,
+ bool do_expensive_check = false);
+
+/**
+ * @brief Heterogeneous Biased Neighborhood Sampling.
+ *
+ * This function traverses from a set of starting vertices, traversing outgoing edges and
+ * randomly selects (with edge biases) from these outgoing neighbors to extract a subgraph.
+ * The branching out to select outgoing neighbors is performed with heterogeneous fanouts
+ * where the number of edge types is bigger than 1.
+ *
+ * Output from this function is a tuple of vectors (src, dst, weight, edge_id, edge_type, hop,
+ * offsets), identifying the randomly selected edges where the size of src, dst, weight, edge_id,
+ * edge_type and hop is the number of sampled edges while the size of the offsets vector is the
+ * number of labels + 1. src is the source vertex, dst is the destination vertex, weight
+ * (optional) is the edge weight, edge_id (optional) identifies the edge id, edge_type (optional)
+ * identifies the edge type, hop identifies which hop the edge was encountered in.
+ * The offsets array (optional) identifies the offset for each label.
+ *
+ * If @p label_to_output_comm_rank is specified then the data will be shuffled so that all entries
+ * for a particular label are returned on the specified rank.
+ *
+ * @tparam vertex_t Type of vertex identifiers. Needs to be an integral type.
+ * @tparam edge_t Type of edge identifiers. Needs to be an integral type.
+ * @tparam weight_t Type of edge weights. Needs to be a floating point type.
+ * @tparam edge_type_t Type of edge type. Needs to be an integral type.
+ * @tparam bias_t Type of bias. Needs to be an integral type.
+ * @tparam store_transposed Flag indicating whether sources (if false) or destinations (if
+ * true) are major indices
+ * @tparam multi_gpu Flag indicating whether template instantiation should target single-GPU (false)
+ * @param handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, and
+ * handles to various CUDA libraries) to run graph algorithms.
+ * @param rng_state A pre-initialized raft::RngState object for generating random numbers
+ * @param graph_view Graph View object to generate NBR Sampling on.
+ * @param edge_weight_view Optional view object holding edge weights for @p graph_view.
+ * @param edge_id_view Optional view object holding edge ids for @p graph_view.
+ * @param edge_type_view Optional view object holding edge types for @p graph_view.
+ * @param edge_bias_view View object holding edge biases (to be used in biased sampling) for @p
+ * graph_view. Bias values should be non-negative and the sum of edge bias values from any vertex
+ * should not exceed std::numeric_limits::max(). 0 bias value indicates that the
+ * corresponding edge can never be selected.
+ * @param starting_vertices Device span of starting vertex IDs for the sampling.
+ * In a multi-gpu context the starting vertices should be local to this GPU.
+ * @param starting_vertex_label_offsets Optional device span of labels associated with each starting
+ * vertex for the sampling.
+ * @param label_to_output_comm_rank Optional device span identifying which rank should get sampling
+ * outputs of each vertex label. This should be the same on each rank.
+ * @param fan_out Host span defining branching out (fan-out) degree per source vertex for each
+ * level. The fanout value at hop x is given by the expression 'fanout[x*num_edge_types +
+ * edge_type_id]'
+ * @param num_edge_types Number of edge types where a value of 1 translates to homogeneous neighbor
+ * sample whereas a value greater than 1 translates to heterogeneous neighbor sample.
+ * @param flags A set of flags indicating which sampling features should be used.
+ * @param do_expensive_check A flag to run expensive checks for input arguments (if set to `true`).
+ * @return tuple device vectors (vertex_t source_vertex, vertex_t destination_vertex,
+ * optional weight_t weight, optional edge_t edge id, optional edge_type_t edge type,
+ * optional int32_t hop, optional label_t label, optional size_t offsets)
+ */
+template
+std::tuple,
+ rmm::device_uvector,
+ std::optional>,
+ std::optional>,
+ std::optional>,
+ std::optional>,
+ std::optional>>
+heterogeneous_biased_neighbor_sample(
+ raft::handle_t const& handle,
+ raft::random::RngState& rng_state,
+ graph_view_t const& graph_view,
+ std::optional> edge_weight_view,
+ std::optional> edge_id_view,
+ std::optional> edge_type_view,
+ edge_property_view_t edge_bias_view,
+ raft::device_span starting_vertices,
+ std::optional> starting_vertex_label_offsets,
+ std::optional> label_to_output_comm_rank,
+ raft::host_span fan_out,
+ edge_type_t num_edge_types,
+ sampling_flags_t sampling_flags,
+ bool do_expensive_check = false);
+
/*
* @brief renumber sampled edge list and compress to the (D)CSR|(D)CSC format.
*
diff --git a/cpp/include/cugraph_c/graph_functions.h b/cpp/include/cugraph_c/graph_functions.h
index ff7e439232a..964b2f2c8d6 100644
--- a/cpp/include/cugraph_c/graph_functions.h
+++ b/cpp/include/cugraph_c/graph_functions.h
@@ -104,6 +104,8 @@ cugraph_error_code_t cugraph_two_hop_neighbors(
/**
* @brief Opaque induced subgraph type
+ *
+ * @deprecated This API will be deleted, use cugraph_edgelist_t
*/
typedef struct {
int32_t align_;
@@ -112,6 +114,8 @@ typedef struct {
/**
* @brief Get the source vertex ids
*
+ * @deprecated This API will be deleted, use cugraph_edgelist_get_sources
+ *
* @param [in] induced_subgraph Opaque pointer to induced subgraph
* @return type erased array view of source vertex ids
*/
@@ -121,6 +125,8 @@ cugraph_type_erased_device_array_view_t* cugraph_induced_subgraph_get_sources(
/**
* @brief Get the destination vertex ids
*
+ * @deprecated This API will be deleted, use cugraph_edgelist_get_destinations
+ *
* @param [in] induced_subgraph Opaque pointer to induced subgraph
* @return type erased array view of destination vertex ids
*/
@@ -130,6 +136,8 @@ cugraph_type_erased_device_array_view_t* cugraph_induced_subgraph_get_destinatio
/**
* @brief Get the edge weights
*
+ * @deprecated This API will be deleted, use cugraph_edgelist_get_edge_weights
+ *
* @param [in] induced_subgraph Opaque pointer to induced subgraph
* @return type erased array view of edge weights
*/
@@ -139,6 +147,8 @@ cugraph_type_erased_device_array_view_t* cugraph_induced_subgraph_get_edge_weigh
/**
* @brief Get the edge ids
*
+ * @deprecated This API will be deleted, use cugraph_edgelist_get_edge_ids
+ *
* @param [in] induced_subgraph Opaque pointer to induced subgraph
* @return type erased array view of edge ids
*/
@@ -148,6 +158,8 @@ cugraph_type_erased_device_array_view_t* cugraph_induced_subgraph_get_edge_ids(
/**
* @brief Get the edge types
*
+ * @deprecated This API will be deleted, use cugraph_edgelist_get_edge_type_ids
+ *
* @param [in] induced_subgraph Opaque pointer to induced subgraph
* @return type erased array view of edge types
*/
@@ -157,6 +169,8 @@ cugraph_type_erased_device_array_view_t* cugraph_induced_subgraph_get_edge_type_
/**
* @brief Get the subgraph offsets
*
+ * @deprecated This API will be deleted, use cugraph_edgelist_get_edge_offsets
+ *
* @param [in] induced_subgraph Opaque pointer to induced subgraph
* @return type erased array view of subgraph identifiers
*/
@@ -166,6 +180,8 @@ cugraph_type_erased_device_array_view_t* cugraph_induced_subgraph_get_subgraph_o
/**
* @brief Free induced subgraph
*
+ * @deprecated This API will be deleted, use cugraph_edgelist_free
+ *
* @param [in] induced subgraph Opaque pointer to induced subgraph
*/
void cugraph_induced_subgraph_result_free(cugraph_induced_subgraph_result_t* induced_subgraph);
@@ -361,6 +377,92 @@ cugraph_type_erased_device_array_view_t* cugraph_degrees_result_get_out_degrees(
*/
void cugraph_degrees_result_free(cugraph_degrees_result_t* degrees_result);
+/**
+ * @brief Opaque edgelist type
+ *
+ */
+typedef struct {
+ int32_t align_;
+} cugraph_edgelist_t;
+
+/**
+ * @brief Get the source vertex ids
+ *
+ * @param [in] edgelist Opaque pointer to edgelist
+ * @return type erased array view of source vertex ids
+ */
+cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_sources(cugraph_edgelist_t* edgelist);
+
+/**
+ * @brief Get the destination vertex ids
+ *
+ * @param [in] edgelist Opaque pointer to edgelist
+ * @return type erased array view of destination vertex ids
+ */
+cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_destinations(
+ cugraph_edgelist_t* edgelist);
+
+/**
+ * @brief Get the edge weights
+ *
+ * @param [in] edgelist Opaque pointer to edgelist
+ * @return type erased array view of edge weights
+ */
+cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_edge_weights(
+ cugraph_edgelist_t* edgelist);
+
+/**
+ * @brief Get the edge ids
+ *
+ * @param [in] edgelist Opaque pointer to edgelist
+ * @return type erased array view of edge ids
+ */
+cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_edge_ids(
+ cugraph_edgelist_t* edgelist);
+
+/**
+ * @brief Get the edge types
+ *
+ * @param [in] edgelist Opaque pointer to edgelist
+ * @return type erased array view of edge types
+ */
+cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_edge_type_ids(
+ cugraph_edgelist_t* edgelist);
+
+/**
+ * @brief Get the edge offsets
+ *
+ * @param [in] edgelist Opaque pointer to edgelist
+ * @return type erased array view of subgraph identifiers
+ */
+cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_edge_offsets(
+ cugraph_edgelist_t* edgelist);
+
+/**
+ * @brief Free edgelist
+ *
+ * @param [in] edgelist Opaque pointer to edgelist
+ */
+void cugraph_edgelist_free(cugraph_edgelist_t* edgelist);
+
+/**
+ * @brief Construct the edge list from the graph view object.
+ *
+ * @param [in] handle Handle for accessing resources
+ * @param [in] graph Graph to operate on
+ * @param [in] do_expensive_check A flag to run expensive checks for input arguments (if set to
+ * true)
+ * @param [out] result Opaque pointer to edgelist
+ * @param [out] error Pointer to an error object storing details of any error. Will
+ * be populated if error code is not CUGRAPH_SUCCESS
+ * @return error code
+ */
+cugraph_error_code_t cugraph_decompress_to_edgelist(const cugraph_resource_handle_t* handle,
+ cugraph_graph_t* graph,
+ bool_t do_expensive_check,
+ cugraph_edgelist_t** result,
+ cugraph_error_t** error);
+
#ifdef __cplusplus
}
#endif
diff --git a/cpp/include/cugraph_c/sampling_algorithms.h b/cpp/include/cugraph_c/sampling_algorithms.h
index bb26e577915..ef75e726d80 100644
--- a/cpp/include/cugraph_c/sampling_algorithms.h
+++ b/cpp/include/cugraph_c/sampling_algorithms.h
@@ -199,6 +199,13 @@ typedef struct {
int32_t align_;
} cugraph_sampling_options_t;
+/**
+ * @brief Opaque sampling options type
+ */
+typedef struct {
+ int32_t align_;
+} sampling_flags_t;
+
/**
* @brief Enumeration for prior sources behavior
*/
@@ -323,6 +330,8 @@ void cugraph_sampling_options_free(cugraph_sampling_options_t* options);
/**
* @brief Uniform Neighborhood Sampling
*
+ * @deprecated This API will be deleted, use cugraph_homogeneous_uniform_neighbor_sample
+ *
* Returns a sample of the neighborhood around specified start vertices. Optionally, each
* start vertex can be associated with a label, allowing the caller to specify multiple batches
* of sampling requests in the same function call - which should improve GPU utilization.
@@ -348,8 +357,8 @@ void cugraph_sampling_options_free(cugraph_sampling_options_t* options);
* label_to_comm_rank[i]. If not specified then the output data will not be shuffled between ranks.
* @param [in] label_offsets Device array of the offsets for each label in the seed list. This
* parameter is only used with the retain_seeds option.
- * @param [in] fanout Host array defining the fan out at each step in the sampling algorithm.
- * We only support fanout values of type INT32
+ * @param [in] fan_out Host array defining the fan out at each step in the sampling
+ * algorithm. We only support fan_out values of type INT32
* @param [in,out] rng_state State of the random number generator, updated with each call
* @param [in] sampling_options
* Opaque pointer defining the sampling options.
@@ -378,6 +387,8 @@ cugraph_error_code_t cugraph_uniform_neighbor_sample(
/**
* @brief Biased Neighborhood Sampling
*
+ * @deprecated This API will be deleted, use cugraph_homogeneous_biased_neighbor_sample.
+ *
* Returns a sample of the neighborhood around specified start vertices. Optionally, each
* start vertex can be associated with a label, allowing the caller to specify multiple batches
* of sampling requests in the same function call - which should improve GPU utilization.
@@ -406,8 +417,8 @@ cugraph_error_code_t cugraph_uniform_neighbor_sample(
* label_to_comm_rank[i]. If not specified then the output data will not be shuffled between ranks.
* @param [in] label_offsets Device array of the offsets for each label in the seed list. This
* parameter is only used with the retain_seeds option.
- * @param [in] fanout Host array defining the fan out at each step in the sampling algorithm.
- * We only support fanout values of type INT32
+ * @param [in] fan_out Host array defining the fan out at each step in the sampling
+ * algorithm. We only support fan_out values of type INT32
* @param [in,out] rng_state State of the random number generator, updated with each call
* @param [in] sampling_options
* Opaque pointer defining the sampling options.
@@ -434,6 +445,186 @@ cugraph_error_code_t cugraph_biased_neighbor_sample(
cugraph_sample_result_t** result,
cugraph_error_t** error);
+/**
+ * @brief Homogeneous Uniform Neighborhood Sampling
+ *
+ * Returns a sample of the neighborhood around specified start vertices and fan_out.
+ * The neighborhood is sampled uniformly.
+ * Optionally, each start vertex can be associated with a label, allowing the caller to specify
+ * multiple batches of sampling requests in the same function call - which should improve GPU
+ * utilization.
+ *
+ * If label is NULL then all start vertices will be considered part of the same batch and the
+ * return value will not have a label column.
+ *
+ * @param [in] handle Handle for accessing resources
+ * * @param [in,out] rng_state State of the random number generator, updated with each call
+ * @param [in] graph Pointer to graph. NOTE: Graph might be modified if the storage
+ * needs to be transposed
+ * @param [in] start_vertices Device array of start vertices for the sampling
+ * @param [in] starting_vertex_label_offsets Device array of the offsets for each label in
+ * the seed list. This parameter is only used with the retain_seeds option.
+ * @param [in] fan_out Host array defining the fan out at each step in the sampling
+ * algorithm. We only support fan_out values of type INT32
+ * @param [in] sampling_options
+ * Opaque pointer defining the sampling options.
+ * @param [in] do_expensive_check
+ * A flag to run expensive checks for input arguments (if set to true)
+ * @param [out] result Output from the uniform_neighbor_sample call
+ * @param [out] error Pointer to an error object storing details of any error. Will
+ * be populated if error code is not CUGRAPH_SUCCESS
+ * @return error code
+ */
+cugraph_error_code_t cugraph_homogeneous_uniform_neighbor_sample(
+ const cugraph_resource_handle_t* handle,
+ cugraph_rng_state_t* rng_state,
+ cugraph_graph_t* graph,
+ const cugraph_type_erased_device_array_view_t* start_vertices,
+ const cugraph_type_erased_device_array_view_t* starting_vertex_label_offsets,
+ const cugraph_type_erased_host_array_view_t* fan_out,
+ const cugraph_sampling_options_t* options,
+ bool_t do_expensive_check,
+ cugraph_sample_result_t** result,
+ cugraph_error_t** error);
+
+/**
+ * @brief Homogeneous Biased Neighborhood Sampling
+ *
+ * Returns a sample of the neighborhood around specified start vertices and fan_out.
+ * The neighborhood is sampled uniformly.
+ * Optionally, each start vertex can be associated with a label, allowing the caller to specify
+ * multiple batches of sampling requests in the same function call - which should improve GPU
+ * utilization.
+ *
+ * If label is NULL then all start vertices will be considered part of the same batch and the
+ * return value will not have a label column.
+ *
+ * @param [in] handle Handle for accessing resources
+ * * @param [in,out] rng_state State of the random number generator, updated with each call
+ * @param [in] graph Pointer to graph. NOTE: Graph might be modified if the storage
+ * needs to be transposed
+ * @param [in] edge_biases Device array of edge biases to use for sampling. If NULL
+ * use the edge weight as the bias. If set to NULL, edges will be sampled uniformly.
+ * @param [in] start_vertices Device array of start vertices for the sampling
+ * @param [in] starting_vertex_label_offsets Device array of the offsets for each label in
+ * the seed list. This parameter is only used with the retain_seeds option.
+ * @param [in] fan_out Host array defining the fan out at each step in the sampling
+ * algorithm. We only support fan_out values of type INT32
+ * @param [in] sampling_options
+ * Opaque pointer defining the sampling options.
+ * @param [in] do_expensive_check
+ * A flag to run expensive checks for input arguments (if set to true)
+ * @param [out] result Output from the uniform_neighbor_sample call
+ * @param [out] error Pointer to an error object storing details of any error. Will
+ * be populated if error code is not CUGRAPH_SUCCESS
+ * @return error code
+ */
+cugraph_error_code_t cugraph_homogeneous_biased_neighbor_sample(
+ const cugraph_resource_handle_t* handle,
+ cugraph_rng_state_t* rng_state,
+ cugraph_graph_t* graph,
+ const cugraph_edge_property_view_t* edge_biases,
+ const cugraph_type_erased_device_array_view_t* start_vertices,
+ const cugraph_type_erased_device_array_view_t* starting_vertex_label_offsets,
+ const cugraph_type_erased_host_array_view_t* fan_out,
+ const cugraph_sampling_options_t* options,
+ bool_t do_expensive_check,
+ cugraph_sample_result_t** result,
+ cugraph_error_t** error);
+
+/**
+ * @brief Heterogeneous Uniform Neighborhood Sampling
+ *
+ * Returns a sample of the neighborhood around specified start vertices and fan_out.
+ * The neighborhood is sampled uniformly.
+ * Optionally, each start vertex can be associated with a label, allowing the caller to specify
+ * multiple batches of sampling requests in the same function call - which should improve GPU
+ * utilization.
+ *
+ * If label is NULL then all start vertices will be considered part of the same batch and the
+ * return value will not have a label column.
+ *
+ * @param [in] handle Handle for accessing resources
+ * * @param [in,out] rng_state State of the random number generator, updated with each call
+ * @param [in] graph Pointer to graph. NOTE: Graph might be modified if the storage
+ * needs to be transposed
+ * @param [in] start_vertices Device array of start vertices for the sampling
+ * @param [in] starting_vertex_label_offsets Device array of the offsets for each label in
+ * the seed list. This parameter is only used with the retain_seeds option.
+ * @param [in] fan_out Host array defining the fan out at each step in the sampling
+ * algorithm. We only support fan_out values of type INT32
+ * @param [in] num_edge_types Number of edge types where a value of 1 translates to homogeneous
+ * neighbor sample whereas a value greater than 1 translates to heterogeneous neighbor sample.
+ * @param [in] sampling_options
+ * Opaque pointer defining the sampling options.
+ * @param [in] do_expensive_check
+ * A flag to run expensive checks for input arguments (if set to true)
+ * @param [out] result Output from the uniform_neighbor_sample call
+ * @param [out] error Pointer to an error object storing details of any error. Will
+ * be populated if error code is not CUGRAPH_SUCCESS
+ * @return error code
+ */
+cugraph_error_code_t cugraph_heterogeneous_uniform_neighbor_sample(
+ const cugraph_resource_handle_t* handle,
+ cugraph_rng_state_t* rng_state,
+ cugraph_graph_t* graph,
+ const cugraph_type_erased_device_array_view_t* start_vertices,
+ const cugraph_type_erased_device_array_view_t* starting_vertex_label_offsets,
+ const cugraph_type_erased_host_array_view_t* fan_out,
+ int num_edge_types,
+ const cugraph_sampling_options_t* options,
+ bool_t do_expensive_check,
+ cugraph_sample_result_t** result,
+ cugraph_error_t** error);
+
+/**
+ * @brief Heterogeneous Biased Neighborhood Sampling
+ *
+ * Returns a sample of the neighborhood around specified start vertices and fan_out.
+ * The neighborhood is sampled uniformly.
+ * Optionally, each start vertex can be associated with a label, allowing the caller to specify
+ * multiple batches of sampling requests in the same function call - which should improve GPU
+ * utilization.
+ *
+ * If label is NULL then all start vertices will be considered part of the same batch and the
+ * return value will not have a label column.
+ *
+ * @param [in] handle Handle for accessing resources
+ * * @param [in,out] rng_state State of the random number generator, updated with each call
+ * @param [in] graph Pointer to graph. NOTE: Graph might be modified if the storage
+ * needs to be transposed
+ * @param [in] edge_biases Device array of edge biases to use for sampling. If NULL
+ * use the edge weight as the bias. If set to NULL, edges will be sampled uniformly.
+ * @param [in] start_vertices Device array of start vertices for the sampling
+ * @param [in] starting_vertex_label_offsets Device array of the offsets for each label in
+ * the seed list. This parameter is only used with the retain_seeds option.
+ * @param [in] fan_out Host array defining the fan out at each step in the sampling
+ * algorithm. We only support fan_out values of type INT32
+ * @param [in] num_edge_types Number of edge types where a value of 1 translates to homogeneous
+ * neighbor sample whereas a value greater than 1 translates to heterogeneous neighbor sample.
+ * @param [in] sampling_options
+ * Opaque pointer defining the sampling options.
+ * @param [in] do_expensive_check
+ * A flag to run expensive checks for input arguments (if set to true)
+ * @param [out] result Output from the uniform_neighbor_sample call
+ * @param [out] error Pointer to an error object storing details of any error. Will
+ * be populated if error code is not CUGRAPH_SUCCESS
+ * @return error code
+ */
+cugraph_error_code_t cugraph_heterogeneous_biased_neighbor_sample(
+ const cugraph_resource_handle_t* handle,
+ cugraph_rng_state_t* rng_state,
+ cugraph_graph_t* graph,
+ const cugraph_edge_property_view_t* edge_biases,
+ const cugraph_type_erased_device_array_view_t* start_vertices,
+ const cugraph_type_erased_device_array_view_t* starting_vertex_label_offsets,
+ const cugraph_type_erased_host_array_view_t* fan_out,
+ int num_edge_types,
+ const cugraph_sampling_options_t* options,
+ bool_t do_expensive_check,
+ cugraph_sample_result_t** result,
+ cugraph_error_t** error);
+
/**
* @deprecated This call should be replaced with cugraph_sample_result_get_majors
* @brief Get the source vertices from the sampling algorithm result
@@ -584,6 +775,26 @@ cugraph_type_erased_device_array_view_t* cugraph_sample_result_get_renumber_map(
cugraph_type_erased_device_array_view_t* cugraph_sample_result_get_renumber_map_offsets(
const cugraph_sample_result_t* result);
+/**
+ * @ingroup samplingC
+ * @brief Get the edge renumber map
+ *
+ * @param [in] result The result from a sampling algorithm
+ * @return type erased array pointing to the renumber map
+ */
+cugraph_type_erased_device_array_view_t* cugraph_sample_result_get_edge_renumber_map(
+ const cugraph_sample_result_t* result);
+
+/**
+ * @ingroup samplingC
+ * @brief Get the edge renumber map offets
+ *
+ * @param [in] result The result from a sampling algorithm
+ * @return type erased array pointing to the renumber map
+ */
+cugraph_type_erased_device_array_view_t* cugraph_sample_result_get_edge_renumber_map_offsets(
+ const cugraph_sample_result_t* result);
+
/**
* @ingroup samplingC
* @brief Free a sampling result
diff --git a/cpp/src/c_api/array.hpp b/cpp/src/c_api/array.hpp
index 048d2ee1cea..0ab30a1cb72 100644
--- a/cpp/src/c_api/array.hpp
+++ b/cpp/src/c_api/array.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2023, NVIDIA CORPORATION.
+ * Copyright (c) 2021-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.
@@ -125,6 +125,27 @@ struct cugraph_type_erased_host_array_t {
std::copy(vec.begin(), vec.end(), reinterpret_cast(data_.get()));
}
+ cugraph_type_erased_host_array_t(cugraph_type_erased_host_array_view_t const* view_p)
+ : data_(std::make_unique(view_p->num_bytes_)),
+ size_(view_p->size_),
+ num_bytes_(view_p->num_bytes_),
+ type_(view_p->type_)
+ {
+ std::copy(view_p->data_, view_p->data_ + num_bytes_, data_.get());
+ }
+
+ template
+ T* as_type()
+ {
+ return reinterpret_cast(data_.get());
+ }
+
+ template
+ T const* as_type() const
+ {
+ return reinterpret_cast(data_.get());
+ }
+
auto view()
{
return new cugraph_type_erased_host_array_view_t{data_.get(), size_, num_bytes_, type_};
diff --git a/cpp/src/c_api/decompress_to_edgelist.cpp b/cpp/src/c_api/decompress_to_edgelist.cpp
new file mode 100644
index 00000000000..75bf0c0fd60
--- /dev/null
+++ b/cpp/src/c_api/decompress_to_edgelist.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#include "c_api/abstract_functor.hpp"
+#include "c_api/core_result.hpp"
+#include "c_api/edgelist.hpp"
+#include "c_api/graph.hpp"
+#include "c_api/resource_handle.hpp"
+#include "c_api/utils.hpp"
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+namespace {
+
+struct decompress_to_edgelist_functor : public cugraph::c_api::abstract_functor {
+ raft::handle_t const& handle_;
+ cugraph::c_api::cugraph_graph_t* graph_{};
+
+ cugraph::c_api::cugraph_core_result_t const* core_result_{};
+ bool do_expensive_check_{};
+ cugraph::c_api::cugraph_edgelist_t* result_{};
+
+ decompress_to_edgelist_functor(cugraph_resource_handle_t const* handle,
+ cugraph_graph_t* graph,
+ bool do_expensive_check)
+ : abstract_functor(),
+ handle_(*reinterpret_cast(handle)->handle_),
+ graph_(reinterpret_cast(graph)),
+ do_expensive_check_(do_expensive_check)
+ {
+ }
+
+ template
+ void operator()()
+ {
+ if constexpr (!cugraph::is_candidate::value) {
+ unsupported();
+ } else {
+ if constexpr (store_transposed) {
+ error_code_ = cugraph::c_api::
+ transpose_storage(
+ handle_, graph_, error_.get());
+ if (error_code_ != CUGRAPH_SUCCESS) return;
+ }
+
+ auto graph =
+ reinterpret_cast*>(
+ graph_->graph_);
+
+ auto graph_view = graph->view();
+
+ auto edge_weights = reinterpret_cast,
+ weight_t>*>(graph_->edge_weights_);
+
+ auto edge_ids = reinterpret_cast,
+ edge_t>*>(graph_->edge_ids_);
+
+ auto edge_types = reinterpret_cast,
+ edge_type_type_t>*>(graph_->edge_types_);
+
+ auto number_map = reinterpret_cast*>(graph_->number_map_);
+
+ auto [result_src, result_dst, result_wgt, result_edge_id, result_edge_type] =
+ cugraph::decompress_to_edgelist(
+ handle_,
+ graph_view,
+ (edge_weights != nullptr) ? std::make_optional(edge_weights->view()) : std::nullopt,
+ (edge_ids != nullptr) ? std::make_optional(edge_ids->view()) : std::nullopt,
+ (edge_types != nullptr) ? std::make_optional(edge_types->view()) : std::nullopt,
+ (number_map != nullptr) ? std::make_optional>(
+ number_map->data(), number_map->size())
+ : std::nullopt,
+ do_expensive_check_);
+
+ result_ = new cugraph::c_api::cugraph_edgelist_t{
+ new cugraph::c_api::cugraph_type_erased_device_array_t(result_src, graph_->vertex_type_),
+ new cugraph::c_api::cugraph_type_erased_device_array_t(result_dst, graph_->vertex_type_),
+ result_wgt ? new cugraph::c_api::cugraph_type_erased_device_array_t(*result_wgt,
+ graph_->weight_type_)
+ : NULL,
+ result_edge_id ? new cugraph::c_api::cugraph_type_erased_device_array_t(*result_edge_id,
+ graph_->edge_type_)
+ : NULL,
+ result_edge_type ? new cugraph::c_api::cugraph_type_erased_device_array_t(
+ *result_edge_type, graph_->edge_type_id_type_)
+ : NULL,
+ NULL};
+ }
+ }
+};
+
+} // namespace
+
+extern "C" cugraph_error_code_t cugraph_decompress_to_edgelist(
+ const cugraph_resource_handle_t* handle,
+ cugraph_graph_t* graph,
+ bool_t do_expensive_check,
+ cugraph_edgelist_t** result,
+ cugraph_error_t** error)
+{
+ decompress_to_edgelist_functor functor(handle, graph, do_expensive_check);
+
+ return cugraph::c_api::run_algorithm(graph, functor, result, error);
+}
diff --git a/cpp/src/c_api/edgelist.cpp b/cpp/src/c_api/edgelist.cpp
new file mode 100644
index 00000000000..640b2bf2853
--- /dev/null
+++ b/cpp/src/c_api/edgelist.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#include "c_api/edgelist.hpp"
+
+#include
+
+extern "C" cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_sources(
+ cugraph_edgelist_t* edgelist)
+{
+ auto internal_pointer = reinterpret_cast(edgelist);
+ return reinterpret_cast(internal_pointer->src_->view());
+}
+
+extern "C" cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_destinations(
+ cugraph_edgelist_t* edgelist)
+{
+ auto internal_pointer = reinterpret_cast(edgelist);
+ return reinterpret_cast(internal_pointer->dst_->view());
+}
+
+extern "C" cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_edge_weights(
+ cugraph_edgelist_t* edgelist)
+{
+ auto internal_pointer = reinterpret_cast(edgelist);
+ return (internal_pointer->wgt_ == nullptr)
+ ? NULL
+ : reinterpret_cast(
+ internal_pointer->wgt_->view());
+}
+
+extern "C" cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_edge_ids(
+ cugraph_edgelist_t* edgelist)
+{
+ auto internal_pointer = reinterpret_cast(edgelist);
+ return (internal_pointer->edge_ids_ == nullptr)
+ ? NULL
+ : reinterpret_cast(
+ internal_pointer->edge_ids_->view());
+}
+
+extern "C" cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_edge_type_ids(
+ cugraph_edgelist_t* edgelist)
+{
+ auto internal_pointer = reinterpret_cast(edgelist);
+ return (internal_pointer->edge_type_ids_ == nullptr)
+ ? NULL
+ : reinterpret_cast(
+ internal_pointer->edge_type_ids_->view());
+}
+
+extern "C" cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_edge_offsets(
+ cugraph_edgelist_t* edgelist)
+{
+ auto internal_pointer = reinterpret_cast(edgelist);
+ return reinterpret_cast(
+ internal_pointer->subgraph_offsets_->view());
+}
+
+extern "C" void cugraph_edgelist_free(cugraph_edgelist_t* edgelist)
+{
+ auto internal_pointer = reinterpret_cast(edgelist);
+ delete internal_pointer->src_;
+ delete internal_pointer->dst_;
+ delete internal_pointer->wgt_;
+ delete internal_pointer->edge_ids_;
+ delete internal_pointer->edge_type_ids_;
+ delete internal_pointer->subgraph_offsets_;
+ delete internal_pointer;
+}
diff --git a/cpp/src/c_api/edgelist.hpp b/cpp/src/c_api/edgelist.hpp
new file mode 100644
index 00000000000..bc0f2d337f1
--- /dev/null
+++ b/cpp/src/c_api/edgelist.hpp
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include "c_api/array.hpp"
+
+namespace cugraph {
+namespace c_api {
+
+struct cugraph_edgelist_t {
+ cugraph_type_erased_device_array_t* src_{};
+ cugraph_type_erased_device_array_t* dst_{};
+ cugraph_type_erased_device_array_t* wgt_{};
+ cugraph_type_erased_device_array_t* edge_ids_{};
+ cugraph_type_erased_device_array_t* edge_type_ids_{};
+ cugraph_type_erased_device_array_t* subgraph_offsets_{};
+};
+
+} // namespace c_api
+} // namespace cugraph
diff --git a/cpp/src/c_api/graph_functions.cpp b/cpp/src/c_api/graph_functions.cpp
index df741a349d2..8778369dbe6 100644
--- a/cpp/src/c_api/graph_functions.cpp
+++ b/cpp/src/c_api/graph_functions.cpp
@@ -84,7 +84,7 @@ struct create_vertex_pairs_functor : public cugraph::c_api::abstract_functor {
std::nullopt,
std::nullopt);
}
-
+ // FIXME: use std::tuple (template) instead.
result_ = new cugraph::c_api::cugraph_vertex_pairs_t{
new cugraph::c_api::cugraph_type_erased_device_array_t(first_copy, graph_->vertex_type_),
new cugraph::c_api::cugraph_type_erased_device_array_t(second_copy, graph_->vertex_type_)};
diff --git a/cpp/src/c_api/neighbor_sampling.cpp b/cpp/src/c_api/neighbor_sampling.cpp
index 69306806030..be3a44d813a 100644
--- a/cpp/src/c_api/neighbor_sampling.cpp
+++ b/cpp/src/c_api/neighbor_sampling.cpp
@@ -16,12 +16,15 @@
#include "c_api/abstract_functor.hpp"
#include "c_api/graph.hpp"
+#include "c_api/graph_helper.hpp"
#include "c_api/properties.hpp"
#include "c_api/random.hpp"
#include "c_api/resource_handle.hpp"
#include "c_api/utils.hpp"
+#include "sampling/detail/sampling_utils.hpp"
#include
+#include
#include
#include
@@ -44,6 +47,13 @@ struct cugraph_sampling_options_t {
bool_t retain_seeds_{FALSE};
};
+struct sampling_flags_t {
+ prior_sources_behavior_t prior_sources_behavior_{prior_sources_behavior_t::DEFAULT};
+ bool_t return_hops_{FALSE};
+ bool_t dedupe_sources_{FALSE};
+ bool_t with_replacement_{FALSE};
+};
+
struct cugraph_sample_result_t {
cugraph_type_erased_device_array_t* major_offsets_{nullptr};
cugraph_type_erased_device_array_t* majors_{nullptr};
@@ -56,6 +66,8 @@ struct cugraph_sample_result_t {
cugraph_type_erased_device_array_t* label_{nullptr};
cugraph_type_erased_device_array_t* renumber_map_{nullptr};
cugraph_type_erased_device_array_t* renumber_map_offsets_{nullptr};
+ cugraph_type_erased_device_array_t* edge_renumber_map_{nullptr};
+ cugraph_type_erased_device_array_t* edge_renumber_map_offsets_{nullptr};
};
} // namespace c_api
@@ -63,6 +75,7 @@ struct cugraph_sample_result_t {
namespace {
+// Deprecated functor
struct uniform_neighbor_sampling_functor : public cugraph::c_api::abstract_functor {
raft::handle_t const& handle_;
cugraph::c_api::cugraph_graph_t* graph_{nullptr};
@@ -398,11 +411,14 @@ struct uniform_neighbor_sampling_functor : public cugraph::c_api::abstract_funct
: nullptr,
(renumber_map_offsets) ? new cugraph::c_api::cugraph_type_erased_device_array_t(
renumber_map_offsets.value(), SIZE_T)
- : nullptr};
+ : nullptr,
+ nullptr,
+ nullptr};
}
}
};
+// Deprecated functor
struct biased_neighbor_sampling_functor : public cugraph::c_api::abstract_functor {
raft::handle_t const& handle_;
cugraph::c_api::cugraph_graph_t* graph_{nullptr};
@@ -748,7 +764,598 @@ struct biased_neighbor_sampling_functor : public cugraph::c_api::abstract_functo
: nullptr,
(renumber_map_offsets) ? new cugraph::c_api::cugraph_type_erased_device_array_t(
renumber_map_offsets.value(), SIZE_T)
- : nullptr};
+ : nullptr,
+ nullptr,
+ nullptr};
+ }
+ }
+};
+
+struct neighbor_sampling_functor : public cugraph::c_api::abstract_functor {
+ raft::handle_t const& handle_;
+ cugraph::c_api::cugraph_rng_state_t* rng_state_{nullptr};
+ cugraph::c_api::cugraph_graph_t* graph_{nullptr};
+ cugraph::c_api::cugraph_edge_property_view_t const* edge_biases_{nullptr};
+ cugraph::c_api::cugraph_type_erased_device_array_view_t const* start_vertices_{nullptr};
+ cugraph::c_api::cugraph_type_erased_device_array_view_t const* start_vertex_offsets_{nullptr};
+ cugraph::c_api::cugraph_type_erased_host_array_view_t const* fan_out_{nullptr};
+ int num_edge_types_{};
+ cugraph::c_api::cugraph_sampling_options_t options_{};
+ bool is_biased_{false};
+ bool do_expensive_check_{false};
+ cugraph::c_api::cugraph_sample_result_t* result_{nullptr};
+
+ neighbor_sampling_functor(cugraph_resource_handle_t const* handle,
+ cugraph_rng_state_t* rng_state,
+ cugraph_graph_t* graph,
+ cugraph_edge_property_view_t const* edge_biases,
+ cugraph_type_erased_device_array_view_t const* start_vertices,
+ cugraph_type_erased_device_array_view_t const* start_vertex_offsets,
+ cugraph_type_erased_host_array_view_t const* fan_out,
+ int num_edge_types,
+ cugraph::c_api::cugraph_sampling_options_t options,
+ bool is_biased,
+ bool do_expensive_check)
+ : abstract_functor(),
+ handle_(*reinterpret_cast(handle)->handle_),
+ rng_state_(reinterpret_cast(rng_state)),
+ graph_(reinterpret_cast(graph)),
+ edge_biases_(
+ reinterpret_cast(edge_biases)),
+ start_vertices_(
+ reinterpret_cast(
+ start_vertices)),
+ start_vertex_offsets_(
+ reinterpret_cast(
+ start_vertex_offsets)),
+ fan_out_(
+ reinterpret_cast(fan_out)),
+ num_edge_types_(num_edge_types),
+ options_(options),
+ is_biased_(is_biased),
+ do_expensive_check_(do_expensive_check)
+ {
+ }
+
+ template
+ void operator()()
+ {
+ using label_t = int32_t;
+
+ // FIXME: Think about how to handle SG vice MG
+ if constexpr (!cugraph::is_candidate::value) {
+ unsupported();
+ } else {
+ // uniform_nbr_sample expects store_transposed == false
+ if constexpr (store_transposed) {
+ error_code_ = cugraph::c_api::
+ transpose_storage(
+ handle_, graph_, error_.get());
+ if (error_code_ != CUGRAPH_SUCCESS) return;
+ }
+
+ auto graph =
+ reinterpret_cast*>(graph_->graph_);
+
+ auto graph_view = graph->view();
+
+ auto edge_weights = reinterpret_cast<
+ cugraph::edge_property_t,
+ weight_t>*>(graph_->edge_weights_);
+
+ auto edge_ids = reinterpret_cast<
+ cugraph::edge_property_t,
+ edge_t>*>(graph_->edge_ids_);
+
+ auto edge_types = reinterpret_cast<
+ cugraph::edge_property_t,
+ edge_type_t>*>(graph_->edge_types_);
+
+ auto number_map = reinterpret_cast*>(graph_->number_map_);
+
+ auto edge_biases =
+ edge_biases_ ? reinterpret_cast*>(
+ edge_biases_->edge_property_)
+ : nullptr;
+
+ rmm::device_uvector start_vertices(start_vertices_->size_, handle_.get_stream());
+ raft::copy(start_vertices.data(),
+ start_vertices_->as_type(),
+ start_vertices.size(),
+ handle_.get_stream());
+
+ std::optional> start_vertex_labels{std::nullopt};
+ std::optional> local_label_to_comm_rank{std::nullopt};
+ std::optional> label_to_comm_rank{
+ std::nullopt}; // global after allgatherv
+
+ std::optional> renumbered_and_sorted_edge_id_renumber_map(
+ std::nullopt);
+ std::optional>
+ renumbered_and_sorted_edge_id_renumber_map_label_type_offsets(std::nullopt);
+
+ if (start_vertex_offsets_ != nullptr) {
+ // Retrieve the start_vertex_labels
+ start_vertex_labels = cugraph::detail::convert_starting_vertex_label_offsets_to_labels(
+ handle_,
+ raft::device_span{start_vertex_offsets_->as_type(),
+ start_vertex_offsets_->size_});
+
+ // Get the number of labels on each GPU
+
+ if constexpr (multi_gpu) {
+ auto num_local_labels = start_vertex_offsets_->size_ - 1;
+
+ auto global_labels = cugraph::host_scalar_allgather(
+ handle_.get_comms(), num_local_labels, handle_.get_stream());
+
+ std::exclusive_scan(
+ global_labels.begin(), global_labels.end(), global_labels.begin(), label_t{0});
+
+ // Compute the global start_vertex_label_offsets
+
+ cugraph::detail::transform_increment_ints(
+ raft::device_span{(*start_vertex_labels).data(),
+ (*start_vertex_labels).size()},
+ (label_t)global_labels[handle_.get_comms().get_rank()],
+ handle_.get_stream());
+
+ rmm::device_uvector unique_labels((*start_vertex_labels).size(),
+ handle_.get_stream());
+ raft::copy(unique_labels.data(),
+ (*start_vertex_labels).data(),
+ unique_labels.size(),
+ handle_.get_stream());
+
+ // Get unique labels
+ // sort the start_vertex_labels
+ cugraph::detail::sort_ints(
+ handle_.get_stream(),
+ raft::device_span{unique_labels.data(), unique_labels.size()});
+
+ auto num_unique_labels = cugraph::detail::unique_ints(
+ handle_.get_stream(),
+ raft::device_span{unique_labels.data(), unique_labels.size()});
+
+ (*local_label_to_comm_rank).resize(num_unique_labels, handle_.get_stream());
+
+ cugraph::detail::scalar_fill(
+ handle_.get_stream(),
+ (*local_label_to_comm_rank).begin(), // This should be rename to rank
+ (*local_label_to_comm_rank).size(),
+ label_t{handle_.get_comms().get_rank()});
+
+ // Perform allgather to get global_label_to_comm_rank_d_vector
+ auto recvcounts = cugraph::host_scalar_allgather(
+ handle_.get_comms(), num_unique_labels, handle_.get_stream());
+
+ std::vector displacements(recvcounts.size());
+ std::exclusive_scan(
+ recvcounts.begin(), recvcounts.end(), displacements.begin(), size_t{0});
+
+ (*label_to_comm_rank)
+ .resize(displacements.back() + recvcounts.back(), handle_.get_stream());
+
+ cugraph::device_allgatherv(handle_.get_comms(),
+ (*local_label_to_comm_rank).begin(),
+ (*label_to_comm_rank).begin(),
+ recvcounts,
+ displacements,
+ handle_.get_stream());
+
+ std::tie(start_vertices, *start_vertex_labels) =
+ cugraph::detail::shuffle_ext_vertex_value_pairs_to_local_gpu_by_vertex_partitioning(
+ handle_, std::move(start_vertices), std::move(*start_vertex_labels));
+ }
+ } else {
+ if constexpr (multi_gpu) {
+ start_vertices =
+ cugraph::detail::shuffle_ext_vertices_to_local_gpu_by_vertex_partitioning(
+ handle_, std::move(start_vertices));
+ }
+ }
+ //
+ // Need to renumber start_vertices
+ //
+ cugraph::renumber_local_ext_vertices(
+ handle_,
+ start_vertices.data(),
+ start_vertices.size(),
+ number_map->data(),
+ graph_view.local_vertex_partition_range_first(),
+ graph_view.local_vertex_partition_range_last(),
+ do_expensive_check_);
+
+ rmm::device_uvector src(0, handle_.get_stream());
+ rmm::device_uvector dst(0, handle_.get_stream());
+ std::optional> wgt{std::nullopt};
+ std::optional> edge_id{std::nullopt};
+ std::optional> edge_type{std::nullopt};
+ std::optional> hop{std::nullopt};
+ std::optional> edge_label{std::nullopt};
+ std::optional> offsets{std::nullopt};
+
+ // FIXME: For biased sampling, the user should pass either biases or edge weights,
+ // otherwised throw an error and suggest the user to call uniform neighbor sample instead
+
+ if (num_edge_types_ > 1) {
+ // call heterogeneous neighbor sample
+ if (is_biased_) {
+ std::tie(src, dst, wgt, edge_id, edge_type, hop, offsets) =
+ cugraph::heterogeneous_biased_neighbor_sample(
+ handle_,
+ rng_state_->rng_state_,
+ graph_view,
+ (edge_weights != nullptr) ? std::make_optional(edge_weights->view()) : std::nullopt,
+ (edge_ids != nullptr) ? std::make_optional(edge_ids->view()) : std::nullopt,
+ (edge_types != nullptr) ? std::make_optional(edge_types->view()) : std::nullopt,
+ (edge_biases != nullptr) ? *edge_biases : edge_weights->view(),
+ raft::device_span{start_vertices.data(), start_vertices.size()},
+ (start_vertex_offsets_ != nullptr)
+ ? std::make_optional>((*start_vertex_labels).data(),
+ (*start_vertex_labels).size())
+ : std::nullopt,
+ label_to_comm_rank ? std::make_optional(raft::device_span{
+ (*label_to_comm_rank).data(), (*label_to_comm_rank).size()})
+ : std::nullopt,
+ raft::host_span(fan_out_->as_type(), fan_out_->size_),
+ num_edge_types_,
+ cugraph::sampling_flags_t{options_.prior_sources_behavior_,
+ options_.return_hops_,
+ options_.dedupe_sources_,
+ options_.with_replacement_},
+ do_expensive_check_);
+ } else {
+ std::tie(src, dst, wgt, edge_id, edge_type, hop, offsets) =
+ cugraph::heterogeneous_uniform_neighbor_sample(
+ handle_,
+ rng_state_->rng_state_,
+ graph_view,
+ (edge_weights != nullptr) ? std::make_optional(edge_weights->view()) : std::nullopt,
+ (edge_ids != nullptr) ? std::make_optional(edge_ids->view()) : std::nullopt,
+ (edge_types != nullptr) ? std::make_optional(edge_types->view()) : std::nullopt,
+ raft::device_span{start_vertices.data(), start_vertices.size()},
+ (start_vertex_offsets_ != nullptr)
+ ? std::make_optional>((*start_vertex_labels).data(),
+ (*start_vertex_labels).size())
+ : std::nullopt,
+ label_to_comm_rank ? std::make_optional(raft::device_span{
+ (*label_to_comm_rank).data(), (*label_to_comm_rank).size()})
+ : std::nullopt,
+ raft::host_span(fan_out_->as_type(), fan_out_->size_),
+ num_edge_types_,
+ cugraph::sampling_flags_t{options_.prior_sources_behavior_,
+ options_.return_hops_,
+ options_.dedupe_sources_,
+ options_.with_replacement_},
+ do_expensive_check_);
+ }
+ } else {
+ // Call homogeneous neighbor sample
+ if (is_biased_) {
+ std::tie(src, dst, wgt, edge_id, edge_type, hop, offsets) =
+ cugraph::homogeneous_biased_neighbor_sample(
+ handle_,
+ rng_state_->rng_state_,
+ graph_view,
+ (edge_weights != nullptr) ? std::make_optional(edge_weights->view()) : std::nullopt,
+ (edge_ids != nullptr) ? std::make_optional(edge_ids->view()) : std::nullopt,
+ (edge_types != nullptr) ? std::make_optional(edge_types->view()) : std::nullopt,
+ (edge_biases != nullptr) ? *edge_biases : edge_weights->view(),
+ raft::device_span{start_vertices.data(), start_vertices.size()},
+ (start_vertex_offsets_ != nullptr)
+ ? std::make_optional>((*start_vertex_labels).data(),
+ (*start_vertex_labels).size())
+ : std::nullopt,
+ label_to_comm_rank ? std::make_optional(raft::device_span{
+ (*label_to_comm_rank).data(), (*label_to_comm_rank).size()})
+ : std::nullopt,
+ raft::host_span(fan_out_->as_type(), fan_out_->size_),
+ cugraph::sampling_flags_t{options_.prior_sources_behavior_,
+ options_.return_hops_,
+ options_.dedupe_sources_,
+ options_.with_replacement_},
+ do_expensive_check_);
+ } else {
+ std::tie(src, dst, wgt, edge_id, edge_type, hop, offsets) =
+ cugraph::homogeneous_uniform_neighbor_sample(
+ handle_,
+ rng_state_->rng_state_,
+ graph_view,
+ (edge_weights != nullptr) ? std::make_optional(edge_weights->view()) : std::nullopt,
+ (edge_ids != nullptr) ? std::make_optional(edge_ids->view()) : std::nullopt,
+ (edge_types != nullptr) ? std::make_optional(edge_types->view()) : std::nullopt,
+ raft::device_span{start_vertices.data(), start_vertices.size()},
+ (start_vertex_offsets_ != nullptr)
+ ? std::make_optional>((*start_vertex_labels).data(),
+ (*start_vertex_labels).size())
+ : std::nullopt,
+ label_to_comm_rank ? std::make_optional(raft::device_span{
+ (*label_to_comm_rank).data(), (*label_to_comm_rank).size()})
+ : std::nullopt,
+ raft::host_span(fan_out_->as_type(), fan_out_->size_),
+ cugraph::sampling_flags_t{options_.prior_sources_behavior_,
+ options_.return_hops_,
+ options_.dedupe_sources_,
+ options_.with_replacement_},
+ do_expensive_check_);
+ }
+ }
+
+ std::vector vertex_partition_lasts = graph_view.vertex_partition_range_lasts();
+
+ cugraph::unrenumber_int_vertices(handle_,
+ src.data(),
+ src.size(),
+ number_map->data(),
+ vertex_partition_lasts,
+ do_expensive_check_);
+
+ cugraph::unrenumber_int_vertices(handle_,
+ dst.data(),
+ dst.size(),
+ number_map->data(),
+ vertex_partition_lasts,
+ do_expensive_check_);
+
+ std::optional> majors{std::nullopt};
+ rmm::device_uvector minors(0, handle_.get_stream());
+ std::optional> major_offsets{std::nullopt};
+
+ std::optional> label_hop_offsets{std::nullopt};
+
+ std::optional> renumber_map{std::nullopt};
+ std::optional> renumber_map_offsets{std::nullopt};
+
+ bool src_is_major = (options_.compression_type_ == cugraph_compression_type_t::CSR) ||
+ (options_.compression_type_ == cugraph_compression_type_t::DCSR) ||
+ (options_.compression_type_ == cugraph_compression_type_t::COO);
+
+ // Extract the edge_label from the offsets
+ if (offsets) {
+ edge_label = cugraph::c_api::expand_sparse_offsets(
+ raft::device_span{(*offsets).data(), (*offsets).size()},
+ label_t{0},
+ handle_.get_stream());
+ }
+
+ if (options_.renumber_results_) {
+ if (num_edge_types_ == 1) { // homogeneous renumbering
+ if (options_.compression_type_ == cugraph_compression_type_t::COO) {
+ // COO
+
+ rmm::device_uvector output_majors(0, handle_.get_stream());
+ rmm::device_uvector output_renumber_map(0, handle_.get_stream());
+ std::tie(output_majors,
+ minors,
+ wgt,
+ edge_id,
+ edge_type,
+ label_hop_offsets,
+ output_renumber_map,
+ renumber_map_offsets) =
+ cugraph::renumber_and_sort_sampled_edgelist(
+ handle_,
+ std::move(src),
+ std::move(dst),
+ std::move(wgt),
+ std::move(edge_id),
+ std::move(edge_type),
+ std::move(hop),
+ options_.retain_seeds_
+ ? std::make_optional(raft::device_span{
+ start_vertices_->as_type(), start_vertices_->size_})
+ : std::nullopt,
+ options_.retain_seeds_
+ ? std::make_optional(raft::device_span{
+ start_vertex_offsets_->as_type(), start_vertex_offsets_->size_})
+ : std::nullopt,
+ offsets ? std::make_optional(
+ raft::device_span{offsets->data(), offsets->size()})
+ : std::nullopt,
+ offsets ? (*offsets).size() - 1 : size_t{1},
+ hop ? fan_out_->size_ : size_t{1},
+ src_is_major,
+ do_expensive_check_);
+
+ majors.emplace(std::move(output_majors));
+ renumber_map.emplace(std::move(output_renumber_map));
+ } else {
+ // (D)CSC, (D)CSR
+
+ bool doubly_compress =
+ (options_.compression_type_ == cugraph_compression_type_t::DCSR) ||
+ (options_.compression_type_ == cugraph_compression_type_t::DCSC);
+
+ rmm::device_uvector output_major_offsets(0, handle_.get_stream());
+ rmm::device_uvector output_renumber_map(0, handle_.get_stream());
+
+ std::tie(majors,
+ output_major_offsets,
+ minors,
+ wgt,
+ edge_id,
+ edge_type,
+ label_hop_offsets,
+ output_renumber_map,
+ renumber_map_offsets) =
+ cugraph::renumber_and_compress_sampled_edgelist(
+ handle_,
+ std::move(src),
+ std::move(dst),
+ std::move(wgt),
+ std::move(edge_id),
+ std::move(edge_type),
+ std::move(hop),
+ options_.retain_seeds_
+ ? std::make_optional(raft::device_span{
+ start_vertices_->as_type(), start_vertices_->size_})
+ : std::nullopt,
+ options_.retain_seeds_
+ ? std::make_optional(raft::device_span{
+ start_vertex_offsets_->as_type(), start_vertex_offsets_->size_})
+ : std::nullopt,
+ offsets ? std::make_optional(
+ raft::device_span{offsets->data(), offsets->size()})
+ : std::nullopt,
+ edge_label ? (*offsets).size() - 1 : size_t{1}, // FIXME: update edge_label
+ hop ? fan_out_->size_ : size_t{1},
+ src_is_major,
+ options_.compress_per_hop_,
+ doubly_compress,
+ do_expensive_check_);
+
+ renumber_map.emplace(std::move(output_renumber_map));
+ major_offsets.emplace(std::move(output_major_offsets));
+ }
+
+ // These are now represented by label_hop_offsets
+ hop.reset();
+ offsets.reset();
+
+ } else { // heterogeneous renumbering
+
+ rmm::device_uvector vertex_type_offsets(
+ graph_view.local_vertex_partition_range_size(), handle_.get_stream());
+
+ cugraph::detail::sequence_fill(handle_.get_stream(),
+ vertex_type_offsets.begin(),
+ vertex_type_offsets.size(),
+ vertex_t{0} // FIXME: Update array
+ );
+
+ rmm::device_uvector output_majors(0, handle_.get_stream());
+ rmm::device_uvector output_renumber_map(0, handle_.get_stream());
+
+ // extract the edge_type from label_type_hop_offsets
+ std::optional> label_type_hop_offsets{std::nullopt};
+ std::tie(output_majors,
+ minors,
+ wgt,
+ edge_id,
+ label_type_hop_offsets, // Contains information about the type and hop offsets
+ output_renumber_map,
+ (*renumber_map_offsets),
+ renumbered_and_sorted_edge_id_renumber_map,
+ renumbered_and_sorted_edge_id_renumber_map_label_type_offsets) =
+ cugraph::heterogeneous_renumber_and_sort_sampled_edgelist(
+ handle_,
+ std::move(src),
+ std::move(dst),
+ std::move(wgt),
+ std::move(edge_id),
+ std::move(edge_type),
+ std::move(hop),
+ options_.retain_seeds_
+ ? std::make_optional(raft::device_span{
+ start_vertices_->as_type(), start_vertices_->size_})
+ : std::nullopt,
+ options_.retain_seeds_
+ ? std::make_optional(raft::device_span{
+ start_vertex_offsets_->as_type(), start_vertex_offsets_->size_})
+ : std::nullopt,
+ offsets ? std::make_optional(
+ raft::device_span{offsets->data(), offsets->size()})
+ : std::nullopt,
+ raft::device_span{vertex_type_offsets.data(),
+ vertex_type_offsets.size()},
+
+ edge_label ? (*offsets).size() - 1 : size_t{1},
+ hop ? fan_out_->size_ : size_t{1},
+ size_t{1},
+ num_edge_types_,
+ src_is_major,
+ do_expensive_check_);
+ if (edge_type) {
+ (*edge_type)
+ .resize(raft::device_span{(*label_type_hop_offsets).data(),
+ (*label_type_hop_offsets).size()}
+ .back() -
+ 1,
+ handle_.get_stream());
+ cugraph::detail::sequence_fill(
+ handle_.get_stream(), (*edge_type).begin(), (*edge_type).size(), edge_type_t{0});
+ }
+
+ majors.emplace(std::move(output_majors));
+ // FIXME: Need to update renumber_map because default values are being passed
+ renumber_map.emplace(std::move(output_renumber_map));
+ }
+
+ } else {
+ if (options_.compression_type_ != cugraph_compression_type_t::COO) {
+ CUGRAPH_FAIL("Can only use COO format if not renumbering");
+ }
+
+ std::tie(src, dst, wgt, edge_id, edge_type, label_hop_offsets) =
+ cugraph::sort_sampled_edgelist(handle_,
+ std::move(src),
+ std::move(dst),
+ std::move(wgt),
+ std::move(edge_id),
+ std::move(edge_type),
+ std::move(hop),
+ offsets
+ ? std::make_optional(raft::device_span{
+ offsets->data(), offsets->size()})
+ : std::nullopt,
+ // derive label size from offset size instead of performing
+ // thrust::unique on edge_label.
+ edge_label ? (*offsets).size() - 1 : size_t{1},
+ hop ? fan_out_->size_ : size_t{1},
+ src_is_major,
+ do_expensive_check_);
+
+ majors.emplace(std::move(src));
+ minors = std::move(dst);
+
+ hop.reset();
+ offsets.reset();
+ }
+
+ result_ = new cugraph::c_api::cugraph_sample_result_t{
+ (major_offsets)
+ ? new cugraph::c_api::cugraph_type_erased_device_array_t(*major_offsets, SIZE_T)
+ : nullptr,
+ (majors)
+ ? new cugraph::c_api::cugraph_type_erased_device_array_t(*majors, graph_->vertex_type_)
+ : nullptr,
+ new cugraph::c_api::cugraph_type_erased_device_array_t(minors, graph_->vertex_type_),
+ (edge_id)
+ ? new cugraph::c_api::cugraph_type_erased_device_array_t(*edge_id, graph_->edge_type_)
+ : nullptr,
+ (edge_type) ? new cugraph::c_api::cugraph_type_erased_device_array_t(
+ *edge_type, graph_->edge_type_id_type_)
+ : nullptr,
+ (wgt) ? new cugraph::c_api::cugraph_type_erased_device_array_t(*wgt, graph_->weight_type_)
+ : nullptr,
+ (hop) ? new cugraph::c_api::cugraph_type_erased_device_array_t(*hop, INT32)
+ : nullptr, // FIXME get rid of this
+ (label_hop_offsets)
+ ? new cugraph::c_api::cugraph_type_erased_device_array_t(*label_hop_offsets, SIZE_T)
+ : nullptr,
+ (edge_label)
+ ? new cugraph::c_api::cugraph_type_erased_device_array_t(edge_label.value(), INT32)
+ : nullptr,
+ (renumber_map) ? new cugraph::c_api::cugraph_type_erased_device_array_t(
+ renumber_map.value(), graph_->vertex_type_)
+ : nullptr,
+ (renumber_map_offsets) ? new cugraph::c_api::cugraph_type_erased_device_array_t(
+ renumber_map_offsets.value(), SIZE_T)
+ : nullptr,
+ (renumbered_and_sorted_edge_id_renumber_map)
+ ? new cugraph::c_api::cugraph_type_erased_device_array_t(
+ renumbered_and_sorted_edge_id_renumber_map.value(), graph_->edge_type_)
+ : nullptr,
+ (renumbered_and_sorted_edge_id_renumber_map_label_type_offsets)
+ ? new cugraph::c_api::cugraph_type_erased_device_array_t(
+ renumbered_and_sorted_edge_id_renumber_map_label_type_offsets.value(), SIZE_T)
+ : nullptr};
}
}
};
@@ -985,6 +1592,26 @@ extern "C" cugraph_type_erased_device_array_view_t* cugraph_sample_result_get_re
internal_pointer->renumber_map_offsets_->view());
}
+extern "C" cugraph_type_erased_device_array_view_t* cugraph_sample_result_get_edge_renumber_map(
+ const cugraph_sample_result_t* result)
+{
+ auto internal_pointer = reinterpret_cast(result);
+ return internal_pointer->renumber_map_ == nullptr
+ ? NULL
+ : reinterpret_cast(
+ internal_pointer->edge_renumber_map_->view());
+}
+
+extern "C" cugraph_type_erased_device_array_view_t*
+cugraph_sample_result_get_edge_renumber_map_offsets(const cugraph_sample_result_t* result)
+{
+ auto internal_pointer = reinterpret_cast(result);
+ return internal_pointer->renumber_map_ == nullptr
+ ? NULL
+ : reinterpret_cast(
+ internal_pointer->edge_renumber_map_offsets_->view());
+}
+
extern "C" cugraph_error_code_t cugraph_test_uniform_neighborhood_sample_result_create(
const cugraph_resource_handle_t* handle,
const cugraph_type_erased_device_array_view_t* srcs,
@@ -1292,6 +1919,7 @@ cugraph_error_code_t cugraph_uniform_neighbor_sample(
"fan_out should be of type int",
*error);
+ // Deprecated functor
uniform_neighbor_sampling_functor functor{handle,
graph,
start_vertices,
@@ -1369,6 +1997,7 @@ cugraph_error_code_t cugraph_biased_neighbor_sample(
"fan_out should be of type int",
*error);
+ // Deprecated functor
biased_neighbor_sampling_functor functor{handle,
graph,
edge_biases,
@@ -1383,3 +2012,249 @@ cugraph_error_code_t cugraph_biased_neighbor_sample(
do_expensive_check};
return cugraph::c_api::run_algorithm(graph, functor, result, error);
}
+
+cugraph_error_code_t cugraph_heterogeneous_uniform_neighbor_sample(
+ const cugraph_resource_handle_t* handle,
+ cugraph_rng_state_t* rng_state,
+ cugraph_graph_t* graph,
+ const cugraph_type_erased_device_array_view_t* start_vertices,
+ const cugraph_type_erased_device_array_view_t* start_vertex_offsets,
+ const cugraph_type_erased_host_array_view_t* fan_out,
+ int num_edge_types,
+ const cugraph_sampling_options_t* options,
+ bool_t do_expensive_check,
+ cugraph_sample_result_t** result,
+ cugraph_error_t** error)
+{
+ auto options_cpp = *reinterpret_cast(options);
+
+ // FIXME: Should we maintain this contition?
+ CAPI_EXPECTS((!options_cpp.retain_seeds_) || (start_vertex_offsets != nullptr),
+ CUGRAPH_INVALID_INPUT,
+ "must specify start_vertex_offsets if retain_seeds is true",
+ *error);
+
+ CAPI_EXPECTS((start_vertex_offsets == nullptr) ||
+ (reinterpret_cast(
+ start_vertex_offsets)
+ ->type_ == SIZE_T),
+ CUGRAPH_INVALID_INPUT,
+ "start_vertex_offsets should be of type size_t",
+ *error);
+
+ CAPI_EXPECTS(
+ reinterpret_cast(fan_out)
+ ->type_ == INT32,
+ CUGRAPH_INVALID_INPUT,
+ "fan_out should be of type int",
+ *error);
+
+ CAPI_EXPECTS(reinterpret_cast(graph)->vertex_type_ ==
+ reinterpret_cast(
+ start_vertices)
+ ->type_,
+ CUGRAPH_INVALID_INPUT,
+ "vertex type of graph and start_vertices must match",
+ *error);
+
+ neighbor_sampling_functor functor{handle,
+ rng_state,
+ graph,
+ nullptr,
+ start_vertices,
+ start_vertex_offsets,
+ fan_out,
+ num_edge_types,
+ std::move(options_cpp),
+ FALSE,
+ do_expensive_check};
+ return cugraph::c_api::run_algorithm(graph, functor, result, error);
+}
+
+cugraph_error_code_t cugraph_heterogeneous_biased_neighbor_sample(
+ const cugraph_resource_handle_t* handle,
+ cugraph_rng_state_t* rng_state,
+ cugraph_graph_t* graph,
+ const cugraph_edge_property_view_t* edge_biases,
+ const cugraph_type_erased_device_array_view_t* start_vertices,
+ const cugraph_type_erased_device_array_view_t* start_vertex_offsets,
+ const cugraph_type_erased_host_array_view_t* fan_out,
+ int num_edge_types,
+ const cugraph_sampling_options_t* options,
+ bool_t do_expensive_check,
+ cugraph_sample_result_t** result,
+ cugraph_error_t** error)
+{
+ auto options_cpp = *reinterpret_cast(options);
+
+ CAPI_EXPECTS(
+ (edge_biases != nullptr) ||
+ (reinterpret_cast(graph)->edge_weights_ != nullptr),
+ CUGRAPH_INVALID_INPUT,
+ "edge_biases is required if the graph is not weighted",
+ *error);
+
+ // FIXME: Should we maintain this contition?
+ CAPI_EXPECTS((!options_cpp.retain_seeds_) || (start_vertex_offsets != nullptr),
+ CUGRAPH_INVALID_INPUT,
+ "must specify start_vertex_offsets if retain_seeds is true",
+ *error);
+
+ CAPI_EXPECTS((start_vertex_offsets == nullptr) ||
+ (reinterpret_cast(
+ start_vertex_offsets)
+ ->type_ == SIZE_T),
+ CUGRAPH_INVALID_INPUT,
+ "start_vertex_offsets should be of type size_t",
+ *error);
+
+ CAPI_EXPECTS(
+ reinterpret_cast(fan_out)
+ ->type_ == INT32,
+ CUGRAPH_INVALID_INPUT,
+ "fan_out should be of type int",
+ *error);
+
+ CAPI_EXPECTS(reinterpret_cast(graph)->vertex_type_ ==
+ reinterpret_cast(
+ start_vertices)
+ ->type_,
+ CUGRAPH_INVALID_INPUT,
+ "vertex type of graph and start_vertices must match",
+ *error);
+
+ neighbor_sampling_functor functor{handle,
+ rng_state,
+ graph,
+ edge_biases,
+ start_vertices,
+ start_vertex_offsets,
+ fan_out,
+ num_edge_types,
+ std::move(options_cpp),
+ TRUE,
+ do_expensive_check};
+ return cugraph::c_api::run_algorithm(graph, functor, result, error);
+}
+
+cugraph_error_code_t cugraph_homogeneous_uniform_neighbor_sample(
+ const cugraph_resource_handle_t* handle,
+ cugraph_rng_state_t* rng_state,
+ cugraph_graph_t* graph,
+ const cugraph_type_erased_device_array_view_t* start_vertices,
+ const cugraph_type_erased_device_array_view_t* start_vertex_offsets, // RENAME?
+ const cugraph_type_erased_host_array_view_t* fan_out,
+ const cugraph_sampling_options_t* options,
+ bool_t do_expensive_check,
+ cugraph_sample_result_t** result,
+ cugraph_error_t** error)
+{
+ auto options_cpp = *reinterpret_cast(options);
+
+ // FIXME: Should we maintain this contition?
+ CAPI_EXPECTS((!options_cpp.retain_seeds_) || (start_vertex_offsets != nullptr),
+ CUGRAPH_INVALID_INPUT,
+ "must specify start_vertex_offsets if retain_seeds is true",
+ *error);
+
+ CAPI_EXPECTS((start_vertex_offsets == nullptr) ||
+ (reinterpret_cast(
+ start_vertex_offsets)
+ ->type_ == SIZE_T),
+ CUGRAPH_INVALID_INPUT,
+ "start_vertex_offsets should be of type size_t",
+ *error);
+
+ CAPI_EXPECTS(
+ reinterpret_cast(fan_out)
+ ->type_ == INT32,
+ CUGRAPH_INVALID_INPUT,
+ "fan_out type must be INT32",
+ *error);
+
+ CAPI_EXPECTS(reinterpret_cast(graph)->vertex_type_ ==
+ reinterpret_cast(
+ start_vertices)
+ ->type_,
+ CUGRAPH_INVALID_INPUT,
+ "vertex type of graph and start_vertices must match",
+ *error);
+
+ neighbor_sampling_functor functor{handle,
+ rng_state,
+ graph,
+ nullptr,
+ start_vertices,
+ start_vertex_offsets,
+ fan_out,
+ 1, // num_edge_types
+ std::move(options_cpp),
+ FALSE,
+ do_expensive_check};
+ return cugraph::c_api::run_algorithm(graph, functor, result, error);
+}
+
+cugraph_error_code_t cugraph_homogeneous_biased_neighbor_sample(
+ const cugraph_resource_handle_t* handle,
+ cugraph_rng_state_t* rng_state,
+ cugraph_graph_t* graph,
+ const cugraph_edge_property_view_t* edge_biases,
+ const cugraph_type_erased_device_array_view_t* start_vertices,
+ const cugraph_type_erased_device_array_view_t* start_vertex_offsets,
+ const cugraph_type_erased_host_array_view_t* fan_out,
+ const cugraph_sampling_options_t* options,
+ bool_t do_expensive_check,
+ cugraph_sample_result_t** result,
+ cugraph_error_t** error)
+{
+ auto options_cpp = *reinterpret_cast