Skip to content

Commit

Permalink
Merge pull request #3901 from rapidsai/branch-23.10
Browse files Browse the repository at this point in the history
Forward-merge branch-23.10 to branch-23.12
  • Loading branch information
GPUtester authored Sep 29, 2023
2 parents b42d9f8 + eed1223 commit 143324d
Show file tree
Hide file tree
Showing 17 changed files with 759 additions and 167 deletions.
1 change: 1 addition & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ add_library(cugraph_c
src/c_api/labeling_result.cpp
src/c_api/weakly_connected_components.cpp
src/c_api/strongly_connected_components.cpp
src/c_api/legacy_k_truss.cpp
)
add_library(cugraph::cugraph_c ALIAS cugraph_c)

Expand Down
43 changes: 24 additions & 19 deletions cpp/include/cugraph/algorithms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,34 +430,39 @@ void connected_components(legacy::GraphCSRView<VT, ET, WT> const& graph,
VT* labels);

/**
* @brief Compute k truss for a graph
* @brief Compute k truss for a graph ** temporary
*
* K Truss is the maximal subgraph of a graph which contains at least three
* vertices where every edge is incident to at least k-2 triangles.
*
* Note that current implementation does not support a weighted graph.
* This version is a temporary solution to clean up python integration through the C API.
*
* @throws cugraph::logic_error with a custom message when an error
* occurs.
* This version is only supported SG.
*
* @tparam VT Type of vertex identifiers. Supported value : int (signed,
* 32-bit)
* @tparam ET Type of edge identifiers. Supported value : int (signed,
* 32-bit)
* @tparam WT Type of edge weights. Supported values : float or double.
* @throws cugraph::logic_error with a custom message when an error
* occurs.
*
* @param[in] graph cuGraph graph descriptor, should contain the connectivity
* information as a COO
* @param[in] k The order of the truss
* @param[in] mr Memory resource used to allocate the returned graph
* @return Unique pointer to K Truss subgraph in COO format
* @tparam vertex_t Type of vertex identifiers. Supported value : int (signed, 32-bit)
* @tparam weight_t Type of edge weights. Supported values : float or double.
*
* @param[in] handle Library handle (RAFT).
* @param[in] src Source vertices from COO
* @param[in] dst Destination vertices from COO
* @param[in] wgt Optional edge weights from COO
* @param[in] k The order of the truss
* @return Tuple containing extracted src, dst and optional weights for the
* subgraph
*/
template <typename VT, typename ET, typename WT>
std::unique_ptr<legacy::GraphCOO<VT, ET, WT>> k_truss_subgraph(
legacy::GraphCOOView<VT, ET, WT> const& graph,
int k,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource());
template <typename vertex_t, typename weight_t>
std::tuple<rmm::device_uvector<vertex_t>,
rmm::device_uvector<vertex_t>,
std::optional<rmm::device_uvector<weight_t>>>
k_truss_subgraph(raft::handle_t const& handle,
raft::device_span<vertex_t> src,
raft::device_span<vertex_t> dst,
std::optional<raft::device_span<weight_t>> wgt,
size_t number_of_vertices,
int k);

// FIXME: Internally distances is of int (signed 32-bit) data type, but current
// template uses data from VT, ET, WT from the legacy::GraphCSR View even if weights
Expand Down
22 changes: 21 additions & 1 deletion cpp/include/cugraph/utilities/graph_traits.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION.
* Copyright (c) 2021-2023, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -47,6 +47,16 @@ struct is_vertex_edge_combo {
(sizeof(vertex_t) <= sizeof(edge_t));
};

// meta-function that constrains
// vertex_t and edge_t template param candidates to only int32_t:
//
template <typename vertex_t, typename edge_t>
struct is_vertex_edge_combo_legacy {
static constexpr bool value = is_one_of<vertex_t, int32_t>::value &&
is_one_of<edge_t, int32_t>::value &&
(sizeof(vertex_t) <= sizeof(edge_t));
};

// meta-function that constrains
// all 3 template param candidates:
//
Expand All @@ -56,4 +66,14 @@ struct is_candidate {
is_vertex_edge_combo<vertex_t, edge_t>::value && is_one_of<weight_t, float, double>::value;
};

// meta-function that constrains
// all 3 template param candidates where vertex_t and edge_t
// are restricted to int32_t:
//
template <typename vertex_t, typename edge_t, typename weight_t>
struct is_candidate_legacy {
static constexpr bool value = is_vertex_edge_combo_legacy<vertex_t, edge_t>::value &&
is_one_of<weight_t, float, double>::value;
};

} // namespace cugraph
21 changes: 21 additions & 0 deletions cpp/include/cugraph_c/community_algorithms.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,27 @@ cugraph_error_code_t cugraph_extract_ego(
cugraph_induced_subgraph_result_t** result,
cugraph_error_t** error);

/**
* @brief Extract k truss for a graph
*
* @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] k The order of the truss
* @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_k_truss_subgraph(const cugraph_resource_handle_t* handle,
cugraph_graph_t* graph,
size_t k,
bool_t do_expensive_check,
cugraph_induced_subgraph_result_t** result,
cugraph_error_t** error);

/**
* @brief Opaque clustering output
*/
Expand Down
150 changes: 150 additions & 0 deletions cpp/src/c_api/legacy_k_truss.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright (c) 2023, 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 k_truss_functor : public cugraph::c_api::abstract_functor {
raft::handle_t const& handle_;
cugraph::c_api::cugraph_graph_t* graph_;
size_t k_;
bool do_expensive_check_;
cugraph::c_api::cugraph_induced_subgraph_result_t* result_{};

k_truss_functor(::cugraph_resource_handle_t const* handle,
::cugraph_graph_t* graph,
size_t k,
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)),
k_(k),
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_legacy<vertex_t, edge_t, weight_t>::value) {
unsupported();
} else if constexpr (multi_gpu) {
unsupported();
} else {
// k_truss 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, false, multi_gpu>*>(graph_->graph_);

auto edge_weights = reinterpret_cast<
cugraph::edge_property_t<cugraph::graph_view_t<vertex_t, edge_t, false, multi_gpu>,
weight_t>*>(graph_->edge_weights_);

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

auto graph_view = graph->view();
rmm::device_uvector<vertex_t> src(0, handle_.get_stream());
rmm::device_uvector<vertex_t> dst(0, handle_.get_stream());
std::optional<rmm::device_uvector<weight_t>> wgt{std::nullopt};

std::tie(src, dst, wgt, std::ignore) = cugraph::decompress_to_edgelist(
handle_,
graph_view,
edge_weights ? std::make_optional(edge_weights->view()) : std::nullopt,
std::optional<cugraph::edge_property_view_t<edge_t, edge_t const*>>{std::nullopt},
std::optional<raft::device_span<vertex_t const>>(std::nullopt),
do_expensive_check_);

auto [result_src, result_dst, result_wgt] = cugraph::k_truss_subgraph(
handle_,
raft::device_span<vertex_t>(src.data(), src.size()),
raft::device_span<vertex_t>(dst.data(), dst.size()),
wgt ? std::make_optional(raft::device_span<weight_t>(wgt->data(), wgt->size()))
: std::nullopt,
graph_view.number_of_vertices(),
k_);

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

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

rmm::device_uvector<size_t> edge_offsets(2, handle_.get_stream());
std::vector<size_t> h_edge_offsets{{0, result_src.size()}};
raft::update_device(
edge_offsets.data(), h_edge_offsets.data(), h_edge_offsets.size(), handle_.get_stream());

result_ = new cugraph::c_api::cugraph_induced_subgraph_result_t{
new cugraph::c_api::cugraph_type_erased_device_array_t(result_src, graph_->vertex_type_),
new cugraph::c_api::cugraph_type_erased_device_array_t(result_dst, graph_->vertex_type_),
wgt ? new cugraph::c_api::cugraph_type_erased_device_array_t(*result_wgt,
graph_->weight_type_)
: NULL,
new cugraph::c_api::cugraph_type_erased_device_array_t(edge_offsets,
cugraph_data_type_id_t::SIZE_T)};
}
}
};

} // namespace

extern "C" cugraph_error_code_t cugraph_k_truss_subgraph(const cugraph_resource_handle_t* handle,
cugraph_graph_t* graph,
size_t k,
bool_t do_expensive_check,
cugraph_induced_subgraph_result_t** result,
cugraph_error_t** error)
{
k_truss_functor functor(handle, graph, k, do_expensive_check);

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

0 comments on commit 143324d

Please sign in to comment.