diff --git a/cpp/src/c_api/degrees.cu b/cpp/src/c_api/degrees.cu index 536807a2e5..d6481efa90 100644 --- a/cpp/src/c_api/degrees.cu +++ b/cpp/src/c_api/degrees.cu @@ -14,17 +14,21 @@ * limitations under the License. */ +#include "c_api/abstract_functor.hpp" +#include "c_api/degrees_result.hpp" +#include "c_api/graph.hpp" +#include "c_api/resource_handle.hpp" +#include "c_api/utils.hpp" + #include #include +#include #include #include +#include -#include -#include -#include -#include -#include +#include #include @@ -92,14 +96,21 @@ struct degrees_functor : public cugraph::c_api::abstract_functor { rmm::device_uvector vertex_ids(0, handle_.get_stream()); - if (source_vertices) { + if (source_vertices_) { // FIXME: Would be more efficient if graph_view.compute_*_degrees could take a vertex // subset - vertex_ids.resize(source_vertices_->size, handle_.get_stream()); - raft::copy( - vertex_ids.data(), source_vertices_->data(), vertex_ids.size(), handle_.get_stream()); + vertex_ids.resize(source_vertices_->size_, handle_.get_stream()); + raft::copy(vertex_ids.data(), + source_vertices_->as_type(), + vertex_ids.size(), + handle_.get_stream()); + + if constexpr (multi_gpu) { + vertex_ids = cugraph::detail::shuffle_ext_vertices_to_local_gpu_by_vertex_partitioning( + handle_, std::move(vertex_ids)); + } - cugraph::renumber_ext_vertices_local( + cugraph::renumber_ext_vertices( handle_, vertex_ids.data(), vertex_ids.size(), @@ -108,8 +119,8 @@ struct degrees_functor : public cugraph::c_api::abstract_functor { graph_view.local_vertex_partition_range_last(), do_expensive_check_); - auto vertex_partition = - vertex_partition_device_view_t(vertex_partition_view); + auto vertex_partition = cugraph::vertex_partition_device_view_t( + graph_view.local_vertex_partition_view()); auto vertices_iter = thrust::make_transform_iterator( vertex_ids.begin(), @@ -118,33 +129,42 @@ struct degrees_functor : public cugraph::c_api::abstract_functor { })); if (in_degrees && out_degrees) { - rmm::device_uvector tmp_in_degrees(vertex_ids.size(), handle.get_stream()); - rmm::device_uvector tmp_out_degrees(vertex_ids.size(), handle.get_stream()); + rmm::device_uvector tmp_in_degrees(vertex_ids.size(), handle_.get_stream()); + rmm::device_uvector tmp_out_degrees(vertex_ids.size(), handle_.get_stream()); thrust::gather( - rmm::exec_policy(stream), - vertex_iter, - vertex_iter + vertex_ids.size(), + handle_.get_thrust_policy(), + vertices_iter, + vertices_iter + vertex_ids.size(), thrust::make_zip_iterator(in_degrees->begin(), out_degrees->begin()), thrust::make_zip_iterator(tmp_in_degrees.begin(), tmp_out_degrees.begin())); in_degrees = std::move(tmp_in_degrees); out_degrees = std::move(tmp_out_degrees); } else if (in_degrees) { - rmm::device_uvector tmp_in_degrees(vertex_ids.size(), handle.get_stream()); - thrust::gather(rmm::exec_policy(stream), - vertex_iter, - vertex_iter + vertex_ids.size(), + rmm::device_uvector tmp_in_degrees(vertex_ids.size(), handle_.get_stream()); + thrust::gather(handle_.get_thrust_policy(), + vertices_iter, + vertices_iter + vertex_ids.size(), in_degrees->begin(), tmp_in_degrees.begin()); in_degrees = std::move(tmp_in_degrees); } else { - rmm::device_uvector tmp_out_degrees(vertex_ids.size(), handle.get_stream()); - thrust::gather(rmm::exec_policy(stream), - vertex_iter, - vertex_iter + vertex_ids.size(), + rmm::device_uvector tmp_out_degrees(vertex_ids.size(), handle_.get_stream()); + thrust::gather(handle_.get_thrust_policy(), + vertices_iter, + vertices_iter + vertex_ids.size(), out_degrees->begin(), tmp_out_degrees.begin()); out_degrees = std::move(tmp_out_degrees); } + + cugraph::unrenumber_local_int_vertices( + handle_, + vertex_ids.data(), + vertex_ids.size(), + number_map->data(), + graph_view.local_vertex_partition_range_first(), + graph_view.local_vertex_partition_range_last(), + do_expensive_check_); } else { vertex_ids.resize(graph_view.local_vertex_partition_range_size(), handle_.get_stream()); raft::copy(vertex_ids.data(), number_map->data(), vertex_ids.size(), handle_.get_stream()); diff --git a/cpp/tests/c_api/c_test_utils.h b/cpp/tests/c_api/c_test_utils.h index ab9fbeccd4..fbbf6333ee 100644 --- a/cpp/tests/c_api/c_test_utils.h +++ b/cpp/tests/c_api/c_test_utils.h @@ -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. @@ -101,6 +101,8 @@ int create_sg_test_graph(const cugraph_resource_handle_t* handle, cugraph_graph_t** graph, cugraph_error_t** ret_error); +size_t cugraph_size_t_allreduce(const cugraph_resource_handle_t* handle, size_t value); + #ifdef __cplusplus } #endif diff --git a/cpp/tests/c_api/degrees_test.c b/cpp/tests/c_api/degrees_test.c index 1c689ed5f8..10a038b323 100644 --- a/cpp/tests/c_api/degrees_test.c +++ b/cpp/tests/c_api/degrees_test.c @@ -33,6 +33,10 @@ int generic_degrees_test(vertex_t* h_src, weight_t* h_wgt, size_t num_vertices, size_t num_edges, + vertex_t* h_vertices, + size_t num_vertices_to_compute, + bool_t in_degrees, + bool_t out_degrees, bool_t store_transposed, bool_t is_symmetric, edge_t *h_in_degrees, @@ -56,10 +60,48 @@ int generic_degrees_test(vertex_t* h_src, TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "create_test_graph failed."); TEST_ALWAYS_ASSERT(ret_code == CUGRAPH_SUCCESS, cugraph_error_message(ret_error)); - ret_code = cugraph_degrees( - handle, graph, FALSE, &result, &ret_error); - TEST_ASSERT( - test_ret_value, ret_code == CUGRAPH_SUCCESS, "cugraph_extract_induced_subgraph failed."); + if (h_vertices == NULL) { + if (in_degrees && out_degrees) { + ret_code = cugraph_degrees( + handle, graph, NULL, FALSE, &result, &ret_error); + } else if (in_degrees) { + ret_code = cugraph_in_degrees( + handle, graph, NULL, FALSE, &result, &ret_error); + } else { + ret_code = cugraph_out_degrees( + handle, graph, NULL, FALSE, &result, &ret_error); + } + + TEST_ASSERT( + test_ret_value, ret_code == CUGRAPH_SUCCESS, "cugraph_extract_degrees failed."); + } else { + cugraph_type_erased_device_array_t* vertices = NULL; + cugraph_type_erased_device_array_view_t* vertices_view = NULL; + + ret_code = + cugraph_type_erased_device_array_create(handle, num_vertices_to_compute, INT32, &vertices, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "seeds create failed."); + + vertices_view = cugraph_type_erased_device_array_view(vertices); + + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + handle, vertices_view, (byte_t*)h_vertices, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "src copy_from_host failed."); + + if (in_degrees && out_degrees) { + ret_code = cugraph_degrees( + handle, graph, vertices_view, FALSE, &result, &ret_error); + } else if (in_degrees) { + ret_code = cugraph_in_degrees( + handle, graph, vertices_view, FALSE, &result, &ret_error); + } else { + ret_code = cugraph_out_degrees( + handle, graph, vertices_view, FALSE, &result, &ret_error); + } + + TEST_ASSERT( + test_ret_value, ret_code == CUGRAPH_SUCCESS, "cugraph_extract_degrees failed."); + } cugraph_type_erased_device_array_view_t* result_vertices; cugraph_type_erased_device_array_view_t* result_in_degrees; @@ -79,19 +121,32 @@ int generic_degrees_test(vertex_t* h_src, handle, (byte_t*)h_result_vertices, result_vertices, &ret_error); TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); - ret_code = cugraph_type_erased_device_array_view_copy_to_host( - handle, (byte_t*)h_result_in_degrees, result_in_degrees, &ret_error); - TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + if (result_in_degrees != NULL) { + ret_code = cugraph_type_erased_device_array_view_copy_to_host( + handle, (byte_t*)h_result_in_degrees, result_in_degrees, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + } - ret_code = cugraph_type_erased_device_array_view_copy_to_host( - handle, (byte_t*)h_result_out_degrees, result_out_degrees, &ret_error); - TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + if (result_out_degrees != NULL) { + ret_code = cugraph_type_erased_device_array_view_copy_to_host( + handle, (byte_t*)h_result_out_degrees, result_out_degrees, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + } - TEST_ASSERT(test_ret_value, num_result_vertices == num_vertices, "results not the same size"); + if (h_vertices != NULL) { + TEST_ASSERT(test_ret_value, num_result_vertices == num_vertices_to_compute, "results not the same size"); + } else { + TEST_ASSERT(test_ret_value, num_result_vertices == num_vertices, "results not the same size"); + } for (size_t i = 0; (i < num_result_vertices) && (test_ret_value == 0); ++i) { - TEST_ASSERT(test_ret_value, h_result_in_degrees[i] == h_in_degrees[h_result_vertices[i]], "in degree did not match"); - TEST_ASSERT(test_ret_value, h_result_out_degrees[i] == h_out_degrees[h_result_vertices[i]], "out degree did not match"); + if (h_in_degrees != NULL) { + TEST_ASSERT(test_ret_value, h_result_in_degrees[i] == h_in_degrees[h_result_vertices[i]], "in degree did not match"); + } + + if (h_out_degrees != NULL) { + TEST_ASSERT(test_ret_value, h_result_out_degrees[i] == h_out_degrees[h_result_vertices[i]], "out degree did not match"); + } } cugraph_degrees_result_free(result); @@ -117,6 +172,10 @@ int test_degrees() h_wgt, num_vertices, num_edges, + NULL, + 0, + TRUE, + TRUE, FALSE, FALSE, h_in_degrees, @@ -140,12 +199,177 @@ int test_degrees_symmetric() h_wgt, num_vertices, num_edges, + NULL, + 0, + TRUE, + TRUE, + FALSE, + TRUE, + h_in_degrees, + h_out_degrees); +} + +int test_in_degrees() +{ + size_t num_edges = 8; + size_t num_vertices = 6; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_in_degrees[] = {1, 2, 0, 2, 1, 2}; + + return generic_degrees_test(h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + NULL, + 0, + TRUE, + FALSE, + FALSE, + TRUE, + h_in_degrees, + NULL); +} + +int test_out_degrees() +{ + size_t num_edges = 8; + size_t num_vertices = 6; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_out_degrees[] = {1, 2, 3, 1, 1, 0}; + + return generic_degrees_test(h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + NULL, + 0, + FALSE, + TRUE, + FALSE, + TRUE, + NULL, + h_out_degrees); +} + +int test_degrees_subset() +{ + size_t num_edges = 8; + size_t num_vertices = 6; + size_t num_vertices_to_compute = 3; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_vertices[] = {2, 3, 5}; + vertex_t h_in_degrees[] = {-1, -1, 0, 2, -1, 2}; + vertex_t h_out_degrees[] = {-1, -1, 3, 1, -1, 0}; + + return generic_degrees_test(h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + h_vertices, + num_vertices_to_compute, + TRUE, + TRUE, + FALSE, + FALSE, + h_in_degrees, + h_out_degrees); +} + +int test_degrees_symmetric_subset() +{ + size_t num_edges = 16; + size_t num_vertices = 6; + size_t num_vertices_to_compute = 3; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4, 1, 3, 4, 0, 1, 3, 5, 5}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5, 0, 1, 1, 2, 2, 2, 3, 4}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f, + 0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_vertices[] = {2, 3, 5}; + vertex_t h_in_degrees[] = {-1, -1, 3, 3, -1, 2}; + vertex_t h_out_degrees[] = {-1, -1, 3, 3, -1, 2}; + + return generic_degrees_test(h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + h_vertices, + num_vertices_to_compute, + TRUE, + TRUE, FALSE, TRUE, h_in_degrees, h_out_degrees); } +int test_in_degrees_subset() +{ + size_t num_edges = 8; + size_t num_vertices = 6; + size_t num_vertices_to_compute = 3; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_vertices[] = {2, 3, 5}; + vertex_t h_in_degrees[] = {-1, -1, 0, 2, -1, 2}; + + return generic_degrees_test(h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + h_vertices, + num_vertices_to_compute, + TRUE, + FALSE, + FALSE, + TRUE, + h_in_degrees, + NULL); +} + +int test_out_degrees_subset() +{ + size_t num_edges = 8; + size_t num_vertices = 6; + size_t num_vertices_to_compute = 3; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_vertices[] = {2, 3, 5}; + vertex_t h_out_degrees[] = {-1, -1, 3, 1, -1, 0}; + + return generic_degrees_test(h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + h_vertices, + num_vertices_to_compute, + FALSE, + TRUE, + FALSE, + TRUE, + NULL, + h_out_degrees); +} + /******************************************************************************/ int main(int argc, char** argv) @@ -153,5 +377,11 @@ int main(int argc, char** argv) int result = 0; result |= RUN_TEST(test_degrees); result |= RUN_TEST(test_degrees_symmetric); + result |= RUN_TEST(test_in_degrees); + result |= RUN_TEST(test_out_degrees); + result |= RUN_TEST(test_degrees_subset); + result |= RUN_TEST(test_degrees_symmetric_subset); + result |= RUN_TEST(test_in_degrees_subset); + result |= RUN_TEST(test_out_degrees_subset); return result; } diff --git a/cpp/tests/c_api/mg_degrees_test.c b/cpp/tests/c_api/mg_degrees_test.c index 1ce8bb6f14..3312dd4f5b 100644 --- a/cpp/tests/c_api/mg_degrees_test.c +++ b/cpp/tests/c_api/mg_degrees_test.c @@ -34,6 +34,10 @@ int generic_degrees_test(const cugraph_resource_handle_t* handle, weight_t* h_wgt, size_t num_vertices, size_t num_edges, + vertex_t* h_vertices, + size_t num_vertices_to_compute, + bool_t in_degrees, + bool_t out_degrees, bool_t store_transposed, bool_t is_symmetric, edge_t* h_in_degrees, @@ -53,10 +57,53 @@ int generic_degrees_test(const cugraph_resource_handle_t* handle, TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "create_test_graph failed."); TEST_ALWAYS_ASSERT(ret_code == CUGRAPH_SUCCESS, cugraph_error_message(ret_error)); - ret_code = cugraph_degrees( - handle, graph, FALSE, &result, &ret_error); - TEST_ASSERT( - test_ret_value, ret_code == CUGRAPH_SUCCESS, "cugraph_extract_degrees failed."); + if (h_vertices == NULL) { + if (in_degrees && out_degrees) { + ret_code = cugraph_degrees( + handle, graph, NULL, FALSE, &result, &ret_error); + } else if (in_degrees) { + ret_code = cugraph_in_degrees( + handle, graph, NULL, FALSE, &result, &ret_error); + } else { + ret_code = cugraph_out_degrees( + handle, graph, NULL, FALSE, &result, &ret_error); + } + + TEST_ASSERT( + test_ret_value, ret_code == CUGRAPH_SUCCESS, "cugraph_extract_degrees failed."); + } else { + cugraph_type_erased_device_array_t* vertices = NULL; + cugraph_type_erased_device_array_view_t* vertices_view = NULL; + + int rank = cugraph_resource_handle_get_rank(handle); + + size_t num_to_allocate = 0; + if (rank == 0) num_to_allocate = num_vertices_to_compute; + + ret_code = + cugraph_type_erased_device_array_create(handle, num_to_allocate, INT32, &vertices, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "seeds create failed."); + + vertices_view = cugraph_type_erased_device_array_view(vertices); + + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + handle, vertices_view, (byte_t*)h_vertices, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "src copy_from_host failed."); + + if (in_degrees && out_degrees) { + ret_code = cugraph_degrees( + handle, graph, vertices_view, FALSE, &result, &ret_error); + } else if (in_degrees) { + ret_code = cugraph_in_degrees( + handle, graph, vertices_view, FALSE, &result, &ret_error); + } else { + ret_code = cugraph_out_degrees( + handle, graph, vertices_view, FALSE, &result, &ret_error); + } + + TEST_ASSERT( + test_ret_value, ret_code == CUGRAPH_SUCCESS, "cugraph_extract_degrees failed."); + } cugraph_type_erased_device_array_view_t* result_vertices; cugraph_type_erased_device_array_view_t* result_in_degrees; @@ -76,17 +123,34 @@ int generic_degrees_test(const cugraph_resource_handle_t* handle, handle, (byte_t*)h_result_vertices, result_vertices, &ret_error); TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); - ret_code = cugraph_type_erased_device_array_view_copy_to_host( - handle, (byte_t*)h_result_in_degrees, result_in_degrees, &ret_error); - TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + if (result_in_degrees != NULL) { + ret_code = cugraph_type_erased_device_array_view_copy_to_host( + handle, (byte_t*)h_result_in_degrees, result_in_degrees, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + } - ret_code = cugraph_type_erased_device_array_view_copy_to_host( - handle, (byte_t*)h_result_out_degrees, result_out_degrees, &ret_error); - TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + if (result_out_degrees != NULL) { + ret_code = cugraph_type_erased_device_array_view_copy_to_host( + handle, (byte_t*)h_result_out_degrees, result_out_degrees, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + } + + if (h_vertices != NULL) { + size_t xxx = cugraph_size_t_allreduce(handle, num_result_vertices); + TEST_ASSERT(test_ret_value, cugraph_size_t_allreduce(handle, num_result_vertices) == num_vertices_to_compute, "results not the same size"); + } else { + size_t xxx = cugraph_size_t_allreduce(handle, num_result_vertices); + TEST_ASSERT(test_ret_value, cugraph_size_t_allreduce(handle, num_result_vertices) == num_vertices, "results not the same size"); + } for (size_t i = 0; (i < num_result_vertices) && (test_ret_value == 0); ++i) { - TEST_ASSERT(test_ret_value, h_result_in_degrees[i] == h_in_degrees[h_result_vertices[i]], "in degree did not match"); - TEST_ASSERT(test_ret_value, h_result_out_degrees[i] == h_out_degrees[h_result_vertices[i]], "out degree did not match"); + if (h_in_degrees != NULL) { + TEST_ASSERT(test_ret_value, h_result_in_degrees[i] == h_in_degrees[h_result_vertices[i]], "in degree did not match"); + } + + if (h_out_degrees != NULL) { + TEST_ASSERT(test_ret_value, h_result_out_degrees[i] == h_out_degrees[h_result_vertices[i]], "out degree did not match"); + } } cugraph_degrees_result_free(result); @@ -113,6 +177,10 @@ int test_degrees(const cugraph_resource_handle_t* handle) h_wgt, num_vertices, num_edges, + NULL, + 0, + TRUE, + TRUE, TRUE, FALSE, h_in_degrees, @@ -138,12 +206,183 @@ int test_degrees_symmetric(const cugraph_resource_handle_t* handle) h_wgt, num_vertices, num_edges, + NULL, + 0, + TRUE, + TRUE, + TRUE, + TRUE, + h_in_degrees, + h_out_degrees); +} + +int test_in_degrees(const cugraph_resource_handle_t *handle) +{ + size_t num_edges = 8; + size_t num_vertices = 6; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_in_degrees[] = {1, 2, 0, 2, 1, 2}; + + return generic_degrees_test(handle, + h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + NULL, + 0, + TRUE, + FALSE, + FALSE, + TRUE, + h_in_degrees, + NULL); +} + +int test_out_degrees(const cugraph_resource_handle_t *handle) +{ + size_t num_edges = 8; + size_t num_vertices = 6; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_out_degrees[] = {1, 2, 3, 1, 1, 0}; + + return generic_degrees_test(handle, + h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + NULL, + 0, + FALSE, + TRUE, + FALSE, + TRUE, + NULL, + h_out_degrees); +} + +int test_degrees_subset(const cugraph_resource_handle_t* handle) +{ + size_t num_edges = 8; + size_t num_vertices = 6; + size_t num_vertices_to_compute = 3; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_vertices[] = {2, 3, 5}; + vertex_t h_in_degrees[] = {-1, -1, 0, 2, -1, 2}; + vertex_t h_out_degrees[] = {-1, -1, 3, 1, -1, 0}; + + return generic_degrees_test(handle, + h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + h_vertices, + num_vertices_to_compute, TRUE, TRUE, + FALSE, + FALSE, h_in_degrees, h_out_degrees); } +int test_degrees_symmetric_subset(const cugraph_resource_handle_t* handle) +{ + size_t num_edges = 16; + size_t num_vertices = 6; + size_t num_vertices_to_compute = 3; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4, 1, 3, 4, 0, 1, 3, 5, 5}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5, 0, 1, 1, 2, 2, 2, 3, 4}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f, + 0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_vertices[] = {2, 3, 5}; + vertex_t h_in_degrees[] = {-1, -1, 3, 3, -1, 2}; + vertex_t h_out_degrees[] = {-1, -1, 3, 3, -1, 2}; + + return generic_degrees_test(handle, + h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + h_vertices, + num_vertices_to_compute, + TRUE, + TRUE, + FALSE, + TRUE, + h_in_degrees, + h_out_degrees); +} + +int test_in_degrees_subset(const cugraph_resource_handle_t* handle) +{ + size_t num_edges = 8; + size_t num_vertices = 6; + size_t num_vertices_to_compute = 3; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_vertices[] = {2, 3, 5}; + vertex_t h_in_degrees[] = {-1, -1, 0, 2, -1, 2}; + + return generic_degrees_test(handle, + h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + h_vertices, + num_vertices_to_compute, + TRUE, + FALSE, + FALSE, + TRUE, + h_in_degrees, + NULL); +} + +int test_out_degrees_subset(const cugraph_resource_handle_t* handle) +{ + size_t num_edges = 8; + size_t num_vertices = 6; + size_t num_vertices_to_compute = 3; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5}; + weight_t h_wgt[] = {0.1f, 2.1f, 1.1f, 5.1f, 3.1f, 4.1f, 7.2f, 3.2f}; + vertex_t h_vertices[] = {2, 3, 5}; + vertex_t h_out_degrees[] = {-1, -1, 3, 1, -1, 0}; + + return generic_degrees_test(handle, + h_src, + h_dst, + h_wgt, + num_vertices, + num_edges, + h_vertices, + num_vertices_to_compute, + FALSE, + TRUE, + FALSE, + TRUE, + NULL, + h_out_degrees); +} + /******************************************************************************/ int main(int argc, char** argv) @@ -154,6 +393,12 @@ int main(int argc, char** argv) int result = 0; result |= RUN_MG_TEST(test_degrees, handle); result |= RUN_MG_TEST(test_degrees_symmetric, handle); + result |= RUN_MG_TEST(test_in_degrees, handle); + result |= RUN_MG_TEST(test_out_degrees, handle); + result |= RUN_MG_TEST(test_degrees_subset, handle); + result |= RUN_MG_TEST(test_degrees_symmetric_subset, handle); + result |= RUN_MG_TEST(test_in_degrees_subset, handle); + result |= RUN_MG_TEST(test_out_degrees_subset, handle); cugraph_free_resource_handle(handle); free_mg_raft_handle(raft_handle); diff --git a/cpp/tests/c_api/test_utils.cpp b/cpp/tests/c_api/test_utils.cpp index e37cc4555d..3013cbb7cc 100644 --- a/cpp/tests/c_api/test_utils.cpp +++ b/cpp/tests/c_api/test_utils.cpp @@ -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. @@ -15,6 +15,9 @@ */ #include "c_test_utils.h" +#include "c_api/resource_handle.hpp" + +#include #include @@ -388,3 +391,12 @@ int create_sg_test_graph(const cugraph_resource_handle_t* handle, return test_ret_value; } + +extern "C" size_t cugraph_size_t_allreduce(const cugraph_resource_handle_t* handle, size_t value) +{ + auto internal_handle = reinterpret_cast(handle); + return cugraph::host_scalar_allreduce(internal_handle->handle_->get_comms(), + value, + raft::comms::op_t::SUM, + internal_handle->handle_->get_stream()); +} diff --git a/python/pylibcugraph/pylibcugraph/_cugraph_c/graph_functions.pxd b/python/pylibcugraph/pylibcugraph/_cugraph_c/graph_functions.pxd index b9fa14f554..6f1ac1f640 100644 --- a/python/pylibcugraph/pylibcugraph/_cugraph_c/graph_functions.pxd +++ b/python/pylibcugraph/pylibcugraph/_cugraph_c/graph_functions.pxd @@ -192,6 +192,7 @@ cdef extern from "cugraph_c/graph_functions.h": cugraph_in_degrees( const cugraph_resource_handle_t* handle, cugraph_graph_t* graph, + const cugraph_type_erased_device_array_view_t* source_vertices, bool_t do_expensive_check, cugraph_degrees_result_t** result, cugraph_error_t** error @@ -201,6 +202,7 @@ cdef extern from "cugraph_c/graph_functions.h": cugraph_out_degrees( const cugraph_resource_handle_t* handle, cugraph_graph_t* graph, + const cugraph_type_erased_device_array_view_t* source_vertices, bool_t do_expensive_check, cugraph_degrees_result_t** result, cugraph_error_t** error @@ -210,6 +212,7 @@ cdef extern from "cugraph_c/graph_functions.h": cugraph_degrees( const cugraph_resource_handle_t* handle, cugraph_graph_t* graph, + const cugraph_type_erased_device_array_view_t* source_vertices, bool_t do_expensive_check, cugraph_degrees_result_t** result, cugraph_error_t** error diff --git a/python/pylibcugraph/pylibcugraph/degrees.pyx b/python/pylibcugraph/pylibcugraph/degrees.pyx index 22309c31f7..1ef138d0af 100644 --- a/python/pylibcugraph/pylibcugraph/degrees.pyx +++ b/python/pylibcugraph/pylibcugraph/degrees.pyx @@ -54,11 +54,9 @@ from pylibcugraph.utils cimport ( ) -#in degrees -#out degrees -#degrees [both] def in_degrees(ResourceHandle resource_handle, _GPUGraph graph, + source_vertices, bool_t do_expensive_check): """ Compute the in degrees for the nodes of the graph. @@ -72,6 +70,9 @@ def in_degrees(ResourceHandle resource_handle, graph : SGGraph or MGGraph The input graph, for either Single or Multi-GPU operations. + source_vertices : cupy array + The nodes for which we will compute degrees. + do_expensive_check : bool_t A flag to run expensive checks for input arguments if True. @@ -94,7 +95,7 @@ def in_degrees(ResourceHandle resource_handle, ... resource_handle, graph_props, srcs, dsts, weight_array=weights, ... store_transposed=True, renumber=False, do_expensive_check=False) >>> (vertices, in_degrees) = pylibcugraph.in_degrees( - resource_handle, G, False) + resource_handle, G, None, False) """ @@ -129,6 +130,7 @@ def in_degrees(ResourceHandle resource_handle, def out_degrees(ResourceHandle resource_handle, _GPUGraph graph, + source_vertices, bool_t do_expensive_check): """ Compute the out degrees for the nodes of the graph. @@ -142,6 +144,9 @@ def out_degrees(ResourceHandle resource_handle, graph : SGGraph or MGGraph The input graph, for either Single or Multi-GPU operations. + source_vertices : cupy array + The nodes for which we will compute degrees. + do_expensive_check : bool_t A flag to run expensive checks for input arguments if True. @@ -164,7 +169,7 @@ def out_degrees(ResourceHandle resource_handle, ... resource_handle, graph_props, srcs, dsts, weight_array=weights, ... store_transposed=True, renumber=False, do_expensive_check=False) >>> (vertices, out_degrees) = pylibcugraph.out_degrees( - resource_handle, G, False) + resource_handle, G, None, False) """ @@ -200,6 +205,7 @@ def out_degrees(ResourceHandle resource_handle, def degrees(ResourceHandle resource_handle, _GPUGraph graph, + source_vertices, bool_t do_expensive_check): """ Compute the degrees for the nodes of the graph. @@ -213,6 +219,9 @@ def degrees(ResourceHandle resource_handle, graph : SGGraph or MGGraph The input graph, for either Single or Multi-GPU operations. + source_vertices : cupy array + The nodes for which we will compute degrees. + do_expensive_check : bool_t A flag to run expensive checks for input arguments if True. @@ -236,7 +245,7 @@ def degrees(ResourceHandle resource_handle, ... resource_handle, graph_props, srcs, dsts, weight_array=weights, ... store_transposed=True, renumber=False, do_expensive_check=False) >>> (vertices, in_degrees, out_degrees) = pylibcugraph.degrees( - resource_handle, G, False) + resource_handle, G, None, False) """