Skip to content

Commit

Permalink
extract the edgelist from the graph (#4750)
Browse files Browse the repository at this point in the history
This PR exposes the C++ function decompress_to_edgelist to the C, PLC and Python API. This will enable the extraction of the edgelist from a graph which is currently not supported. It also removes the deprecated parameter `legacy_renum_only`

Authors:
  - Joseph Nke (https://github.com/jnke2016)

Approvers:
  - Rick Ratzel (https://github.com/rlratzel)
  - Chuck Hastings (https://github.com/ChuckHastings)
  - Seunghwa Kang (https://github.com/seunghwak)

URL: #4750
  • Loading branch information
jnke2016 authored Nov 22, 2024
1 parent 290d5d4 commit d3b80a2
Show file tree
Hide file tree
Showing 15 changed files with 840 additions and 95 deletions.
2 changes: 2 additions & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -538,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)

Expand Down
102 changes: 102 additions & 0 deletions cpp/include/cugraph_c/graph_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand All @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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);
Expand Down Expand Up @@ -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
137 changes: 137 additions & 0 deletions cpp/src/c_api/decompress_to_edgelist.cpp
Original file line number Diff line number Diff line change
@@ -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 <cugraph_c/algorithms.h>

#include <cugraph/algorithms.hpp>
#include <cugraph/detail/shuffle_wrappers.hpp>
#include <cugraph/detail/utility_wrappers.hpp>
#include <cugraph/graph_functions.hpp>

#include <optional>

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<cugraph::c_api::cugraph_resource_handle_t const*>(handle)->handle_),
graph_(reinterpret_cast<cugraph::c_api::cugraph_graph_t*>(graph)),
do_expensive_check_(do_expensive_check)
{
}

template <typename vertex_t,
typename edge_t,
typename weight_t,
typename edge_type_type_t,
bool store_transposed,
bool multi_gpu>
void operator()()
{
if constexpr (!cugraph::is_candidate<vertex_t, edge_t, weight_t>::value) {
unsupported();
} else {
if constexpr (store_transposed) {
error_code_ = cugraph::c_api::
transpose_storage<vertex_t, edge_t, weight_t, store_transposed, multi_gpu>(
handle_, graph_, error_.get());
if (error_code_ != CUGRAPH_SUCCESS) return;
}

auto graph =
reinterpret_cast<cugraph::graph_t<vertex_t, edge_t, store_transposed, multi_gpu>*>(
graph_->graph_);

auto graph_view = graph->view();

auto edge_weights = reinterpret_cast<cugraph::edge_property_t<
cugraph::graph_view_t<vertex_t, edge_t, store_transposed, multi_gpu>,
weight_t>*>(graph_->edge_weights_);

auto edge_ids = reinterpret_cast<cugraph::edge_property_t<
cugraph::graph_view_t<vertex_t, edge_t, store_transposed, multi_gpu>,
edge_t>*>(graph_->edge_ids_);

auto edge_types = reinterpret_cast<cugraph::edge_property_t<
cugraph::graph_view_t<vertex_t, edge_t, store_transposed, multi_gpu>,
edge_type_type_t>*>(graph_->edge_types_);

auto number_map = reinterpret_cast<rmm::device_uvector<vertex_t>*>(graph_->number_map_);

auto [result_src, result_dst, result_wgt, result_edge_id, result_edge_type] =
cugraph::decompress_to_edgelist<vertex_t,
edge_t,
weight_t,
edge_type_type_t,
store_transposed,
multi_gpu>(
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<raft::device_span<vertex_t const>>(
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);
}
83 changes: 83 additions & 0 deletions cpp/src/c_api/edgelist.cpp
Original file line number Diff line number Diff line change
@@ -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 <cugraph_c/algorithms.h>

extern "C" cugraph_type_erased_device_array_view_t* cugraph_edgelist_get_sources(
cugraph_edgelist_t* edgelist)
{
auto internal_pointer = reinterpret_cast<cugraph::c_api::cugraph_edgelist_t*>(edgelist);
return reinterpret_cast<cugraph_type_erased_device_array_view_t*>(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<cugraph::c_api::cugraph_edgelist_t*>(edgelist);
return reinterpret_cast<cugraph_type_erased_device_array_view_t*>(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<cugraph::c_api::cugraph_edgelist_t*>(edgelist);
return (internal_pointer->wgt_ == nullptr)
? NULL
: reinterpret_cast<cugraph_type_erased_device_array_view_t*>(
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<cugraph::c_api::cugraph_edgelist_t*>(edgelist);
return (internal_pointer->edge_ids_ == nullptr)
? NULL
: reinterpret_cast<cugraph_type_erased_device_array_view_t*>(
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<cugraph::c_api::cugraph_edgelist_t*>(edgelist);
return (internal_pointer->edge_type_ids_ == nullptr)
? NULL
: reinterpret_cast<cugraph_type_erased_device_array_view_t*>(
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<cugraph::c_api::cugraph_edgelist_t*>(edgelist);
return reinterpret_cast<cugraph_type_erased_device_array_view_t*>(
internal_pointer->subgraph_offsets_->view());
}

extern "C" void cugraph_edgelist_free(cugraph_edgelist_t* edgelist)
{
auto internal_pointer = reinterpret_cast<cugraph::c_api::cugraph_edgelist_t*>(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;
}
Loading

0 comments on commit d3b80a2

Please sign in to comment.