Skip to content

Commit

Permalink
Merge pull request #39 from betochimas/branch-22.06
Browse files Browse the repository at this point in the history
Define C API for eigenvector centrality (rapidsai#2180)
  • Loading branch information
betochimas authored Apr 6, 2022
2 parents 3e0cf16 + 9956084 commit 66ba355
Show file tree
Hide file tree
Showing 14 changed files with 617 additions and 134 deletions.
2 changes: 2 additions & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ add_library(cugraph_c SHARED
src/c_api/graph_sg.cpp
src/c_api/graph_mg.cpp
src/c_api/pagerank.cpp
src/c_api/centrality_result.cpp
src/c_api/eigenvector_centrality.cpp
src/c_api/hits.cpp
src/c_api/bfs.cpp
src/c_api/sssp.cpp
Expand Down
58 changes: 42 additions & 16 deletions cpp/include/cugraph_c/algorithms.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,36 +25,36 @@ extern "C" {
#endif

/**
* @brief Opaque pagerank result type
* @brief Opaque centrality result type
*/
typedef struct {
int32_t align_;
} cugraph_pagerank_result_t;
} cugraph_centrality_result_t;

/**
* @brief Get the vertex ids from the pagerank result
* @brief Get the vertex ids from the centrality result
*
* @param [in] result The result from pagerank
* @param [in] result The result from a centrality algorithm
* @return type erased array of vertex ids
*/
cugraph_type_erased_device_array_view_t* cugraph_pagerank_result_get_vertices(
cugraph_pagerank_result_t* result);
cugraph_type_erased_device_array_view_t* cugraph_centrality_result_get_vertices(
cugraph_centrality_result_t* result);

/**
* @brief Get the pagerank values from the pagerank result
* @brief Get the centrality values from a centrality algorithm result
*
* @param [in] result The result from pagerank
* @return type erased array of pagerank values
* @param [in] result The result from a centrality algorithm
* @return type erased array view of centrality values
*/
cugraph_type_erased_device_array_view_t* cugraph_pagerank_result_get_pageranks(
cugraph_pagerank_result_t* result);
cugraph_type_erased_device_array_view_t* cugraph_centrality_result_get_values(
cugraph_centrality_result_t* result);

/**
* @brief Free pagerank result
* @brief Free centrality result
*
* @param [in] result The result from pagerank
* @param [in] result The result from a centrality algorithm
*/
void cugraph_pagerank_result_free(cugraph_pagerank_result_t* result);
void cugraph_centrality_result_free(cugraph_centrality_result_t* result);

/**
* @brief Compute pagerank
Expand Down Expand Up @@ -90,7 +90,7 @@ cugraph_error_code_t cugraph_pagerank(
size_t max_iterations,
bool_t has_initial_guess,
bool_t do_expensive_check,
cugraph_pagerank_result_t** result,
cugraph_centrality_result_t** result,
cugraph_error_t** error);

/**
Expand Down Expand Up @@ -136,9 +136,35 @@ cugraph_error_code_t cugraph_personalized_pagerank(
size_t max_iterations,
bool_t has_initial_guess,
bool_t do_expensive_check,
cugraph_pagerank_result_t** result,
cugraph_centrality_result_t** result,
cugraph_error_t** error);

/**
* @brief Compute eigenvector centrality
*
* Computed using the power method.
*
* @param [in] handle Handle for accessing resources
* @param [in] graph Pointer to graph
* @param [in] epsilon Error tolerance to check convergence. Convergence is measured
* comparing the L1 norm until it is less than epsilon
* @param [in] max_iterations Maximum number of power iterations, will not exceed this number
* of iterations even if we haven't converged
* @param [in] do_expensive_check A flag to run expensive checks for input arguments (if set to
* `true`).
* @param [out] result Opaque pointer to eigenvector centrality results
* @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_eigenvector_centrality(const cugraph_resource_handle_t* handle,
cugraph_graph_t* graph,
double epsilon,
size_t max_iterations,
bool_t do_expensive_check,
cugraph_centrality_result_t** result,
cugraph_error_t** error);

/**
* @brief Opaque hits result type
*/
Expand Down
43 changes: 43 additions & 0 deletions cpp/src/c_api/centrality_result.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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/centrality_result.hpp>

extern "C" cugraph_type_erased_device_array_view_t* cugraph_centrality_result_get_vertices(
cugraph_centrality_result_t* result)
{
auto internal_pointer = reinterpret_cast<cugraph::c_api::cugraph_centrality_result_t*>(result);
return reinterpret_cast<cugraph_type_erased_device_array_view_t*>(
internal_pointer->vertex_ids_->view());
}

extern "C" cugraph_type_erased_device_array_view_t* cugraph_centrality_result_get_values(
cugraph_centrality_result_t* result)
{
auto internal_pointer = reinterpret_cast<cugraph::c_api::cugraph_centrality_result_t*>(result);
return reinterpret_cast<cugraph_type_erased_device_array_view_t*>(
internal_pointer->values_->view());
}

extern "C" void cugraph_centrality_result_free(cugraph_centrality_result_t* result)
{
auto internal_pointer = reinterpret_cast<cugraph::c_api::cugraph_centrality_result_t*>(result);
delete internal_pointer->vertex_ids_;
delete internal_pointer->values_;
delete internal_pointer;
}
30 changes: 30 additions & 0 deletions cpp/src/c_api/centrality_result.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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.
*/

#pragma once

#include <c_api/array.hpp>

namespace cugraph {
namespace c_api {

struct cugraph_centrality_result_t {
cugraph_type_erased_device_array_t* vertex_ids_{};
cugraph_type_erased_device_array_t* values_{};
};

} // namespace c_api
} // namespace cugraph
125 changes: 125 additions & 0 deletions cpp/src/c_api/eigenvector_centrality.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* 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/centrality_result.hpp>
#include <c_api/graph.hpp>
#include <c_api/resource_handle.hpp>
#include <c_api/utils.hpp>

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

#include <optional>

namespace {

struct eigenvector_centrality_functor : public cugraph::c_api::abstract_functor {
raft::handle_t const& handle_;
cugraph::c_api::cugraph_graph_t* graph_{};
double epsilon_{};
size_t max_iterations_{};
bool do_expensive_check_{};
cugraph::c_api::cugraph_centrality_result_t* result_{};

eigenvector_centrality_functor(cugraph_resource_handle_t const* handle,
cugraph_graph_t* graph,
double epsilon,
size_t max_iterations,
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)),
epsilon_(epsilon),
max_iterations_(max_iterations),
do_expensive_check_(do_expensive_check)
{
}

template <typename vertex_t,
typename edge_t,
typename weight_t,
bool store_transposed,
bool multi_gpu>
void operator()()
{
// FIXME: Think about how to handle SG vice MG
if constexpr (!cugraph::is_candidate<vertex_t, edge_t, weight_t>::value) {
unsupported();
} else {
// Eigenvector Centrality expects store_transposed == true
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, true, 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<weight_t> centralities(graph_view.get_number_of_local_vertices(),
handle_.get_stream());

// FIXME: For now we'll call pagerank which returns a similarly formatted thing
cugraph::pagerank<vertex_t, edge_t, weight_t, weight_t, multi_gpu>(
handle_,
graph_view,
std::nullopt,
std::nullopt,
std::nullopt,
std::nullopt,
centralities.data(),
weight_t{0.95},
static_cast<weight_t>(epsilon_),
max_iterations_,
false,
do_expensive_check_);

rmm::device_uvector<vertex_t> vertex_ids(graph_view.get_number_of_local_vertices(),
handle_.get_stream());
raft::copy(vertex_ids.data(), number_map->data(), vertex_ids.size(), handle_.get_stream());

result_ = new cugraph::c_api::cugraph_centrality_result_t{
new cugraph::c_api::cugraph_type_erased_device_array_t(vertex_ids, graph_->vertex_type_),
new cugraph::c_api::cugraph_type_erased_device_array_t(centralities, graph_->weight_type_)};
}
}
};

} // namespace

extern "C" cugraph_error_code_t cugraph_eigenvector_centrality(
const cugraph_resource_handle_t* handle,
cugraph_graph_t* graph,
double epsilon,
size_t max_iterations,
bool_t do_expensive_check,
cugraph_centrality_result_t** result,
cugraph_error_t** error)
{
eigenvector_centrality_functor functor(
handle, graph, epsilon, max_iterations, do_expensive_check);

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

0 comments on commit 66ba355

Please sign in to comment.