Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose graph_view method to count multi edges through C API and PLC #4426

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions cpp/include/cugraph_c/graph_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,26 @@ cugraph_error_code_t cugraph_allgather(const cugraph_resource_handle_t* handle,
cugraph_induced_subgraph_result_t** result,
cugraph_error_t** error);

/**
* @brief Count multi_edges
*
* Count the number of multi-edges in the graph
*
* @param [in] handle Handle for accessing resources.
* @param [in] graph Pointer to graph
* @param [in] do_expensive_check A flag to run expensive checks for input arguments (if set to
* true)
* @param [out] result Where to store the count of multi-edges
* @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_count_multi_edges(const cugraph_resource_handle_t* handle,
cugraph_graph_t* graph,
bool_t do_expensive_check,
size_t* result,
cugraph_error_t** error);

/**
* @brief Opaque degree result type
*/
Expand Down
49 changes: 49 additions & 0 deletions cpp/src/c_api/graph_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,44 @@ struct two_hop_neighbors_functor : public cugraph::c_api::abstract_functor {
}
};

struct count_multi_edges_functor : public cugraph::c_api::abstract_functor {
raft::handle_t const& handle_{};
cugraph::c_api::cugraph_graph_t* graph_{nullptr};
size_t result_{};
bool do_expensive_check_{false};

count_multi_edges_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 {
auto graph =
reinterpret_cast<cugraph::graph_t<vertex_t, edge_t, store_transposed, multi_gpu>*>(
graph_->graph_);

auto graph_view = graph->view();

result_ = static_cast<size_t>(graph_view.count_multi_edges(handle_));
}
}
};

} // namespace

extern "C" cugraph_error_code_t cugraph_create_vertex_pairs(
Expand Down Expand Up @@ -281,3 +319,14 @@ extern "C" cugraph_error_code_t cugraph_two_hop_neighbors(

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

extern "C" cugraph_error_code_t cugraph_count_multi_edges(const cugraph_resource_handle_t* handle,
cugraph_graph_t* graph,
bool_t do_expensive_check,
size_t* result,
cugraph_error_t** error)
{
count_multi_edges_functor functor(handle, graph, do_expensive_check);

return cugraph::c_api::run_algorithm(graph, functor, result, error);
}
2 changes: 2 additions & 0 deletions cpp/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,7 @@ if(BUILD_CUGRAPH_MG_TESTS)
ConfigureCTestMG(MG_CAPI_K_CORE_TEST c_api/mg_k_core_test.c)
ConfigureCTestMG(MG_CAPI_INDUCED_SUBGRAPH_TEST c_api/mg_induced_subgraph_test.c)
ConfigureCTestMG(MG_CAPI_DEGREES c_api/mg_degrees_test.c)
ConfigureCTestMG(MG_CAPI_COUNT_MULTI_EDGES c_api/mg_count_multi_edges_test.c)
ConfigureCTestMG(MG_CAPI_EGONET_TEST c_api/mg_egonet_test.c)
ConfigureCTestMG(MG_CAPI_TWO_HOP_NEIGHBORS_TEST c_api/mg_two_hop_neighbors_test.c)

Expand Down Expand Up @@ -777,6 +778,7 @@ 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_DEGREES c_api/degrees_test.c)
ConfigureCTest(CAPI_COUNT_MULTI_EDGES c_api/count_multi_edges_test.c)
ConfigureCTest(CAPI_EGONET_TEST c_api/egonet_test.c)
ConfigureCTest(CAPI_TWO_HOP_NEIGHBORS_TEST c_api/two_hop_neighbors_test.c)
ConfigureCTest(CAPI_K_TRUSS_TEST c_api/k_truss_test.c)
Expand Down
114 changes: 114 additions & 0 deletions cpp/tests/c_api/count_multi_edges_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright (c) 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_test_utils.h" /* RUN_TEST */

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

#include <stdio.h>

typedef int32_t vertex_t;
typedef int32_t edge_t;
typedef float weight_t;

data_type_id_t vertex_tid = INT32;
data_type_id_t edge_tid = INT32;
data_type_id_t weight_tid = FLOAT32;
data_type_id_t edge_id_tid = INT32;
data_type_id_t edge_type_tid = INT32;

/*
* Create graph and count multi-edges
*/
int generic_count_multi_edges_test(vertex_t* h_src,
vertex_t* h_dst,
weight_t* h_wgt,
size_t num_vertices,
size_t num_edges,
bool_t store_transposed,
bool_t is_symmetric,
bool_t is_multigraph,
size_t multi_edges_count)
{
int test_ret_value = 0;

cugraph_error_code_t ret_code = CUGRAPH_SUCCESS;
cugraph_error_t* ret_error;

cugraph_resource_handle_t* handle = NULL;
cugraph_graph_t* graph = NULL;
size_t result = 0;

handle = cugraph_create_resource_handle(NULL);
TEST_ASSERT(test_ret_value, handle != NULL, "resource handle creation failed.");

ret_code = create_sg_test_graph(handle,
vertex_tid,
edge_tid,
h_src,
h_dst,
weight_tid,
h_wgt,
edge_type_tid,
NULL,
edge_id_tid,
NULL,
num_edges,
store_transposed,
FALSE,
is_symmetric,
is_multigraph,
&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));

ret_code = cugraph_count_multi_edges(handle, graph, FALSE, &result, &ret_error);

TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "cugraph_count_multi_edges failed.");

TEST_ASSERT(test_ret_value, result == multi_edges_count, "multi-edge count did not match");

cugraph_graph_free(graph);
cugraph_error_free(ret_error);

return test_ret_value;
}

int test_multi_edges_count()
{
size_t num_edges = 14;
size_t num_vertices = 6;

vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4, 0, 1, 1, 3, 0, 1};
vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5, 1, 3, 0, 1, 1, 0};
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};
size_t multi_edge_count = 4;

return generic_count_multi_edges_test(
h_src, h_dst, h_wgt, num_vertices, num_edges, TRUE, TRUE, TRUE, multi_edge_count);
}

/******************************************************************************/

int main(int argc, char** argv)
{
int result = 0;
result |= RUN_TEST(test_multi_edges_count);
return result;
}
118 changes: 118 additions & 0 deletions cpp/tests/c_api/mg_count_multi_edges_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright (c) 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 "mg_test_utils.h" /* RUN_TEST */

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

#include <stdio.h>

typedef int32_t vertex_t;
typedef int32_t edge_t;
typedef float weight_t;

data_type_id_t vertex_tid = INT32;
data_type_id_t edge_tid = INT32;
data_type_id_t weight_tid = FLOAT32;
data_type_id_t edge_id_tid = INT32;
data_type_id_t edge_type_tid = INT32;

/*
* Create graph and count multi-edges
*/
int generic_count_multi_edges_test(const cugraph_resource_handle_t* handle,
vertex_t* h_src,
vertex_t* h_dst,
weight_t* h_wgt,
size_t num_vertices,
size_t num_edges,
bool_t store_transposed,
bool_t is_symmetric,
bool_t is_multigraph,
size_t multi_edges_count)
{
int test_ret_value = 0;

cugraph_error_code_t ret_code = CUGRAPH_SUCCESS;
cugraph_error_t* ret_error;

cugraph_graph_t* graph = NULL;
size_t result = 0;

ret_code = create_mg_test_graph_new(handle,
vertex_tid,
edge_tid,
h_src,
h_dst,
weight_tid,
h_wgt,
edge_type_tid,
NULL,
edge_id_tid,
NULL,
num_edges,
store_transposed,
FALSE,
is_symmetric,
is_multigraph,
&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));

ret_code = cugraph_count_multi_edges(handle, graph, FALSE, &result, &ret_error);

TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "cugraph_count_multi_edges failed.");

TEST_ASSERT(test_ret_value, result == multi_edges_count, "multi-edge count did not match");

cugraph_graph_free(graph);
cugraph_error_free(ret_error);

return test_ret_value;
}

int test_multi_edges_count(const cugraph_resource_handle_t* handle)
{
size_t num_edges = 14;
size_t num_vertices = 6;

vertex_t h_src[] = {0, 1, 1, 2, 2, 2, 3, 4, 0, 1, 1, 3, 0, 1};
vertex_t h_dst[] = {1, 3, 4, 0, 1, 3, 5, 5, 1, 3, 0, 1, 1, 0};
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};
size_t multi_edge_count = 4;

return generic_count_multi_edges_test(
handle, h_src, h_dst, h_wgt, num_vertices, num_edges, TRUE, TRUE, TRUE, multi_edge_count);
}

/******************************************************************************/

int main(int argc, char** argv)
{
void* raft_handle = create_mg_raft_handle(argc, argv);
cugraph_resource_handle_t* handle = cugraph_create_resource_handle(raft_handle);

int result = 0;
result |= RUN_MG_TEST(test_multi_edges_count, handle);

cugraph_free_resource_handle(handle);
free_mg_raft_handle(raft_handle);

return result;
}
11 changes: 11 additions & 0 deletions python/pylibcugraph/pylibcugraph/_cugraph_c/graph_functions.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,17 @@ cdef extern from "cugraph_c/graph_functions.h":
cugraph_error_t** error
)

###########################################################################
# count multi-edges
cdef cugraph_error_code_t \
cugraph_count_multi_edges(
const cugraph_resource_handle_t *handle,
cugraph_graph_t* graph,
bool_t do_expenive_check,
size_t *result,
cugraph_error_t** error
)

###########################################################################
# degrees
ctypedef struct cugraph_degrees_result_t:
Expand Down
Loading
Loading