Skip to content

Commit

Permalink
Define and implement C/C++ for MNMG Egonet (#2864)
Browse files Browse the repository at this point in the history
Define and implement C API for egonet.  This will help us eliminate dependence on `cython.cu`.

Closes #2906 
Closes #2907
Closes #2908
Closes #2909
Closes #2910
Closes #2911

Authors:
  - Chuck Hastings (https://github.com/ChuckHastings)

Approvers:
  - Seunghwa Kang (https://github.com/seunghwak)
  - Joseph Nke (https://github.com/jnke2016)

URL: #2864
  • Loading branch information
ChuckHastings authored Nov 11, 2022
1 parent 4802b28 commit a950bd9
Show file tree
Hide file tree
Showing 17 changed files with 2,072 additions and 406 deletions.
4 changes: 3 additions & 1 deletion cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ set(CUGRAPH_SOURCES
src/community/legacy/ktruss.cu
src/community/legacy/ecg.cu
src/community/legacy/extract_subgraph_by_vertex.cu
src/community/legacy/egonet.cu
src/community/egonet_sg.cu
src/community/egonet_mg.cu
src/sampling/random_walks.cu
src/sampling/random_walks_sg.cu
src/sampling/detail/sampling_utils_mg.cu
Expand Down Expand Up @@ -365,6 +366,7 @@ add_library(cugraph_c
src/c_api/betweenness_centrality.cpp
src/c_api/core_number.cpp
src/c_api/core_result.cpp
src/c_api/extract_ego.cpp
src/c_api/k_core.cpp
src/c_api/induced_subgraph.cpp
src/c_api/induced_subgraph_helper.cu
Expand Down
35 changes: 35 additions & 0 deletions cpp/include/cugraph/algorithms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1349,10 +1349,14 @@ void katz_centrality(raft::handle_t const& handle,
bool has_initial_guess = false,
bool normalize = false,
bool do_expensive_check = false);

/**
* @brief returns induced EgoNet subgraph(s) of neighbors centered at nodes in source_vertex within
* a given radius.
*
* @deprecated This algorithm will be deprecated to replaced by the new version
* that uses the raft::device_span.
*
* @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.
Expand Down Expand Up @@ -1380,6 +1384,37 @@ extract_ego(raft::handle_t const& handle,
vertex_t n_subgraphs,
vertex_t radius);

/**
* @brief returns induced EgoNet subgraph(s) of neighbors centered at nodes in source_vertex within
* a given radius.
*
* @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 multi_gpu Flag indicating whether template instantiation should target single-GPU (false)
* or multi-GPU (true).
* @param handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, and
* handles to various CUDA libraries) to run graph algorithms. Must have at least one worker stream.
* @param graph_view Graph view object of, we extract induced egonet subgraphs from @p graph_view.
* @param source_vertex Pointer to egonet center vertices (size == @p n_subgraphs).
* @param n_subgraphs Number of induced EgoNet subgraphs to extract (ie. number of elements in @p
* source_vertex).
* @param radius Include all neighbors of distance <= radius from @p source_vertex.
* @return std::tuple<rmm::device_uvector<vertex_t>, rmm::device_uvector<vertex_t>,
* rmm::device_uvector<weight_t>, rmm::device_uvector<size_t>> Quadraplet of edge source vertices,
* edge destination vertices, edge weights, and edge offsets for each induced EgoNet subgraph.
*/
template <typename vertex_t, typename edge_t, typename weight_t, bool multi_gpu>
std::tuple<rmm::device_uvector<vertex_t>,
rmm::device_uvector<vertex_t>,
std::optional<rmm::device_uvector<weight_t>>,
rmm::device_uvector<size_t>>
extract_ego(raft::handle_t const& handle,
graph_view_t<vertex_t, edge_t, weight_t, false, multi_gpu> const& graph_view,
raft::device_span<vertex_t const> source_vertices,
vertex_t radius,
bool do_expensive_check = false);

/**
* @brief returns random walks (RW) from starting sources, where each path is of given maximum
* length. Uniform distribution is assumed for the random engine.
Expand Down
25 changes: 25 additions & 0 deletions cpp/include/cugraph_c/community_algorithms.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <cugraph_c/error.h>
#include <cugraph_c/graph.h>
#include <cugraph_c/graph_functions.h>
#include <cugraph_c/resource_handle.h>

/** @defgroup community Community algorithms
Expand Down Expand Up @@ -135,6 +136,30 @@ double cugraph_heirarchical_clustering_result_get_modularity(
*/
void cugraph_heirarchical_clustering_result_free(cugraph_heirarchical_clustering_result_t* result);

/**
* @brief Extract ego graphs
*
* @param [in] handle Handle for accessing resources
* @param [in] graph Pointer to graph. NOTE: Graph might be modified if the storage
* needs to be transposed
* @param [in] source_vertices Device array of vertices we want to extract egonets for.
* @param [in] radius The number of hops to go out from each source vertex
* @param [in] do_expensive_check
* A flag to run expensive checks for input arguments (if set to true)
* @param [out] result Opaque object containing the extracted subgraph
* @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_extract_ego(
const cugraph_resource_handle_t* handle,
cugraph_graph_t* graph,
const cugraph_type_erased_device_array_view_t* source_vertices,
size_t radius,
bool_t do_expensive_check,
cugraph_induced_subgraph_result_t** result,
cugraph_error_t** error);

#ifdef __cplusplus
}
#endif
Expand Down
154 changes: 154 additions & 0 deletions cpp/src/c_api/extract_ego.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright (c) 2022, 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 <cugraph_c/algorithms.h>

#include <c_api/abstract_functor.hpp>
#include <c_api/graph.hpp>
#include <c_api/induced_subgraph_result.hpp>
#include <c_api/resource_handle.hpp>
#include <c_api/utils.hpp>

#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 extract_ego_functor : public cugraph::c_api::abstract_functor {
raft::handle_t const& handle_;
cugraph::c_api::cugraph_graph_t* graph_;
cugraph::c_api::cugraph_type_erased_device_array_view_t const* source_vertices_;
size_t radius_;
bool do_expensive_check_;
cugraph::c_api::cugraph_induced_subgraph_result_t* result_{};

extract_ego_functor(::cugraph_resource_handle_t const* handle,
::cugraph_graph_t* graph,
::cugraph_type_erased_device_array_view_t const* source_vertices,
size_t radius,
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)),
source_vertices_(
reinterpret_cast<cugraph::c_api::cugraph_type_erased_device_array_view_t const*>(
source_vertices)),
radius_(radius),
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 {
// extract ego expects store_transposed == false
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, weight_t, false, multi_gpu>*>(
graph_->graph_);

auto graph_view = graph->view();

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

rmm::device_uvector<vertex_t> source_vertices(source_vertices_->size_, handle_.get_stream());
raft::copy(source_vertices.data(),
source_vertices_->as_type<vertex_t>(),
source_vertices.size(),
handle_.get_stream());

if constexpr (multi_gpu) {
source_vertices =
cugraph::detail::shuffle_ext_vertices_by_gpu_id(handle_, std::move(source_vertices));
}

cugraph::renumber_ext_vertices<vertex_t, multi_gpu>(
handle_,
source_vertices.data(),
source_vertices.size(),
number_map->data(),
graph_view.local_vertex_partition_range_first(),
graph_view.local_vertex_partition_range_last(),
do_expensive_check_);

auto [src, dst, wgt, edge_offsets] =
cugraph::extract_ego<vertex_t, edge_t, weight_t, multi_gpu>(
handle_,
graph_view,
raft::device_span<vertex_t const>{source_vertices.data(), source_vertices.size()},
radius_,
do_expensive_check_);

cugraph::unrenumber_int_vertices<vertex_t, multi_gpu>(
handle_,
src.data(),
src.size(),
number_map->data(),
graph_view.vertex_partition_range_lasts(),
do_expensive_check_);

cugraph::unrenumber_int_vertices<vertex_t, multi_gpu>(
handle_,
dst.data(),
dst.size(),
number_map->data(),
graph_view.vertex_partition_range_lasts(),
do_expensive_check_);

result_ = new cugraph::c_api::cugraph_induced_subgraph_result_t{
new cugraph::c_api::cugraph_type_erased_device_array_t(src, graph_->vertex_type_),
new cugraph::c_api::cugraph_type_erased_device_array_t(dst, graph_->edge_type_),
wgt ? new cugraph::c_api::cugraph_type_erased_device_array_t(*wgt, graph_->edge_type_)
: NULL,
new cugraph::c_api::cugraph_type_erased_device_array_t(edge_offsets,
data_type_id_t::SIZE_T)};
}
}
};

} // namespace

extern "C" cugraph_error_code_t cugraph_extract_ego(
const cugraph_resource_handle_t* handle,
cugraph_graph_t* graph,
const cugraph_type_erased_device_array_view_t* source_vertices,
size_t radius,
bool_t do_expensive_check,
cugraph_induced_subgraph_result_t** result,
cugraph_error_t** error)
{
extract_ego_functor functor(handle, graph, source_vertices, radius, do_expensive_check);

return cugraph::c_api::run_algorithm(graph, functor, result, error);
}
Loading

0 comments on commit a950bd9

Please sign in to comment.