diff --git a/cpp/include/cugraph_c/graph_functions.h b/cpp/include/cugraph_c/graph_functions.h index dc62a096323..655324df284 100644 --- a/cpp/include/cugraph_c/graph_functions.h +++ b/cpp/include/cugraph_c/graph_functions.h @@ -87,6 +87,8 @@ void cugraph_vertex_pairs_free(cugraph_vertex_pairs_t* vertex_pairs); * @param [in] start_vertices Optional type erased array of starting vertices * If NULL use all, if specified compute two-hop * neighbors for these starting vertices + * @param [in] do_expensive_check + * A flag to run expensive checks for input arguments (if set to true) * @param [out] result Opaque pointer to resulting vertex pairs * @param [out] error Pointer to an error object storing details of any error. Will * be populated if error code is not CUGRAPH_SUCCESS @@ -94,8 +96,9 @@ void cugraph_vertex_pairs_free(cugraph_vertex_pairs_t* vertex_pairs); */ cugraph_error_code_t cugraph_two_hop_neighbors( const cugraph_resource_handle_t* handle, - const cugraph_graph_t* graph, + cugraph_graph_t* graph, const cugraph_type_erased_device_array_view_t* start_vertices, + bool_t do_expensive_check, cugraph_vertex_pairs_t** result, cugraph_error_t** error); diff --git a/cpp/src/c_api/graph_functions.cpp b/cpp/src/c_api/graph_functions.cpp index c7c5b9698ad..3b385b84371 100644 --- a/cpp/src/c_api/graph_functions.cpp +++ b/cpp/src/c_api/graph_functions.cpp @@ -19,9 +19,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -80,15 +82,23 @@ struct create_vertex_pairs_functor : public cugraph::c_api::abstract_functor { }; struct two_hop_neighbors_functor : public cugraph::c_api::abstract_functor { - raft::handle_t const& handle_; - cugraph::c_api::cugraph_graph_t const* graph_; + raft::handle_t const& handle_{}; + cugraph::c_api::cugraph_graph_t* graph_{nullptr}; + cugraph::c_api::cugraph_type_erased_device_array_view_t const* start_vertices_{nullptr}; cugraph::c_api::cugraph_vertex_pairs_t* result_{}; + bool do_expensive_check_{false}; two_hop_neighbors_functor(::cugraph_resource_handle_t const* handle, - ::cugraph_graph_t const* graph) + ::cugraph_graph_t* graph, + ::cugraph_type_erased_device_array_view_t const* start_vertices, + bool do_expensive_check) : abstract_functor(), handle_(*reinterpret_cast(handle)->handle_), - graph_(reinterpret_cast(graph)) + graph_(reinterpret_cast(graph)), + start_vertices_( + reinterpret_cast( + start_vertices)), + do_expensive_check_(do_expensive_check) { } @@ -103,12 +113,91 @@ struct two_hop_neighbors_functor : public cugraph::c_api::abstract_functor { if constexpr (!cugraph::is_candidate::value) { unsupported(); } else { - auto graph = reinterpret_cast< - cugraph::graph_t*>(graph_->graph_); + // k_hop_nbrs 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 number_map = reinterpret_cast*>(graph_->number_map_); + + rmm::device_uvector start_vertices(0, handle_.get_stream()); + + if (start_vertices_ != nullptr) { + start_vertices.resize(start_vertices_->size_, handle_.get_stream()); + raft::copy(start_vertices.data(), + start_vertices_->as_type(), + start_vertices_->size_, + handle_.get_stream()); + + cugraph::renumber_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_); + + if constexpr (multi_gpu) { + start_vertices = + cugraph::detail::shuffle_ext_vertices_by_gpu_id(handle_, std::move(start_vertices)); + } + } else { + start_vertices.resize(graph_view.local_vertex_partition_range_size(), handle_.get_stream()); + cugraph::detail::sequence_fill(handle_.get_stream(), + start_vertices.data(), + start_vertices.size(), + graph_view.local_vertex_partition_range_first()); + } + + auto [offsets, dst] = cugraph::k_hop_nbrs( + handle_, + graph_view, + raft::device_span{start_vertices.data(), start_vertices.size()}, + size_t{2}, + do_expensive_check_); + + auto src = cugraph::c_api::expand_sparse_offsets( + raft::device_span{offsets.data(), offsets.size()}, + vertex_t{0}, + handle_.get_stream()); + + // convert ids back to srcs: src[i] = start_vertices[src[i]] + cugraph::unrenumber_local_int_vertices(handle_, + src.data(), + src.size(), + start_vertices.data(), + vertex_t{0}, + graph_view.local_vertex_partition_range_size(), + do_expensive_check_); - CUGRAPH_FAIL("Not implemented"); + cugraph::unrenumber_int_vertices( + handle_, + src.data(), + src.size(), + number_map->data(), + graph_view.vertex_partition_range_lasts(), + do_expensive_check_); + + cugraph::unrenumber_int_vertices( + handle_, + dst.data(), + dst.size(), + number_map->data(), + graph_view.vertex_partition_range_lasts(), + do_expensive_check_); + + result_ = new cugraph::c_api::cugraph_vertex_pairs_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_->vertex_type_)}; } } }; @@ -170,12 +259,13 @@ extern "C" void cugraph_vertex_pairs_free(cugraph_vertex_pairs_t* vertex_pairs) extern "C" cugraph_error_code_t cugraph_two_hop_neighbors( const cugraph_resource_handle_t* handle, - const cugraph_graph_t* graph, + cugraph_graph_t* graph, const cugraph_type_erased_device_array_view_t* start_vertices, + bool_t do_expensive_check, cugraph_vertex_pairs_t** result, cugraph_error_t** error) { - two_hop_neighbors_functor functor(handle, graph); + two_hop_neighbors_functor functor(handle, graph, start_vertices, do_expensive_check); return cugraph::c_api::run_algorithm(graph, functor, result, error); } diff --git a/cpp/src/c_api/graph_functions.hpp b/cpp/src/c_api/graph_functions.hpp index 2a46a1439de..5b9978ce4f0 100644 --- a/cpp/src/c_api/graph_functions.hpp +++ b/cpp/src/c_api/graph_functions.hpp @@ -16,6 +16,8 @@ #pragma once +#include + namespace cugraph { namespace c_api { diff --git a/cpp/src/c_api/graph_helper.cu b/cpp/src/c_api/graph_helper.cu index 4856e561cfd..914344f8722 100644 --- a/cpp/src/c_api/graph_helper.cu +++ b/cpp/src/c_api/graph_helper.cu @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#pragma once #include @@ -43,5 +42,13 @@ template rmm::device_uvector expand_sparse_offsets( int64_t base_vertex_id, rmm::cuda_stream_view const& stream); +template rmm::device_uvector expand_sparse_offsets(raft::device_span offsets, + int32_t base_vertex_id, + rmm::cuda_stream_view const& stream); + +template rmm::device_uvector expand_sparse_offsets(raft::device_span offsets, + int64_t base_vertex_id, + rmm::cuda_stream_view const& stream); + } // namespace c_api } // namespace cugraph diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 4f5cb7c25a1..1f4b56e36a3 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -591,6 +591,7 @@ if(BUILD_CUGRAPH_MG_TESTS) ConfigureCTestMG(MG_CAPI_SIMILARITY_TEST c_api/mg_similarity_test.c c_api/mg_test_utils.cpp) ConfigureCTestMG(MG_CAPI_K_CORE_TEST c_api/mg_k_core_test.c c_api/mg_test_utils.cpp) ConfigureCTestMG(MG_CAPI_INDUCED_SUBGRAPH_TEST c_api/mg_induced_subgraph_test.c c_api/mg_test_utils.cpp) + ConfigureCTestMG(MG_CAPI_TWO_HOP_NEIGHBORS_TEST c_api/mg_two_hop_neighbors_test.c c_api/mg_test_utils.cpp) endif() ################################################################################################### @@ -645,6 +646,7 @@ ConfigureCTest(CAPI_CORE_NUMBER_TEST c_api/core_number_test.c) ConfigureCTest(CAPI_SIMILARITY_TEST c_api/similarity_test.c) ConfigureCTest(CAPI_K_CORE_TEST c_api/k_core_test.c) ConfigureCTest(CAPI_INDUCED_SUBGRAPH_TEST c_api/induced_subgraph_test.c) +ConfigureCTest(CAPI_TWO_HOP_NEIGHBORS_TEST c_api/two_hop_neighbors_test.c) ################################################################################################### ### enable testing ################################################################################ diff --git a/cpp/tests/c_api/mg_two_hop_neighbors_test.c b/cpp/tests/c_api/mg_two_hop_neighbors_test.c new file mode 100644 index 00000000000..a04586aba12 --- /dev/null +++ b/cpp/tests/c_api/mg_two_hop_neighbors_test.c @@ -0,0 +1,218 @@ +/* + * 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 "mg_test_utils.h" /* RUN_TEST */ + +#include +#include +#include + +#include + +typedef int32_t vertex_t; +typedef int32_t edge_t; +typedef float weight_t; + +int generic_two_hop_nbr_test(const cugraph_resource_handle_t* resource_handle, + vertex_t* h_src, + vertex_t* h_dst, + weight_t* h_wgt, + vertex_t* h_sources, + vertex_t* h_result_v1, + vertex_t* h_result_v2, + size_t num_vertices, + size_t num_edges, + size_t num_sources, + size_t num_result_pairs, + bool_t store_transposed) +{ + int test_ret_value = 0; + + cugraph_error_code_t ret_code = CUGRAPH_SUCCESS; + cugraph_error_t* ret_error; + + cugraph_graph_t* graph = NULL; + cugraph_type_erased_device_array_t* start_vertices = NULL; + cugraph_type_erased_device_array_view_t* start_vertices_view = NULL; + cugraph_vertex_pairs_t* result = NULL; + + int rank = cugraph_resource_handle_get_rank(resource_handle); + + ret_code = create_mg_test_graph( + resource_handle, h_src, h_dst, h_wgt, num_edges, store_transposed, TRUE, &graph, &ret_error); + + 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)); + + if (num_sources > 0) { + if (rank == 0) { + ret_code = cugraph_type_erased_device_array_create( + resource_handle, num_sources, INT32, &start_vertices, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "p_sources create failed."); + + start_vertices_view = cugraph_type_erased_device_array_view(start_vertices); + + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + resource_handle, start_vertices_view, (byte_t*)h_sources, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "src copy_from_host failed."); + } else { + start_vertices_view = cugraph_type_erased_device_array_view_create(NULL, 0, INT32); + } + } + + ret_code = cugraph_two_hop_neighbors( + resource_handle, graph, start_vertices_view, FALSE, &result, &ret_error); + + cugraph_type_erased_device_array_view_t* v1; + cugraph_type_erased_device_array_view_t* v2; + + v1 = cugraph_vertex_pairs_get_first(result); + v2 = cugraph_vertex_pairs_get_second(result); + + size_t number_of_pairs = cugraph_type_erased_device_array_view_size(v1); + + vertex_t h_v1[number_of_pairs]; + vertex_t h_v2[number_of_pairs]; + + ret_code = cugraph_type_erased_device_array_view_copy_to_host( + resource_handle, (byte_t*)h_v1, v1, &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( + resource_handle, (byte_t*)h_v2, v2, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + + bool_t M[num_vertices][num_vertices]; + for (int i = 0; i < num_vertices; ++i) + for (int j = 0; j < num_vertices; ++j) + M[i][j] = FALSE; + + for (int i = 0; i < num_result_pairs; ++i) + M[h_result_v1[i]][h_result_v2[i]] = TRUE; + + for (int i = 0; (i < number_of_pairs) && (test_ret_value == 0); ++i) { + TEST_ASSERT(test_ret_value, M[h_v1[i]][h_v2[i]], "result not found"); + } + + cugraph_vertex_pairs_free(result); + cugraph_type_erased_device_array_view_free(start_vertices_view); + cugraph_type_erased_device_array_free(start_vertices); + cugraph_mg_graph_free(graph); + cugraph_error_free(ret_error); + + return test_ret_value; +} + +int test_two_hop_nbr_all(const cugraph_resource_handle_t* handle) +{ + size_t num_edges = 22; + size_t num_vertices = 7; + size_t num_sources = 0; + size_t num_result_pairs = 43; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4, 1, 3, 4, 0, 1, 3, 5, 5, 3, 1, 4, 5, 5, 6}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5, 0, 1, 1, 2, 2, 2, 3, 4, 4, 5, 3, 1, 6, 5}; + weight_t h_wgt[] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + + vertex_t h_result_v1[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6}; + vertex_t h_result_v2[] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 0, 1, 2, + 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 1, 3, 4, 6}; + + return generic_two_hop_nbr_test(handle, + h_src, + h_dst, + h_wgt, + NULL, + h_result_v1, + h_result_v2, + num_vertices, + num_edges, + num_sources, + num_result_pairs, + FALSE); +} + +int test_two_hop_nbr_one(const cugraph_resource_handle_t* handle) +{ + size_t num_edges = 22; + size_t num_vertices = 7; + size_t num_sources = 1; + size_t num_result_pairs = 6; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4, 1, 3, 4, 0, 1, 3, 5, 5, 3, 1, 4, 5, 5, 6}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5, 0, 1, 1, 2, 2, 2, 3, 4, 4, 5, 3, 1, 6, 5}; + weight_t h_wgt[] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + + vertex_t h_sources[] = {0}; + + vertex_t h_result_v1[] = {0, 0, 0, 0, 0, 0}; + vertex_t h_result_v2[] = {0, 1, 2, 3, 4, 5}; + + return generic_two_hop_nbr_test(handle, + h_src, + h_dst, + h_wgt, + h_sources, + h_result_v1, + h_result_v2, + num_vertices, + num_edges, + num_sources, + num_result_pairs, + FALSE); +} + +/******************************************************************************/ + +int main(int argc, char** argv) +{ + // Set up MPI: + int comm_rank; + int comm_size; + int num_gpus_per_node; + cudaError_t status; + int mpi_status; + int result = 0; + cugraph_resource_handle_t* handle = NULL; + cugraph_error_t* ret_error; + cugraph_error_code_t ret_code = CUGRAPH_SUCCESS; + int prows = 1; + + C_MPI_TRY(MPI_Init(&argc, &argv)); + C_MPI_TRY(MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank)); + C_MPI_TRY(MPI_Comm_size(MPI_COMM_WORLD, &comm_size)); + C_CUDA_TRY(cudaGetDeviceCount(&num_gpus_per_node)); + C_CUDA_TRY(cudaSetDevice(comm_rank % num_gpus_per_node)); + + void* raft_handle = create_raft_handle(prows); + handle = cugraph_create_resource_handle(raft_handle); + + if (result == 0) { + result |= RUN_MG_TEST(test_two_hop_nbr_all, handle); + result |= RUN_MG_TEST(test_two_hop_nbr_one, handle); + + cugraph_free_resource_handle(handle); + } + + free_raft_handle(raft_handle); + + C_MPI_TRY(MPI_Finalize()); + + return result; +} diff --git a/cpp/tests/c_api/two_hop_neighbors_test.c b/cpp/tests/c_api/two_hop_neighbors_test.c new file mode 100644 index 00000000000..d47280276c5 --- /dev/null +++ b/cpp/tests/c_api/two_hop_neighbors_test.c @@ -0,0 +1,195 @@ +/* + * 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 "c_test_utils.h" /* RUN_TEST */ + +#include +#include +#include + +#include + +typedef int32_t vertex_t; +typedef int32_t edge_t; +typedef float weight_t; + +int generic_two_hop_nbr_test(vertex_t* h_src, + vertex_t* h_dst, + weight_t* h_wgt, + vertex_t* h_sources, + vertex_t* h_result_v1, + vertex_t* h_result_v2, + size_t num_vertices, + size_t num_edges, + size_t num_sources, + size_t num_result_pairs, + bool_t store_transposed) +{ + int test_ret_value = 0; + + cugraph_error_code_t ret_code = CUGRAPH_SUCCESS; + cugraph_error_t* ret_error; + + cugraph_resource_handle_t* resource_handle = NULL; + cugraph_graph_t* graph = NULL; + cugraph_type_erased_device_array_t* start_vertices = NULL; + cugraph_type_erased_device_array_view_t* start_vertices_view = NULL; + cugraph_vertex_pairs_t* result = NULL; + + resource_handle = cugraph_create_resource_handle(NULL); + TEST_ASSERT(test_ret_value, resource_handle != NULL, "resource handle creation failed."); + + ret_code = create_test_graph(resource_handle, + h_src, + h_dst, + h_wgt, + num_edges, + store_transposed, + FALSE, + TRUE, + &graph, + &ret_error); + + 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)); + + if (num_sources > 0) { + ret_code = cugraph_type_erased_device_array_create( + resource_handle, num_sources, INT32, &start_vertices, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "p_sources create failed."); + + start_vertices_view = cugraph_type_erased_device_array_view(start_vertices); + + ret_code = cugraph_type_erased_device_array_view_copy_from_host( + resource_handle, start_vertices_view, (byte_t*)h_sources, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "src copy_from_host failed."); + } + + ret_code = cugraph_two_hop_neighbors( + resource_handle, graph, start_vertices_view, FALSE, &result, &ret_error); + + cugraph_type_erased_device_array_view_t* v1; + cugraph_type_erased_device_array_view_t* v2; + + v1 = cugraph_vertex_pairs_get_first(result); + v2 = cugraph_vertex_pairs_get_second(result); + + size_t number_of_pairs = cugraph_type_erased_device_array_view_size(v1); + + vertex_t h_v1[number_of_pairs]; + vertex_t h_v2[number_of_pairs]; + + ret_code = cugraph_type_erased_device_array_view_copy_to_host( + resource_handle, (byte_t*)h_v1, v1, &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( + resource_handle, (byte_t*)h_v2, v2, &ret_error); + TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "copy_to_host failed."); + + bool_t M[num_vertices][num_vertices]; + for (int i = 0; i < num_vertices; ++i) + for (int j = 0; j < num_vertices; ++j) + M[i][j] = FALSE; + + for (int i = 0; i < num_result_pairs; ++i) + M[h_result_v1[i]][h_result_v2[i]] = TRUE; + + TEST_ASSERT(test_ret_value, number_of_pairs == num_result_pairs, "results are different sizes"); + + for (int i = 0; (i < number_of_pairs) && (test_ret_value == 0); ++i) { + TEST_ASSERT(test_ret_value, M[h_v1[i]][h_v2[i]], "result not found"); + } + + cugraph_vertex_pairs_free(result); + cugraph_type_erased_device_array_view_free(start_vertices_view); + cugraph_type_erased_device_array_free(start_vertices); + cugraph_sg_graph_free(graph); + cugraph_free_resource_handle(resource_handle); + cugraph_error_free(ret_error); + + return test_ret_value; +} + +int test_two_hop_nbr_all() +{ + size_t num_edges = 22; + size_t num_vertices = 7; + size_t num_sources = 0; + size_t num_result_pairs = 43; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4, 1, 3, 4, 0, 1, 3, 5, 5, 3, 1, 4, 5, 5, 6}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5, 0, 1, 1, 2, 2, 2, 3, 4, 4, 5, 3, 1, 6, 5}; + weight_t h_wgt[] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + + vertex_t h_result_v1[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6}; + vertex_t h_result_v2[] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 0, 1, 2, + 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 1, 3, 4, 6}; + + return generic_two_hop_nbr_test(h_src, + h_dst, + h_wgt, + NULL, + h_result_v1, + h_result_v2, + num_vertices, + num_edges, + num_sources, + num_result_pairs, + FALSE); +} + +int test_two_hop_nbr_one() +{ + size_t num_edges = 22; + size_t num_vertices = 7; + size_t num_sources = 1; + size_t num_result_pairs = 6; + + vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4, 1, 3, 4, 0, 1, 3, 5, 5, 3, 1, 4, 5, 5, 6}; + vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5, 0, 1, 1, 2, 2, 2, 3, 4, 4, 5, 3, 1, 6, 5}; + weight_t h_wgt[] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + + vertex_t h_sources[] = {0}; + + vertex_t h_result_v1[] = {0, 0, 0, 0, 0, 0}; + vertex_t h_result_v2[] = {0, 1, 2, 3, 4, 5}; + + return generic_two_hop_nbr_test(h_src, + h_dst, + h_wgt, + h_sources, + h_result_v1, + h_result_v2, + num_vertices, + num_edges, + num_sources, + num_result_pairs, + FALSE); +} + +/******************************************************************************/ + +int main(int argc, char** argv) +{ + int result = 0; + result |= RUN_TEST(test_two_hop_nbr_all); + result |= RUN_TEST(test_two_hop_nbr_one); + return result; +}