diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index ad30b3769d7..dfa10aba037 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ #============================================================================= -# Copyright (c) 2018-2024, NVIDIA CORPORATION. +# Copyright (c) 2018-2025, NVIDIA CORPORATION. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -396,6 +396,14 @@ set(CUGRAPH_SOURCES src/structure/create_graph_from_edgelist_sg_v32_e32.cu src/structure/create_graph_from_edgelist_mg_v64_e64.cu src/structure/create_graph_from_edgelist_mg_v32_e32.cu + src/structure/create_graph_from_edgelist_sg_v64_e64_t32.cu + src/structure/create_graph_from_edgelist_sg_v32_e32_t32.cu + src/structure/create_graph_from_edgelist_mg_v64_e64_t32.cu + src/structure/create_graph_from_edgelist_mg_v32_e32_t32.cu + src/structure/create_graph_from_edgelist_sg_v64_e64_t64.cu + src/structure/create_graph_from_edgelist_sg_v32_e32_t64.cu + src/structure/create_graph_from_edgelist_mg_v64_e64_t64.cu + src/structure/create_graph_from_edgelist_mg_v32_e32_t64.cu src/structure/symmetrize_edgelist_sg_v64_e64.cu src/structure/symmetrize_edgelist_sg_v32_e32.cu src/structure/symmetrize_edgelist_mg_v64_e64.cu diff --git a/cpp/include/cugraph/detail/shuffle_wrappers.hpp b/cpp/include/cugraph/detail/shuffle_wrappers.hpp index e0d8e7f0275..33ae38b8119 100644 --- a/cpp/include/cugraph/detail/shuffle_wrappers.hpp +++ b/cpp/include/cugraph/detail/shuffle_wrappers.hpp @@ -40,6 +40,7 @@ namespace detail { * @tparam edge_t Type of edge identifiers. Needs to be an integral type. * @tparam weight_t Type of edge weights. Needs to be a floating point type. * @tparam edge_type_t Type of edge type identifiers. Needs to be an integral type. + * @tparam edge_time_t The type of the edge time stamp. Needs to be an integral type. * * @param[in] handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, * and handles to various CUDA libraries) to run graph algorithms. @@ -51,16 +52,24 @@ namespace detail { * @param[in] weights Optional vector of vertex pair weight values. * @param[in] edge_ids Optional vector of vertex pair edge id values. * @param[in] edge_types Optional vector of vertex pair edge type values. + * @param[in] edge_start_times Optional vector of vertex pair edge start time values. + * @param[in] edge_end_times Optional vector of vertex pair edge end time values. * * @return Tuple of vectors storing shuffled major vertices, minor vertices and optional weights, * edge ids and edge types */ -template +template std::tuple, rmm::device_uvector, std::optional>, std::optional>, - std::optional>, + std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -68,7 +77,9 @@ shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types); + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); /** * @brief Shuffle internal (i.e. renumbered) vertex pairs (which can be edge end points) to their @@ -78,6 +89,7 @@ shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( * @tparam edge_t Type of edge identifiers. Needs to be an integral type. * @tparam weight_t Type of edge weights. Needs to be a floating point type. * @tparam edge_type_t Type of edge type identifiers. Needs to be an integral type. + * @tparam edge_time_t Type of edge time. Needs to be an integral type. * * @param[in] handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, * and handles to various CUDA libraries) to run graph algorithms. @@ -89,6 +101,8 @@ shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( * @param[in] weights Optional vector of vertex pair weight values. * @param[in] edge_ids Optional vector of vertex pair edge id values. * @param[in] edge_types Optional vector of vertex pair edge type values. + * @param[in] edge_start_times Optional vector of vertex pair edge start time values. + * @param[in] edge_end_times Optional vector of vertex pair edge end time values. * * @param[in] vertex_partition_range_lasts Vector of each GPU's vertex partition range's last * (exclusive) vertex ID. @@ -96,12 +110,18 @@ shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( * @return Tuple of vectors storing shuffled major vertices, minor vertices and optional weights, * edge ids and edge types and rx counts */ -template +template std::tuple, rmm::device_uvector, std::optional>, std::optional>, - std::optional>, + std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -109,7 +129,9 @@ shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, std::vector const& vertex_partition_range_lasts); /** @@ -218,7 +240,10 @@ shuffle_int_vertex_value_pairs_to_local_gpu_by_vertex_partitioning( * ID for an edge. * * @tparam vertex_t Type of vertex identifiers. Needs to be an integral type. + * @tparam edge_t Type of edge identifiers. Needs to be an integral type. * @tparam weight_t Type of edge weights. Needs to be a floating point type. + * @tparam edge_type_t Type of edge type identifiers. Needs to be an integral type. + * @tparam edge_time_t Type of edge time. Needs to be an integral type. * * @param[in] handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, * and handles to various CUDA libraries) to run graph algorithms. @@ -227,7 +252,10 @@ shuffle_int_vertex_value_pairs_to_local_gpu_by_vertex_partitioning( * @param[in,out] d_edgelist_minors Vertex IDs for destinations (if we are internally storing edges * in the sparse 2D matrix using sources as major indices) or sources (otherwise) * @param[in,out] d_edgelist_weights Optional edge weights - * @param[in,out] d_edgelist_id_type_pairs Optional edge (ID, type) pairs + * @param[in,out] d_edgelist_ids Optional edge ids + * @param[in,out] d_edgelist_types Optional edge types + * @param[in,out] d_edgelist_start_times Optional edge start times + * @param[in,out] d_edgelist_end_times Optional edge end times * @param[in] groupby_and_count_local_partition_by_minor If set to true, groupby and count edges * based on (local partition ID, GPU ID) pairs (where GPU IDs are computed by applying the * compute_gpu_id_from_vertex_t function to the minor vertex ID). If set to false, groupby and count @@ -237,7 +265,11 @@ shuffle_int_vertex_value_pairs_to_local_gpu_by_vertex_partitioning( * groupby_and_count_local_partition is false) or in each segment with the same (local partition ID, * GPU ID) pair. */ -template +template rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( raft::handle_t const& handle, rmm::device_uvector& d_edgelist_majors, @@ -245,6 +277,8 @@ rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( std::optional>& d_edgelist_weights, std::optional>& d_edgelist_edge_ids, std::optional>& d_edgelist_edge_types, + std::optional>& d_edgelist_edge_start_times, + std::optional>& d_edgelist_edge_end_times, bool groupby_and_count_local_partition_by_minor = false); /** diff --git a/cpp/include/cugraph/graph_functions.hpp b/cpp/include/cugraph/graph_functions.hpp index e85959e164a..7dd3a88d3ba 100644 --- a/cpp/include/cugraph/graph_functions.hpp +++ b/cpp/include/cugraph/graph_functions.hpp @@ -401,11 +401,15 @@ decompress_to_edgelist( * @brief Symmetrize edgelist. * * @tparam vertex_t Type of vertex identifiers. Needs to be an integral type. + * @tparam edge_t Type of edge identifiers. Needs to be an integral type. * @tparam weight_t Type of edge weights. Needs to be a floating point type. + * @tparam edge_type_t Type of edge type identifiers. Needs to be an integral type. + * @tparam edge_time_t Type of edge time. Needs to be an integral type. * @tparam store_transposed Flag indicating whether to use sources (if false) or destinations (if * true) as major indices in storing edges using a 2D sparse matrix. * @tparam multi_gpu Flag indicating whether template instantiation should target single-GPU (false) * or multi-GPU (true). + * * @param handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, and * handles to various CUDA libraries) to run graph algorithms. * @param edgelist_srcs Vector of edge source vertex IDs. If multi-GPU, applying the @@ -413,20 +417,36 @@ decompress_to_edgelist( * function to work (edges should be pre-shuffled). * @param edgelist_dsts Vector of edge destination vertex IDs. * @param edgelist_weights Vector of edge weights. + * @param edgelist_edge_ids Vector of edge ids + * @param edgelist_edge_types Vector of edge types + * @param edgelist_edge_start_times Vector of edge start times + * @param edgelist_edge_end_times Vector of edge end times * @param reciprocal Flag indicating whether to keep (if set to `false`) or discard (if set to * `true`) edges that appear only in one direction. - * @return std::tuple, rmm::device_uvector, - * std::optional>> Tuple of symmetrized sources, destinations, and - * optional weights (if @p edgelist_weights is valid). + * @return Tuple of symmetrized sources, destinations, optional weights, optional edge ids, optional + * edge types, optional edge start times and optional edge end times */ -template +template std::tuple, rmm::device_uvector, - std::optional>> + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> symmetrize_edgelist(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool reciprocal); /** @@ -696,7 +716,6 @@ extract_induced_subgraphs( * @tparam vertex_t Type of vertex identifiers. Needs to be an integral type. * @tparam edge_t Type of edge identifiers. Needs to be an integral type. * @tparam weight_t Type of edge weight. Needs to be floating point type - * @tparam edge_id_t Type of edge id. Needs to be an integral type * @tparam edge_type_t Type of edge type. Needs to be an integral type, currently only int32_t is * supported * @tparam store_transposed Flag indicating whether to use sources (if false) or destinations (if @@ -728,7 +747,6 @@ extract_induced_subgraphs( template @@ -737,7 +755,7 @@ std::tuple< std::optional< edge_property_t, weight_t>>, std::optional< - edge_property_t, edge_id_t>>, + edge_property_t, edge_t>>, std::optional< edge_property_t, edge_type_t>>, std::optional>> @@ -746,12 +764,85 @@ create_graph_from_edgelist(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, - std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_ids, std::optional>&& edgelist_edge_types, graph_properties_t graph_properties, bool renumber, bool do_expensive_check = false); +/** + * @ingroup graph_functions_cpp + * @brief create a graph from (the optional vertex list and) the given edge list (with optional edge + * IDs and types). + * + * @tparam vertex_t Type of vertex identifiers. Needs to be an integral type. + * @tparam edge_t Type of edge identifiers. Needs to be an integral type. + * @tparam weight_t Type of edge weight. Needs to be floating point type + * @tparam edge_type_t Type of edge type. Needs to be an integral type, currently only int32_t is + * supported + * @tparam edge_time_t Type of edge time. Needs to be an integral type. + * @tparam store_transposed Flag indicating whether to use sources (if false) or destinations (if + * true) as major indices in storing edges using a 2D sparse matrix. transposed. + * @tparam multi_gpu Flag indicating whether template instantiation should target single-GPU (false) + * or multi-GPU (true). + * @param handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, and + * handles to various CUDA libraries) to run graph algorithms. + * @param vertices If valid, part of the entire set of vertices in the graph to be renumbered. + * This parameter can be used to include isolated vertices. If @p renumber is false and @p vertices + * is valid, @p vertices elements should be consecutive integers starting from 0. If multi-GPU, + * applying the compute_gpu_id_from_vertex_t to every vertex should return the local GPU ID for this + * function to work (vertices should be pre-shuffled). + * @param edgelist_srcs Vector of edge source vertex IDs. If multi-GPU, applying the + * compute_gpu_id_from_ext_edge_endpoints_t to every edge should return the local GPU ID for this + * function to work (edges should be pre-shuffled). + * @param edgelist_dsts Vector of edge destination vertex IDs. + * @param edgelist_weights Vector of weight values for edges + * @param edgelist_edge_ids Vector of edge_id values for edges + * @param edgelist_edge_types Vector of edge_type values for edges + * @param edgelist_edge_start_times Vector of start time values for edges + * @param edgelist_edge_end_times Vector of end time values for edges + * @param graph_properties Properties of the graph represented by the input (optional vertex list + * and) edge list. + * @param renumber Flag indicating whether to renumber vertices or not (must be true if @p multi_gpu + * is true). + * @param do_expensive_check A flag to run expensive checks for input arguments (if set to `true`). + * @return Tuple of the generated graph and optional edge_property_t objects storing the provided + * edge properties and a renumber map (if @p renumber is true). + */ +template +std::tuple< + graph_t, + std::optional< + edge_property_t, weight_t>>, + std::optional< + edge_property_t, edge_t>>, + std::optional< + edge_property_t, edge_type_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check = false); + /** * @ingroup graph_functions_cpp * @brief create a graph from (the optional vertex list and) the given edge list (with optional edge @@ -762,7 +853,6 @@ create_graph_from_edgelist(raft::handle_t const& handle, * @tparam vertex_t Type of vertex identifiers. Needs to be an integral type. * @tparam edge_t Type of edge identifiers. Needs to be an integral type. * @tparam weight_t Type of edge weight. Needs to be floating point type - * @tparam edge_id_t Type of edge id. Needs to be an integral type * @tparam edge_type_t Type of edge type. Needs to be an integral type, currently only int32_t is * supported * @tparam store_transposed Flag indicating whether to use sources (if false) or destinations (if @@ -794,7 +884,6 @@ create_graph_from_edgelist(raft::handle_t const& handle, template @@ -803,7 +892,7 @@ std::tuple< std::optional< edge_property_t, weight_t>>, std::optional< - edge_property_t, edge_id_t>>, + edge_property_t, edge_t>>, std::optional< edge_property_t, edge_type_t>>, std::optional>> @@ -813,12 +902,87 @@ create_graph_from_edgelist( std::vector>&& edgelist_srcs, std::vector>&& edgelist_dsts, std::optional>>&& edgelist_weights, - std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_ids, std::optional>>&& edgelist_edge_types, graph_properties_t graph_properties, bool renumber, bool do_expensive_check = false); +/** + * @ingroup graph_functions_cpp + * @brief create a graph from (the optional vertex list and) the given edge list (with optional edge + * IDs, types, start and end times). + * + * This version takes edge list in multiple chunks (e.g. edge data from multiple files). + * + * @tparam vertex_t Type of vertex identifiers. Needs to be an integral type. + * @tparam edge_t Type of edge identifiers. Needs to be an integral type. + * @tparam weight_t Type of edge weight. Needs to be floating point type + * @tparam edge_type_t Type of edge type. Needs to be an integral type, currently only int32_t is + * supported + * @tparam edge_time_t Type of edge time. Needs to be an integral type. + * @tparam store_transposed Flag indicating whether to use sources (if false) or destinations (if + * true) as major indices in storing edges using a 2D sparse matrix. transposed. + * @tparam multi_gpu Flag indicating whether template instantiation should target single-GPU (false) + * or multi-GPU (true). + * @param handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, and + * handles to various CUDA libraries) to run graph algorithms. + * @param vertices If valid, part of the entire set of vertices in the graph to be renumbered. + * This parameter can be used to include isolated vertices. If @p renumber is false and @p vertices + * is valid, @p vertices elements should be consecutive integers starting from 0. If multi-GPU, + * applying the compute_gpu_id_from_vertex_t to every vertex should return the local GPU ID for this + * function to work (vertices should be pre-shuffled). + * @param edgelist_srcs Vectors of edge source vertex IDs. If multi-GPU, applying the + * compute_gpu_id_from_ext_edge_endpoints_t to every edge should return the local GPU ID for this + * function to work (edges should be pre-shuffled). + * @param edgelist_dsts Vectors of edge destination vertex IDs. + * @param edgelist_weights Vectors of weight values for edges + * @param edgelist_edge_ids Vectors of edge_id values for edges + * @param edgelist_edge_types Vectors of edge_type values for edges + * @param edgelist_edge_start_times Vector of start time values for edges + * @param edgelist_edge_end_times Vector of end time values for edges + * @param graph_properties Properties of the graph represented by the input (optional vertex list + * and) edge list. + * @param renumber Flag indicating whether to renumber vertices or not (must be true if @p multi_gpu + * is true). + * @param do_expensive_check A flag to run expensive checks for input arguments (if set to `true`). + * @return Tuple of the generated graph and optional edge_property_t objects storing the provided + * edge properties and a renumber map (if @p renumber is true). + */ +template +std::tuple< + graph_t, + std::optional< + edge_property_t, weight_t>>, + std::optional< + edge_property_t, edge_t>>, + std::optional< + edge_property_t, edge_type_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check = false); + /** * @ingroup graph_functions_cpp * @brief Find all 2-hop neighbors in the graph @@ -1026,6 +1190,7 @@ rmm::device_uvector select_random_vertices( * @tparam edge_t Type of edge identifiers. Needs to be an integral type. * @tparam weight_t Type of edge weight. Currently float and double are supported. * @tparam edge_type_t Type of edge type. Needs to be an integral type. + * @tparam edge_time_t Type of edge time. Needs to be an integral type. * * @param handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, and * handles to various CUDA libraries) to run graph algorithms. @@ -1034,21 +1199,31 @@ rmm::device_uvector select_random_vertices( * @param edgelist_weights Optional list of edge weights * @param edgelist_edge_ids Optional list of edge ids * @param edgelist_edge_types Optional list of edge types - * @return Tuple of vectors storing edge sources, destinations, optional weights, - * optional edge ids, optional edge types. + * @param edgelist_edge_start_times Optional list of edge start times + * @param edgelist_edge_end_times Optional list of edge end times + * @return Tuple of vectors storing edge sources, destinations, optional weights, optional edge ids, + * optional edge types, optional edge start times and optional edge end times. */ -template +template std::tuple, rmm::device_uvector, std::optional>, std::optional>, - std::optional>> + std::optional>, + std::optional>, + std::optional>> remove_self_loops(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, - std::optional>&& edgelist_edge_types); + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times); /** * @ingroup graph_functions_cpp @@ -1068,6 +1243,7 @@ remove_self_loops(raft::handle_t const& handle, * @tparam edge_t Type of edge identifiers. Needs to be an integral type. * @tparam weight_t Type of edge weight. Currently float and double are supported. * @tparam edge_type_t Type of edge type. Needs to be an integral type. + * @tparam edge_time_t Type of edge time. Needs to be an integral type. * * @param handle RAFT handle object to encapsulate resources (e.g. CUDA stream, communicator, and * handles to various CUDA libraries) to run graph algorithms. @@ -1076,26 +1252,36 @@ remove_self_loops(raft::handle_t const& handle, * @param edgelist_weights Optional list of edge weights * @param edgelist_edge_ids Optional list of edge ids * @param edgelist_edge_types Optional list of edge types + * @param edgelist_edge_start_times Optional list of edge start times + * @param edgelist_edge_end_times Optional list of edge end times * @param keep_min_value_edge Flag indicating whether to keep an arbitrary edge (false) or the * minimum value edge (true) among the edges in a multi-edge. Relevant only if @p * edgelist_weights.has_value() | @p edgelist_edge_ids.has_value() | @p * edgelist_edge_types.has_value() is true. Setting this to true incurs performance overhead as this * requires more comparisons. - * @return Tuple of vectors storing edge sources, destinations, optional weights, - * optional edge ids, optional edge types. + * @return Tuple of vectors storing edge sources, destinations, optional weights, optional edge ids, + * optional edge types, optional edge start times and optional edge end times. */ -template +template std::tuple, rmm::device_uvector, std::optional>, std::optional>, - std::optional>> + std::optional>, + std::optional>, + std::optional>> remove_multi_edges(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_edge_times, bool keep_min_value_edge = false); /** diff --git a/cpp/src/c_api/graph.hpp b/cpp/src/c_api/graph.hpp index 8332f6600e9..306a92e0c40 100644 --- a/cpp/src/c_api/graph.hpp +++ b/cpp/src/c_api/graph.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,17 +36,23 @@ struct cugraph_graph_t { bool store_transposed_; bool multi_gpu_; - void* graph_; // graph_t<...>* - void* number_map_; // rmm::device_uvector* - void* edge_weights_; // edge_property_t< - // graph_view_t, - // weight_t>* - void* edge_ids_; // edge_property_t< - // graph_view_t, - // edge_t>* - void* edge_types_; // edge_property_t< - // graph_view_t, - // edge_type_id_t>* + void* graph_; // graph_t<...>* + void* number_map_; // rmm::device_uvector* + void* edge_weights_; // edge_property_t< + // graph_view_t, + // weight_t>* + void* edge_ids_; // edge_property_t< + // graph_view_t, + // edge_t>* + void* edge_types_; // edge_property_t< + // graph_view_t, + // edge_type_t>* + void* edge_start_times_; // edge_property_t< + // graph_view_t, + // edge_time_t>* + void* edge_end_times_; // edge_property_t< + // graph_view_t, + // edge_time_t>* }; template as_type(), second_->size_, handle_.get_stream()); if constexpr (multi_gpu) { - std::tie(first_copy, second_copy, std::ignore, std::ignore, std::ignore, std::ignore) = + std::tie(first_copy, + second_copy, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore) = cugraph::detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, edge_t, weight_t, - edge_type_type_t>(handle_, - std::move(first_copy), - std::move(second_copy), - std::nullopt, - std::nullopt, - std::nullopt); + edge_type_type_t, + int32_t>(handle_, + std::move(first_copy), + std::move(second_copy), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt); } // FIXME: use std::tuple (template) instead. result_ = new cugraph::c_api::cugraph_vertex_pairs_t{ diff --git a/cpp/src/c_api/graph_mg.cpp b/cpp/src/c_api/graph_mg.cpp index c63528a9180..88e3b795348 100644 --- a/cpp/src/c_api/graph_mg.cpp +++ b/cpp/src/c_api/graph_mg.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -119,11 +119,13 @@ struct create_graph_functor : public cugraph::c_api::abstract_functor { template void operator()() { + using edge_time_t = int32_t; + if constexpr (!multi_gpu || !cugraph::is_candidate::value) { unsupported(); } else { @@ -141,7 +143,7 @@ struct create_graph_functor : public cugraph::c_api::abstract_functor { std::optional, - edge_type_id_t>> + edge_type_t>> new_edge_types{std::nullopt}; std::optional> vertex_list = @@ -161,16 +163,21 @@ struct create_graph_functor : public cugraph::c_api::abstract_functor { edge_ids_ ? std::make_optional(concatenate(handle_, edge_ids_, num_arrays_)) : std::nullopt; - std::optional> edgelist_edge_types = + std::optional> edgelist_edge_types = edge_type_ids_ - ? std::make_optional(concatenate(handle_, edge_type_ids_, num_arrays_)) + ? std::make_optional(concatenate(handle_, edge_type_ids_, num_arrays_)) : std::nullopt; + std::optional> edgelist_edge_start_times{std::nullopt}; + std::optional> edgelist_edge_end_times{std::nullopt}; + std::tie(store_transposed ? edgelist_dsts : edgelist_srcs, store_transposed ? edgelist_srcs : edgelist_dsts, edgelist_weights, edgelist_edge_ids, edgelist_edge_types, + edgelist_edge_start_times, + edgelist_edge_end_times, std::ignore) = cugraph::detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( handle_, @@ -178,7 +185,9 @@ struct create_graph_functor : public cugraph::c_api::abstract_functor { std::move(store_transposed ? edgelist_srcs : edgelist_dsts), std::move(edgelist_weights), std::move(edgelist_edge_ids), - std::move(edgelist_edge_types)); + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times)); if (vertex_list) { vertex_list = cugraph::detail::shuffle_ext_vertices_to_local_gpu_by_vertex_partitioning( @@ -200,67 +209,93 @@ struct create_graph_functor : public cugraph::c_api::abstract_functor { auto edge_types = new cugraph::edge_property_t< cugraph::graph_view_t, - edge_type_id_t>(handle_); + edge_type_t>(handle_); if (drop_self_loops_) { - std::tie( - edgelist_srcs, edgelist_dsts, edgelist_weights, edgelist_edge_ids, edgelist_edge_types) = + std::tie(edgelist_srcs, + edgelist_dsts, + edgelist_weights, + edgelist_edge_ids, + edgelist_edge_types, + edgelist_edge_start_times, + edgelist_edge_end_times) = cugraph::remove_self_loops(handle_, std::move(edgelist_srcs), std::move(edgelist_dsts), std::move(edgelist_weights), std::move(edgelist_edge_ids), - std::move(edgelist_edge_types)); + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times)); } if (drop_multi_edges_) { - std::tie( - edgelist_srcs, edgelist_dsts, edgelist_weights, edgelist_edge_ids, edgelist_edge_types) = + std::tie(edgelist_srcs, + edgelist_dsts, + edgelist_weights, + edgelist_edge_ids, + edgelist_edge_types, + edgelist_edge_start_times, + edgelist_edge_end_times) = cugraph::remove_multi_edges(handle_, std::move(edgelist_srcs), std::move(edgelist_dsts), std::move(edgelist_weights), std::move(edgelist_edge_ids), std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times), properties_->is_symmetric ? true /* keep minimum weight edges to maintain symmetry */ : false); } if (symmetrize_) { - if (edgelist_edge_ids || edgelist_edge_types) { - // Currently doesn't support the symmetrization of edgelist with edge_ids and edge_types - unsupported(); - } - // Symmetrize the edgelist - std::tie(edgelist_srcs, edgelist_dsts, edgelist_weights) = - cugraph::symmetrize_edgelist( + std::tie(edgelist_srcs, + edgelist_dsts, + edgelist_weights, + edgelist_edge_ids, + edgelist_edge_types, + edgelist_edge_start_times, + edgelist_edge_end_times) = cugraph:: + symmetrize_edgelist( handle_, std::move(edgelist_srcs), std::move(edgelist_dsts), std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times), false); } - std::tie(*graph, new_edge_weights, new_edge_ids, new_edge_types, new_number_map) = - cugraph::create_graph_from_edgelist( - handle_, - std::move(vertex_list), - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(edgelist_weights), - std::move(edgelist_edge_ids), - std::move(edgelist_edge_types), - cugraph::graph_properties_t{properties_->is_symmetric, properties_->is_multigraph}, - renumber_, - do_expensive_check_); + std::tie(*graph, + new_edge_weights, + new_edge_ids, + new_edge_types, + std::ignore, + std::ignore, + new_number_map) = cugraph::create_graph_from_edgelist( + handle_, + std::move(vertex_list), + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times), + cugraph::graph_properties_t{properties_->is_symmetric, properties_->is_multigraph}, + renumber_, + do_expensive_check_); if (renumber_) { *number_map = std::move(new_number_map.value()); diff --git a/cpp/src/c_api/graph_sg.cpp b/cpp/src/c_api/graph_sg.cpp index e57d6b5bb14..684a8c66e40 100644 --- a/cpp/src/c_api/graph_sg.cpp +++ b/cpp/src/c_api/graph_sg.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,11 +83,13 @@ struct create_graph_functor : public cugraph::c_api::abstract_functor { template void operator()() { + using edge_time_t = int32_t; + if constexpr (multi_gpu || !cugraph::is_candidate::value) { unsupported(); } else { @@ -109,7 +111,7 @@ struct create_graph_functor : public cugraph::c_api::abstract_functor { std::optional, - edge_type_id_t>> + edge_type_t>> new_edge_types{std::nullopt}; std::optional> vertex_list = @@ -156,16 +158,16 @@ struct create_graph_functor : public cugraph::c_api::abstract_functor { handle_.get_stream()); } - std::optional> edgelist_edge_types = - edge_type_ids_ ? std::make_optional(rmm::device_uvector( - edge_type_ids_->size_, handle_.get_stream())) + std::optional> edgelist_edge_types = + edge_type_ids_ ? std::make_optional(rmm::device_uvector(edge_type_ids_->size_, + handle_.get_stream())) : std::nullopt; if (edgelist_edge_types) { - raft::copy(edgelist_edge_types->data(), - edge_type_ids_->as_type(), - edge_type_ids_->size_, - handle_.get_stream()); + raft::copy(edgelist_edge_types->data(), + edge_type_ids_->as_type(), + edge_type_ids_->size_, + handle_.get_stream()); } auto graph = new cugraph::graph_t(handle_); @@ -183,67 +185,104 @@ struct create_graph_functor : public cugraph::c_api::abstract_functor { auto edge_types = new cugraph::edge_property_t< cugraph::graph_view_t, - edge_type_id_t>(handle_); + edge_type_t>(handle_); if (drop_self_loops_) { - std::tie( - edgelist_srcs, edgelist_dsts, edgelist_weights, edgelist_edge_ids, edgelist_edge_types) = - cugraph::remove_self_loops(handle_, - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(edgelist_weights), - std::move(edgelist_edge_ids), - std::move(edgelist_edge_types)); + std::optional> dummy_start_times{std::nullopt}; + std::optional> dummy_end_times{std::nullopt}; + + std::tie(edgelist_srcs, + edgelist_dsts, + edgelist_weights, + edgelist_edge_ids, + edgelist_edge_types, + std::ignore, + std::ignore) = cugraph::remove_self_loops(handle_, + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::move(dummy_start_times), + std::move(dummy_end_times)); } if (drop_multi_edges_) { - std::tie( - edgelist_srcs, edgelist_dsts, edgelist_weights, edgelist_edge_ids, edgelist_edge_types) = + std::optional> dummy_start_times{std::nullopt}; + std::optional> dummy_end_times{std::nullopt}; + + std::tie(edgelist_srcs, + edgelist_dsts, + edgelist_weights, + edgelist_edge_ids, + edgelist_edge_types, + std::ignore, + std::ignore) = cugraph::remove_multi_edges(handle_, std::move(edgelist_srcs), std::move(edgelist_dsts), std::move(edgelist_weights), std::move(edgelist_edge_ids), std::move(edgelist_edge_types), + std::move(dummy_start_times), + std::move(dummy_end_times), properties_->is_symmetric ? true /* keep minimum weight edges to maintain symmetry */ : false); } if (symmetrize_) { - if (edgelist_edge_ids || edgelist_edge_types) { - // Currently doesn't support the symmetrization with edge_ids and edge_types - unsupported(); - } + std::optional> dummy_start_times{std::nullopt}; + std::optional> dummy_end_times{std::nullopt}; // Symmetrize the edgelist - std::tie(edgelist_srcs, edgelist_dsts, edgelist_weights) = - cugraph::symmetrize_edgelist( + std::tie(edgelist_srcs, + edgelist_dsts, + edgelist_weights, + edgelist_edge_ids, + edgelist_edge_types, + std::ignore, + std::ignore) = cugraph:: + symmetrize_edgelist( handle_, std::move(edgelist_srcs), std::move(edgelist_dsts), std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::move(dummy_start_times), + std::move(dummy_end_times), false); } - std::tie(*graph, new_edge_weights, new_edge_ids, new_edge_types, new_number_map) = - cugraph::create_graph_from_edgelist( - handle_, - std::move(vertex_list), - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(edgelist_weights), - std::move(edgelist_edge_ids), - std::move(edgelist_edge_types), - cugraph::graph_properties_t{properties_->is_symmetric, properties_->is_multigraph}, - renumber_, - do_expensive_check_); + std::optional> dummy_start_times{std::nullopt}; + std::optional> dummy_end_times{std::nullopt}; + + std::tie(*graph, + new_edge_weights, + new_edge_ids, + new_edge_types, + std::ignore, + std::ignore, + new_number_map) = cugraph::create_graph_from_edgelist( + handle_, + std::move(vertex_list), + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::move(dummy_start_times), + std::move(dummy_end_times), + cugraph::graph_properties_t{properties_->is_symmetric, properties_->is_multigraph}, + renumber_, + do_expensive_check_); if (renumber_) { *number_map = std::move(new_number_map.value()); @@ -271,7 +310,9 @@ struct create_graph_functor : public cugraph::c_api::abstract_functor { number_map, new_edge_weights ? edge_weights : nullptr, new_edge_ids ? edge_ids : nullptr, - new_edge_types ? edge_types : nullptr}; + new_edge_types ? edge_types : nullptr, + nullptr, + nullptr}; result_ = reinterpret_cast(result); } @@ -319,11 +360,13 @@ struct create_graph_csr_functor : public cugraph::c_api::abstract_functor { template void operator()() { + using edge_time_t = int32_t; + if constexpr (multi_gpu || !cugraph::is_candidate::value) { unsupported(); } else { @@ -345,7 +388,7 @@ struct create_graph_csr_functor : public cugraph::c_api::abstract_functor { std::optional, - edge_type_id_t>> + edge_type_t>> new_edge_types{std::nullopt}; std::optional> vertex_list = std::make_optional( @@ -376,7 +419,7 @@ struct create_graph_csr_functor : public cugraph::c_api::abstract_functor { handle_.get_stream()); } - std::optional, rmm::device_uvector>> + std::optional, rmm::device_uvector>> edgelist_edge_tuple{}; std::optional> edgelist_edge_ids = @@ -391,18 +434,21 @@ struct create_graph_csr_functor : public cugraph::c_api::abstract_functor { handle_.get_stream()); } - std::optional> edgelist_edge_types = - edge_type_ids_ ? std::make_optional(rmm::device_uvector( - edge_type_ids_->size_, handle_.get_stream())) + std::optional> edgelist_edge_types = + edge_type_ids_ ? std::make_optional(rmm::device_uvector(edge_type_ids_->size_, + handle_.get_stream())) : std::nullopt; if (edgelist_edge_types) { - raft::copy(edgelist_edge_types->data(), - edge_type_ids_->as_type(), - edge_type_ids_->size_, - handle_.get_stream()); + raft::copy(edgelist_edge_types->data(), + edge_type_ids_->as_type(), + edge_type_ids_->size_, + handle_.get_stream()); } + std::optional> edgelist_edge_start_times{std::nullopt}; + std::optional> edgelist_edge_end_times{std::nullopt}; + auto graph = new cugraph::graph_t(handle_); rmm::device_uvector* number_map = @@ -418,42 +464,54 @@ struct create_graph_csr_functor : public cugraph::c_api::abstract_functor { auto edge_types = new cugraph::edge_property_t< cugraph::graph_view_t, - edge_type_id_t>(handle_); + edge_type_t>(handle_); if (symmetrize_) { - if (edgelist_edge_ids || edgelist_edge_types) { - // Currently doesn't support the symmetrization with edge_ids and edge_types - unsupported(); - } - // Symmetrize the edgelist - std::tie(edgelist_srcs, edgelist_dsts, edgelist_weights) = - cugraph::symmetrize_edgelist( + std::tie(edgelist_srcs, + edgelist_dsts, + edgelist_weights, + edgelist_edge_ids, + edgelist_edge_types, + edgelist_edge_start_times, + edgelist_edge_end_times) = cugraph:: + symmetrize_edgelist( handle_, std::move(edgelist_srcs), std::move(edgelist_dsts), std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times), false); } - std::tie(*graph, new_edge_weights, new_edge_ids, new_edge_types, new_number_map) = - cugraph::create_graph_from_edgelist( - handle_, - std::move(vertex_list), - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(edgelist_weights), - std::move(edgelist_edge_ids), - std::move(edgelist_edge_types), - cugraph::graph_properties_t{properties_->is_symmetric, properties_->is_multigraph}, - renumber_, - do_expensive_check_); + std::tie(*graph, + new_edge_weights, + new_edge_ids, + new_edge_types, + std::ignore, + std::ignore, + new_number_map) = cugraph::create_graph_from_edgelist( + handle_, + std::move(vertex_list), + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times), + cugraph::graph_properties_t{properties_->is_symmetric, properties_->is_multigraph}, + renumber_, + do_expensive_check_); if (renumber_) { *number_map = std::move(new_number_map.value()); @@ -509,7 +567,7 @@ struct destroy_graph_functor : public cugraph::c_api::abstract_functor { template void operator()() @@ -536,7 +594,7 @@ struct destroy_graph_functor : public cugraph::c_api::abstract_functor { auto internal_edge_type_pointer = reinterpret_cast< cugraph::edge_property_t, - edge_type_id_t>*>(edge_types_); + edge_type_t>*>(edge_types_); if (internal_edge_type_pointer) { delete internal_edge_type_pointer; } } }; diff --git a/cpp/src/community/detail/refine_impl.cuh b/cpp/src/community/detail/refine_impl.cuh index d69c1463edf..01a68a3a0d7 100644 --- a/cpp/src/community/detail/refine_impl.cuh +++ b/cpp/src/community/detail/refine_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, NVIDIA CORPORATION. + * Copyright (c) 2023-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -635,36 +635,36 @@ refine_clustering( d_weights, std::ignore, std::ignore, + std::ignore, + std::ignore, std::ignore) = cugraph::detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, vertex_t, weight_t, + int32_t, int32_t>(handle, store_transposed ? std::move(d_dsts) : std::move(d_srcs), store_transposed ? std::move(d_srcs) : std::move(d_dsts), std::move(d_weights), std::nullopt, + std::nullopt, + std::nullopt, std::nullopt); } std::tie(decision_graph, coarse_edge_weights, std::ignore, std::ignore, renumber_map) = - create_graph_from_edgelist(handle, - std::nullopt, - std::move(d_srcs), - std::move(d_dsts), - std::move(d_weights), - std::nullopt, - std::nullopt, - cugraph::graph_properties_t{false, false}, - true, - false); + create_graph_from_edgelist( + handle, + std::nullopt, + std::move(d_srcs), + std::move(d_dsts), + std::move(d_weights), + std::nullopt, + std::nullopt, + cugraph::graph_properties_t{false, false}, + true, + false); auto decision_graph_view = decision_graph.view(); diff --git a/cpp/src/community/edge_triangle_count_impl.cuh b/cpp/src/community/edge_triangle_count_impl.cuh index e3501065008..fbf47615dbe 100644 --- a/cpp/src/community/edge_triangle_count_impl.cuh +++ b/cpp/src/community/edge_triangle_count_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, NVIDIA CORPORATION. + * Copyright (c) 2024-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -248,10 +248,18 @@ edge_property_t, edge_t> edge_t handle.get_stream()); // There are still multiple copies here but is it worth sorting and reducing again? - std::tie(pair_srcs, pair_dsts, std::ignore, pair_count, std::ignore, std::ignore) = + std::tie(pair_srcs, + pair_dsts, + std::ignore, + pair_count, + std::ignore, + std::ignore, + std::ignore, + std::ignore) = shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( handle, std::move(std::get<0>(vertex_pair_buffer)), @@ -260,6 +268,8 @@ edge_property_t, edge_t> edge_t // FIXME: Add general purpose function for shuffling vertex pairs and arbitrary attributes std::move(opt_increase_count), std::nullopt, + std::nullopt, + std::nullopt, graph_view.vertex_partition_range_lasts()); thrust::for_each( diff --git a/cpp/src/community/k_truss_impl.cuh b/cpp/src/community/k_truss_impl.cuh index e052a892917..2b712a6de77 100644 --- a/cpp/src/community/k_truss_impl.cuh +++ b/cpp/src/community/k_truss_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, NVIDIA CORPORATION. + * Copyright (c) 2024-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -130,16 +130,25 @@ k_truss(raft::handle_t const& handle, exclude_self_loop_t{}); if constexpr (multi_gpu) { - std::tie(srcs, dsts, std::ignore, std::ignore, std::ignore, std::ignore) = + std::tie( + srcs, dsts, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) = detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( - handle, std::move(srcs), std::move(dsts), std::nullopt, std::nullopt, std::nullopt); + handle, + std::move(srcs), + std::move(dsts), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt); } std::tie(*modified_graph, std::ignore, std::ignore, std::ignore, renumber_map) = - create_graph_from_edgelist( + create_graph_from_edgelist( handle, std::nullopt, std::move(srcs), @@ -178,17 +187,25 @@ k_truss(raft::handle_t const& handle, std::make_optional(core_number_span)); if constexpr (multi_gpu) { - std::tie(srcs, dsts, wgts, std::ignore, std::ignore, std::ignore) = + std::tie(srcs, dsts, wgts, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) = detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( - handle, std::move(srcs), std::move(dsts), std::move(wgts), std::nullopt, std::nullopt); + handle, + std::move(srcs), + std::move(dsts), + std::move(wgts), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt); } std::optional> tmp_renumber_map{std::nullopt}; std::tie(*modified_graph, edge_weight, std::ignore, std::ignore, tmp_renumber_map) = - create_graph_from_edgelist( + create_graph_from_edgelist( handle, std::nullopt, std::move(srcs), @@ -257,18 +274,26 @@ k_truss(raft::handle_t const& handle, } if constexpr (multi_gpu) { - std::tie(srcs, dsts, wgts, std::ignore, std::ignore, std::ignore) = + std::tie(srcs, dsts, wgts, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) = detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( - handle, std::move(srcs), std::move(dsts), std::move(wgts), std::nullopt, std::nullopt); + handle, + std::move(srcs), + std::move(dsts), + std::move(wgts), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt); } std::optional> tmp_renumber_map{std::nullopt}; std::tie(*modified_graph, edge_weight, std::ignore, std::ignore, tmp_renumber_map) = - create_graph_from_edgelist( + create_graph_from_edgelist( handle, std::nullopt, std::move(srcs), @@ -343,12 +368,23 @@ k_truss(raft::handle_t const& handle, std::make_optional( raft::device_span((*renumber_map).data(), (*renumber_map).size()))); - std::tie(edgelist_srcs, edgelist_dsts, edgelist_wgts) = - symmetrize_edgelist(handle, - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(edgelist_wgts), - false); + std::tie(edgelist_srcs, + edgelist_dsts, + edgelist_wgts, + std::ignore, + std::ignore, + std::ignore, + std::ignore) = + symmetrize_edgelist( + handle, + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_wgts), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + false); return std::make_tuple( std::move(edgelist_srcs), std::move(edgelist_dsts), std::move(edgelist_wgts)); diff --git a/cpp/src/community/triangle_count_impl.cuh b/cpp/src/community/triangle_count_impl.cuh index e902901cd36..100451f06f3 100644 --- a/cpp/src/community/triangle_count_impl.cuh +++ b/cpp/src/community/triangle_count_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024, NVIDIA CORPORATION. + * Copyright (c) 2022-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -439,16 +439,25 @@ void triangle_count(raft::handle_t const& handle, extract_low_to_high_degree_edges_t{}); if constexpr (multi_gpu) { - std::tie(srcs, dsts, std::ignore, std::ignore, std::ignore, std::ignore) = + std::tie( + srcs, dsts, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) = detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( - handle, std::move(srcs), std::move(dsts), std::nullopt, std::nullopt, std::nullopt); + handle, + std::move(srcs), + std::move(dsts), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt); } std::tie(modified_graph, std::ignore, std::ignore, std::ignore, renumber_map) = - create_graph_from_edgelist( + create_graph_from_edgelist( handle, std::nullopt, std::move(srcs), diff --git a/cpp/src/components/weakly_connected_components_impl.cuh b/cpp/src/components/weakly_connected_components_impl.cuh index 219bc3c4d1d..e791f4dcad3 100644 --- a/cpp/src/components/weakly_connected_components_impl.cuh +++ b/cpp/src/components/weakly_connected_components_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2024, NVIDIA CORPORATION. + * Copyright (c) 2020-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -684,17 +684,22 @@ void weakly_connected_components_impl(raft::handle_t const& handle, std::ignore, std::ignore, std::ignore, + std::ignore, + std::ignore, std::ignore) = detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, edge_t, weight_t, - edge_type_t>(handle, - std::move(std::get<0>(edge_buffer)), - std::move(std::get<1>(edge_buffer)), - std::nullopt, - std::nullopt, - std::nullopt); + edge_type_t, + int32_t>(handle, + std::move(std::get<0>(edge_buffer)), + std::move(std::get<1>(edge_buffer)), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt); auto edge_first = get_dataframe_buffer_begin(edge_buffer); auto edge_last = get_dataframe_buffer_end(edge_buffer); thrust::sort(handle.get_thrust_policy(), edge_first, edge_last); @@ -710,7 +715,6 @@ void weakly_connected_components_impl(raft::handle_t const& handle, create_graph_from_edgelist(handle, diff --git a/cpp/src/detail/groupby_and_count.cuh b/cpp/src/detail/groupby_and_count.cuh index a452bcaeea2..2117e3142f2 100644 --- a/cpp/src/detail/groupby_and_count.cuh +++ b/cpp/src/detail/groupby_and_count.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ #include "detail/graph_partition_utils.cuh" #include +#include #include #include #include @@ -26,9 +27,9 @@ #include #include +#include #include #include -#include #include #include @@ -36,7 +37,11 @@ namespace cugraph { namespace detail { -template +template rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( raft::handle_t const& handle, rmm::device_uvector& d_edgelist_majors, @@ -44,6 +49,8 @@ rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( std::optional>& d_edgelist_weights, std::optional>& d_edgelist_edge_ids, std::optional>& d_edgelist_edge_types, + std::optional>& d_edgelist_edge_start_times, + std::optional>& d_edgelist_edge_end_times, bool groupby_and_count_local_partition_by_minor) { auto& comm = handle.get_comms(); @@ -56,10 +63,34 @@ rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( auto const minor_comm_size = minor_comm.get_size(); auto const minor_comm_rank = minor_comm.get_rank(); + int edge_property_count = 0; + size_t element_size = sizeof(vertex_t) * 2; + + if (d_edgelist_weights) { + ++edge_property_count; + element_size += sizeof(weight_t); + } + + if (d_edgelist_edge_ids) { + ++edge_property_count; + element_size += sizeof(edge_t); + } + if (d_edgelist_edge_types) { + ++edge_property_count; + element_size += sizeof(edge_type_t); + } + if (d_edgelist_edge_start_times) { + ++edge_property_count; + element_size += sizeof(edge_time_t); + } + if (d_edgelist_edge_end_times) { + ++edge_property_count; + element_size += sizeof(edge_time_t); + } + + if (edge_property_count > 1) { element_size = sizeof(vertex_t) * 2 + sizeof(size_t); } + auto total_global_mem = handle.get_device_properties().totalGlobalMem; - auto element_size = sizeof(vertex_t) * 2 + (d_edgelist_weights ? sizeof(weight_t) : size_t{0}) + - (d_edgelist_edge_ids ? sizeof(edge_t) : size_t{0}) + - (d_edgelist_edge_types ? sizeof(edge_type_t) : size_t{0}); auto constexpr mem_frugal_ratio = 0.1; // if the expected temporary buffer size exceeds the mem_frugal_ratio of the // total_global_mem, switch to the memory frugal approach (thrust::sort is used to @@ -73,193 +104,218 @@ rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( rmm::device_uvector result(0, handle.get_stream()); - if (groupby_and_count_local_partition_by_minor) { - auto local_edge_and_vertex_partition_id_pair_op = - [major_comm_size, - local_edge_partition_id_key_func = - cugraph::detail::compute_local_edge_partition_id_from_ext_edge_endpoints_t{ - comm_size, major_comm_size, minor_comm_size}, - vertex_partition_id_key_func = - cugraph::detail::compute_vertex_partition_id_from_ext_vertex_t{ - comm_size}] __device__(auto pair) { - auto local_edge_partition_id = local_edge_partition_id_key_func(pair); - auto vertex_partition_id = vertex_partition_id_key_func(thrust::get<1>(pair)); - return (local_edge_partition_id * major_comm_size) + - ((vertex_partition_id) % major_comm_size); - }; + auto local_edge_partition_include_minor_op = + [major_comm_size, + local_edge_partition_id_key_func = + cugraph::detail::compute_local_edge_partition_id_from_ext_edge_endpoints_t{ + comm_size, major_comm_size, minor_comm_size}, + vertex_partition_id_key_func = + cugraph::detail::compute_vertex_partition_id_from_ext_vertex_t{ + comm_size}] __device__(auto pair) { + auto local_edge_partition_id = local_edge_partition_id_key_func(pair); + auto vertex_partition_id = vertex_partition_id_key_func(thrust::get<1>(pair)); + return (local_edge_partition_id * major_comm_size) + + ((vertex_partition_id) % major_comm_size); + }; + auto local_edge_partition_op = + [key_func = + cugraph::detail::compute_local_edge_partition_id_from_ext_edge_endpoints_t{ + comm_size, major_comm_size, minor_comm_size}] __device__(auto pair) { + return key_func(pair); + }; + + if (edge_property_count == 0) { + if (groupby_and_count_local_partition_by_minor) { + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + local_edge_partition_include_minor_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } else { + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + local_edge_partition_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } + + } else if (edge_property_count == 1) { if (d_edgelist_weights) { - if (d_edgelist_edge_ids) { - if (d_edgelist_edge_types) { - result = - cugraph::groupby_and_count(pair_first, - pair_first + d_edgelist_majors.size(), - thrust::make_zip_iterator(d_edgelist_weights->begin(), - d_edgelist_edge_ids->begin(), - d_edgelist_edge_types->begin()), - local_edge_and_vertex_partition_id_pair_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - result = cugraph::groupby_and_count( - pair_first, - pair_first + d_edgelist_majors.size(), - thrust::make_zip_iterator(d_edgelist_weights->begin(), d_edgelist_edge_ids->begin()), - local_edge_and_vertex_partition_id_pair_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } + if (groupby_and_count_local_partition_by_minor) { + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + d_edgelist_weights->begin(), + local_edge_partition_include_minor_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); } else { - if (d_edgelist_edge_types) { - result = cugraph::groupby_and_count( - pair_first, - pair_first + d_edgelist_majors.size(), - thrust::make_zip_iterator(d_edgelist_weights->begin(), d_edgelist_edge_types->begin()), - local_edge_and_vertex_partition_id_pair_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - result = cugraph::groupby_and_count(pair_first, - pair_first + d_edgelist_majors.size(), - d_edgelist_weights->begin(), - local_edge_and_vertex_partition_id_pair_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + d_edgelist_weights->begin(), + local_edge_partition_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); } - } else { - if (d_edgelist_edge_ids) { - if (d_edgelist_edge_types) { - result = cugraph::groupby_and_count( - pair_first, - pair_first + d_edgelist_majors.size(), - thrust::make_zip_iterator(d_edgelist_edge_ids->begin(), d_edgelist_edge_types->begin()), - local_edge_and_vertex_partition_id_pair_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - result = cugraph::groupby_and_count(pair_first, - pair_first + d_edgelist_majors.size(), - d_edgelist_edge_ids->begin(), - local_edge_and_vertex_partition_id_pair_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } + } else if (d_edgelist_edge_ids) { + if (groupby_and_count_local_partition_by_minor) { + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + d_edgelist_edge_ids->begin(), + local_edge_partition_include_minor_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); } else { - if (d_edgelist_edge_types) { - result = cugraph::groupby_and_count(pair_first, - pair_first + d_edgelist_majors.size(), - d_edgelist_edge_types->begin(), - local_edge_and_vertex_partition_id_pair_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - result = cugraph::groupby_and_count(pair_first, - pair_first + d_edgelist_majors.size(), - local_edge_and_vertex_partition_id_pair_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + d_edgelist_edge_ids->begin(), + local_edge_partition_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); } - } - } else { - auto local_edge_partition_id_op = - [key_func = - cugraph::detail::compute_local_edge_partition_id_from_ext_edge_endpoints_t{ - comm_size, major_comm_size, minor_comm_size}] __device__(auto pair) { - return key_func(pair); - }; - - if (d_edgelist_weights) { - if (d_edgelist_edge_ids) { - if (d_edgelist_edge_types) { - result = - cugraph::groupby_and_count(pair_first, - pair_first + d_edgelist_majors.size(), - thrust::make_zip_iterator(d_edgelist_weights->begin(), - d_edgelist_edge_ids->begin(), - d_edgelist_edge_types->begin()), - local_edge_partition_id_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - result = cugraph::groupby_and_count( - pair_first, - pair_first + d_edgelist_majors.size(), - thrust::make_zip_iterator(d_edgelist_weights->begin(), d_edgelist_edge_ids->begin()), - local_edge_partition_id_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } + } else if (d_edgelist_edge_types) { + if (groupby_and_count_local_partition_by_minor) { + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + d_edgelist_edge_types->begin(), + local_edge_partition_include_minor_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); } else { - if (d_edgelist_edge_types) { - result = cugraph::groupby_and_count( - pair_first, - pair_first + d_edgelist_majors.size(), - thrust::make_zip_iterator(d_edgelist_weights->begin(), d_edgelist_edge_types->begin()), - local_edge_partition_id_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - result = cugraph::groupby_and_count(pair_first, - pair_first + d_edgelist_majors.size(), - d_edgelist_weights->begin(), - local_edge_partition_id_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + d_edgelist_edge_types->begin(), + local_edge_partition_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); } - } else { - if (d_edgelist_edge_ids) { - if (d_edgelist_edge_types) { - result = cugraph::groupby_and_count( - pair_first, - pair_first + d_edgelist_majors.size(), - thrust::make_zip_iterator(d_edgelist_edge_ids->begin(), d_edgelist_edge_types->begin()), - local_edge_partition_id_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - result = cugraph::groupby_and_count(pair_first, - pair_first + d_edgelist_majors.size(), - d_edgelist_edge_ids->begin(), - local_edge_partition_id_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } + } else if (d_edgelist_edge_start_times) { + if (groupby_and_count_local_partition_by_minor) { + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + d_edgelist_edge_start_times->begin(), + local_edge_partition_include_minor_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } else { + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + d_edgelist_edge_start_times->begin(), + local_edge_partition_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } + } else if (d_edgelist_edge_end_times) { + if (groupby_and_count_local_partition_by_minor) { + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + d_edgelist_edge_end_times->begin(), + local_edge_partition_include_minor_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); } else { - if (d_edgelist_edge_types) { - result = cugraph::groupby_and_count(pair_first, - pair_first + d_edgelist_majors.size(), - d_edgelist_edge_types->begin(), - local_edge_partition_id_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - result = cugraph::groupby_and_count(pair_first, - pair_first + d_edgelist_majors.size(), - local_edge_partition_id_op, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + d_edgelist_edge_end_times->begin(), + local_edge_partition_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); } } + } else { + rmm::device_uvector property_position(d_edgelist_majors.size(), handle.get_stream()); + detail::sequence_fill( + handle.get_stream(), property_position.data(), property_position.size(), edge_t{0}); + + if (groupby_and_count_local_partition_by_minor) { + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + property_position.begin(), + local_edge_partition_include_minor_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } else { + result = cugraph::groupby_and_count(pair_first, + pair_first + d_edgelist_majors.size(), + property_position.begin(), + local_edge_partition_op, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } + + if (d_edgelist_weights) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + d_edgelist_weights->begin(), + tmp.begin()); + + d_edgelist_weights = std::move(tmp); + } + + if (d_edgelist_edge_ids) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + d_edgelist_edge_ids->begin(), + tmp.begin()); + + d_edgelist_edge_ids = std::move(tmp); + } + + if (d_edgelist_edge_types) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + d_edgelist_edge_types->begin(), + tmp.begin()); + + d_edgelist_edge_types = std::move(tmp); + } + + if (d_edgelist_edge_start_times) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + d_edgelist_edge_start_times->begin(), + tmp.begin()); + + d_edgelist_edge_start_times = std::move(tmp); + } + + if (d_edgelist_edge_end_times) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + d_edgelist_edge_end_times->begin(), + tmp.begin()); + + d_edgelist_edge_end_times = std::move(tmp); + } } return result; diff --git a/cpp/src/detail/groupby_and_count_mg_v32_e32.cu b/cpp/src/detail/groupby_and_count_mg_v32_e32.cu index 9f07585c202..6177707a3b9 100644 --- a/cpp/src/detail/groupby_and_count_mg_v32_e32.cu +++ b/cpp/src/detail/groupby_and_count_mg_v32_e32.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,6 +42,8 @@ template rmm::device_uvector groupby_and_count_edgelist_by_local_partiti std::optional>& d_edgelist_weights, std::optional>& d_edgelist_edge_ids, std::optional>& d_edgelist_edge_types, + std::optional>& d_edgelist_edge_start_times, + std::optional>& d_edgelist_edge_end_times, bool groupby_and_counts_local_partition); template rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( @@ -51,6 +53,30 @@ template rmm::device_uvector groupby_and_count_edgelist_by_local_partiti std::optional>& d_edgelist_weights, std::optional>& d_edgelist_edge_ids, std::optional>& d_edgelist_edge_types, + std::optional>& d_edgelist_edge_start_times, + std::optional>& d_edgelist_edge_end_times, + bool groupby_and_counts_local_partition); + +template rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( + raft::handle_t const& handle, + rmm::device_uvector& d_edgelist_majors, + rmm::device_uvector& d_edgelist_minors, + std::optional>& d_edgelist_weights, + std::optional>& d_edgelist_edge_ids, + std::optional>& d_edgelist_edge_types, + std::optional>& d_edgelist_edge_start_times, + std::optional>& d_edgelist_edge_end_times, + bool groupby_and_counts_local_partition); + +template rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( + raft::handle_t const& handle, + rmm::device_uvector& d_edgelist_majors, + rmm::device_uvector& d_edgelist_minors, + std::optional>& d_edgelist_weights, + std::optional>& d_edgelist_edge_ids, + std::optional>& d_edgelist_edge_types, + std::optional>& d_edgelist_edge_start_times, + std::optional>& d_edgelist_edge_end_times, bool groupby_and_counts_local_partition); } // namespace detail diff --git a/cpp/src/detail/groupby_and_count_mg_v64_e64.cu b/cpp/src/detail/groupby_and_count_mg_v64_e64.cu index edbb14346cf..a5411bb9ede 100644 --- a/cpp/src/detail/groupby_and_count_mg_v64_e64.cu +++ b/cpp/src/detail/groupby_and_count_mg_v64_e64.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,6 +42,8 @@ template rmm::device_uvector groupby_and_count_edgelist_by_local_partiti std::optional>& d_edgelist_weights, std::optional>& d_edgelist_edge_ids, std::optional>& d_edgelist_edge_types, + std::optional>& d_edgelist_edge_start_times, + std::optional>& d_edgelist_edge_end_times, bool groupby_and_counts_local_partition); template rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( @@ -51,6 +53,30 @@ template rmm::device_uvector groupby_and_count_edgelist_by_local_partiti std::optional>& d_edgelist_weights, std::optional>& d_edgelist_edge_ids, std::optional>& d_edgelist_edge_types, + std::optional>& d_edgelist_edge_start_times, + std::optional>& d_edgelist_edge_end_times, + bool groupby_and_counts_local_partition); + +template rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( + raft::handle_t const& handle, + rmm::device_uvector& d_edgelist_majors, + rmm::device_uvector& d_edgelist_minors, + std::optional>& d_edgelist_weights, + std::optional>& d_edgelist_edge_ids, + std::optional>& d_edgelist_edge_types, + std::optional>& d_edgelist_edge_start_times, + std::optional>& d_edgelist_edge_end_times, + bool groupby_and_counts_local_partition); + +template rmm::device_uvector groupby_and_count_edgelist_by_local_partition_id( + raft::handle_t const& handle, + rmm::device_uvector& d_edgelist_majors, + rmm::device_uvector& d_edgelist_minors, + std::optional>& d_edgelist_weights, + std::optional>& d_edgelist_edge_ids, + std::optional>& d_edgelist_edge_types, + std::optional>& d_edgelist_edge_start_times, + std::optional>& d_edgelist_edge_end_times, bool groupby_and_counts_local_partition); } // namespace detail diff --git a/cpp/src/link_prediction/similarity_impl.cuh b/cpp/src/link_prediction/similarity_impl.cuh index 00f73b5c263..cc1db0a37d2 100644 --- a/cpp/src/link_prediction/similarity_impl.cuh +++ b/cpp/src/link_prediction/similarity_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024, NVIDIA CORPORATION. + * Copyright (c) 2022-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -421,17 +421,21 @@ all_pairs_similarity(raft::handle_t const& handle, // shuffle vertex pairs auto vertex_partition_range_lasts = graph_view.vertex_partition_range_lasts(); - std::tie(v1, v2, std::ignore, std::ignore, std::ignore, std::ignore) = + std::tie( + v1, v2, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) = detail::shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + int32_t, + int32_t>( handle, std::move(v1), std::move(v2), std::nullopt, std::nullopt, std::nullopt, + std::nullopt, + std::nullopt, vertex_partition_range_lasts); } @@ -607,17 +611,21 @@ all_pairs_similarity(raft::handle_t const& handle, // shuffle vertex pairs auto vertex_partition_range_lasts = graph_view.vertex_partition_range_lasts(); - std::tie(v1, v2, std::ignore, std::ignore, std::ignore, std::ignore) = + std::tie( + v1, v2, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) = detail::shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + int32_t, + int32_t>( handle, std::move(v1), std::move(v2), std::nullopt, std::nullopt, std::nullopt, + std::nullopt, + std::nullopt, vertex_partition_range_lasts); } diff --git a/cpp/src/sampling/negative_sampling_impl.cuh b/cpp/src/sampling/negative_sampling_impl.cuh index 93bb03077bc..541eda67860 100644 --- a/cpp/src/sampling/negative_sampling_impl.cuh +++ b/cpp/src/sampling/negative_sampling_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, NVIDIA CORPORATION. + * Copyright (c) 2024-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -306,10 +306,18 @@ std::tuple, rmm::device_uvector> negativ if constexpr (multi_gpu) { auto vertex_partition_range_lasts = graph_view.vertex_partition_range_lasts(); - std::tie(batch_src, batch_dst, std::ignore, std::ignore, std::ignore, std::ignore) = + std::tie(batch_src, + batch_dst, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore) = detail::shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( handle, std::move(batch_src), @@ -317,6 +325,8 @@ std::tuple, rmm::device_uvector> negativ std::nullopt, std::nullopt, std::nullopt, + std::nullopt, + std::nullopt, vertex_partition_range_lasts); } diff --git a/cpp/src/sampling/neighbor_sampling_impl.hpp b/cpp/src/sampling/neighbor_sampling_impl.hpp index 4363005500c..bbc0fbc17af 100644 --- a/cpp/src/sampling/neighbor_sampling_impl.hpp +++ b/cpp/src/sampling/neighbor_sampling_impl.hpp @@ -202,8 +202,8 @@ neighbor_sample_impl(raft::handle_t const& handle, ? std::make_optional(rmm::device_uvector(0, handle.get_stream())) : std::nullopt; - for (auto edge_type_id = 0; edge_type_id < num_edge_types; edge_type_id++) { - auto k_level = fan_out[(hop * num_edge_types) + edge_type_id]; + for (edge_type_t edge_type = 0; edge_type < num_edge_types; edge_type++) { + auto k_level = fan_out[(hop * num_edge_types) + edge_type]; rmm::device_uvector srcs(0, handle.get_stream()); rmm::device_uvector dsts(0, handle.get_stream()); std::optional> weights{std::nullopt}; @@ -212,7 +212,7 @@ neighbor_sample_impl(raft::handle_t const& handle, std::optional> labels{std::nullopt}; if (num_edge_types > 1) { - modified_graph_view.attach_edge_mask(edge_masks_vector[edge_type_id].view()); + modified_graph_view.attach_edge_mask(edge_masks_vector[edge_type].view()); } if (k_level > 0) { diff --git a/cpp/src/structure/coarsen_graph_impl.cuh b/cpp/src/structure/coarsen_graph_impl.cuh index ed0a70e570f..ba965fe6f56 100644 --- a/cpp/src/structure/coarsen_graph_impl.cuh +++ b/cpp/src/structure/coarsen_graph_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2024, NVIDIA CORPORATION. + * Copyright (c) 2020-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -349,17 +349,26 @@ coarsen_graph(raft::handle_t const& handle, // 1-2. globally shuffle - std::tie( - edgelist_majors, edgelist_minors, edgelist_weights, std::ignore, std::ignore, std::ignore) = + std::tie(edgelist_majors, + edgelist_minors, + edgelist_weights, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore) = cugraph::detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, edge_t, weight_t, + int32_t, int32_t>(handle, std::move(edgelist_majors), std::move(edgelist_minors), std::move(edgelist_weights), std::nullopt, + std::nullopt, + std::nullopt, std::nullopt); // 1-3. groupby and coarsen again @@ -477,16 +486,21 @@ coarsen_graph(raft::handle_t const& handle, reversed_edgelist_weights, std::ignore, std::ignore, + std::ignore, + std::ignore, std::ignore) = cugraph::detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, edge_t, weight_t, + int32_t, int32_t>(handle, std::move(reversed_edgelist_majors), std::move(reversed_edgelist_minors), std::move(reversed_edgelist_weights), std::nullopt, + std::nullopt, + std::nullopt, std::nullopt); auto output_offset = concatenated_edgelist_majors.size(); @@ -551,13 +565,7 @@ coarsen_graph(raft::handle_t const& handle, edge_weights{std::nullopt}; std::optional> renumber_map{std::nullopt}; std::tie(coarsened_graph, edge_weights, std::ignore, std::ignore, renumber_map) = - create_graph_from_edgelist( + create_graph_from_edgelist( handle, std::move(unique_labels), store_transposed ? std::move(concatenated_edgelist_minors) @@ -714,13 +722,7 @@ coarsen_graph(raft::handle_t const& handle, edge_weights{std::nullopt}; std::optional> renumber_map{std::nullopt}; std::tie(coarsened_graph, edge_weights, std::ignore, std::ignore, renumber_map) = - create_graph_from_edgelist( + create_graph_from_edgelist( handle, std::optional>{std::move(vertices)}, store_transposed ? std::move(coarsened_edgelist_minors) diff --git a/cpp/src/structure/create_graph_from_edgelist_impl.cuh b/cpp/src/structure/create_graph_from_edgelist_impl.cuh index cd98db31654..85de59bf403 100644 --- a/cpp/src/structure/create_graph_from_edgelist_impl.cuh +++ b/cpp/src/structure/create_graph_from_edgelist_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, 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,7 @@ */ #pragma once +#include "cugraph/edge_partition_view.hpp" #include "detail/graph_partition_utils.cuh" #include "structure/detail/structure_utils.cuh" @@ -259,9 +260,23 @@ bool check_symmetric(raft::handle_t const& handle, handle.get_thrust_policy(), org_srcs.begin(), org_srcs.end(), symmetrized_srcs.begin()); thrust::copy( handle.get_thrust_policy(), org_dsts.begin(), org_dsts.end(), symmetrized_dsts.begin()); - std::tie(symmetrized_srcs, symmetrized_dsts, std::ignore) = - symmetrize_edgelist( - handle, std::move(symmetrized_srcs), std::move(symmetrized_dsts), std::nullopt, true); + std::tie(symmetrized_srcs, + symmetrized_dsts, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore) = + symmetrize_edgelist( + handle, + std::move(symmetrized_srcs), + std::move(symmetrized_dsts), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + true); if (org_srcs.size() != symmetrized_srcs.size()) { return false; } @@ -382,6 +397,7 @@ std::vector> split_edge_chunk_elements_to_local_edge_part auto output_offset = edge_partition_intra_partition_segment_offset_vectors[i][j] + edge_partition_intra_segment_copy_output_displacement_vectors[i][j * num_chunks + k]; + thrust::copy(handle.get_thrust_policy(), edgelist_elements[k].begin() + segment_offset, edgelist_elements[k].begin() + (segment_offset + segment_size), @@ -418,8 +434,8 @@ void decompress_vertices(raft::handle_t const& handle, template std::enable_if_t< @@ -429,9 +445,13 @@ std::enable_if_t< std::optional< edge_property_t, weight_t>>, std::optional< - edge_property_t, edge_id_t>>, + edge_property_t, edge_t>>, std::optional< edge_property_t, edge_type_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional< + edge_property_t, edge_time_t>>, std::optional>>> create_graph_from_partitioned_edgelist( raft::handle_t const& handle, @@ -439,8 +459,12 @@ create_graph_from_partitioned_edgelist( std::vector>&& edge_partition_edgelist_srcs, std::vector>&& edge_partition_edgelist_dsts, std::optional>>&& edge_partition_edgelist_weights, - std::optional>>&& edge_partition_edgelist_edge_ids, + std::optional>>&& edge_partition_edgelist_edge_ids, std::optional>>&& edge_partition_edgelist_edge_types, + std::optional>>&& + edge_partition_edgelist_edge_start_times, + std::optional>>&& + edge_partition_edgelist_edge_end_times, std::vector> const& edgelist_intra_partition_segment_offset_vectors, graph_properties_t graph_properties, bool renumber) @@ -478,12 +502,34 @@ create_graph_from_partitioned_edgelist( num_segments_per_vertex_partition > (detail::num_sparse_segments_per_vertex_partition + 2); // 2. sort and compress edge list (COO) to CSR (or CSC) or CSR + DCSR (CSC + DCSC) hybrid + int edge_property_count = 0; + size_t element_size = sizeof(vertex_t) * 2; + + if (edge_partition_edgelist_weights) { + ++edge_property_count; + element_size += sizeof(weight_t); + } + + if (edge_partition_edgelist_edge_ids) { + ++edge_property_count; + element_size += sizeof(edge_t); + } + if (edge_partition_edgelist_edge_types) { + ++edge_property_count; + element_size += sizeof(edge_type_t); + } + if (edge_partition_edgelist_edge_start_times) { + ++edge_property_count; + element_size += sizeof(edge_time_t); + } + if (edge_partition_edgelist_edge_end_times) { + ++edge_property_count; + element_size += sizeof(edge_time_t); + } + + if (edge_property_count > 1) { element_size = sizeof(vertex_t) * 2 + sizeof(size_t); } auto total_global_mem = handle.get_device_properties().totalGlobalMem; - size_t element_size = sizeof(vertex_t) * 2; - if (edge_partition_edgelist_weights) { element_size += sizeof(weight_t); } - if (edge_partition_edgelist_edge_ids) { element_size += sizeof(edge_id_t); } - if (edge_partition_edgelist_edge_types) { element_size += sizeof(edge_type_t); } auto constexpr mem_frugal_ratio = 0.05; // if the expected temporary buffer size exceeds the mem_frugal_ratio of the // total_global_mem, switch to the memory frugal approach @@ -493,9 +539,13 @@ create_graph_from_partitioned_edgelist( std::vector> edge_partition_offsets; std::vector> edge_partition_indices; std::optional>> edge_partition_weights{std::nullopt}; - std::optional>> edge_partition_edge_ids{std::nullopt}; + std::optional>> edge_partition_edge_ids{std::nullopt}; std::optional>> edge_partition_edge_types{ std::nullopt}; + std::optional>> edge_partition_edge_start_times{ + std::nullopt}; + std::optional>> edge_partition_edge_end_times{ + std::nullopt}; std::optional>> edge_partition_dcs_nzd_vertices{ std::nullopt}; @@ -506,13 +556,21 @@ create_graph_from_partitioned_edgelist( (*edge_partition_weights).reserve(edge_partition_edgelist_srcs.size()); } if (edge_partition_edgelist_edge_ids) { - edge_partition_edge_ids = std::vector>{}; + edge_partition_edge_ids = std::vector>{}; (*edge_partition_edge_ids).reserve(edge_partition_edgelist_srcs.size()); } if (edge_partition_edgelist_edge_types) { edge_partition_edge_types = std::vector>{}; (*edge_partition_edge_types).reserve(edge_partition_edgelist_srcs.size()); } + if (edge_partition_edgelist_edge_start_times) { + edge_partition_edge_start_times = std::vector>{}; + (*edge_partition_edge_start_times).reserve(edge_partition_edgelist_srcs.size()); + } + if (edge_partition_edgelist_edge_end_times) { + edge_partition_edge_end_times = std::vector>{}; + (*edge_partition_edge_end_times).reserve(edge_partition_edgelist_srcs.size()); + } if (use_dcs) { edge_partition_dcs_nzd_vertices = std::vector>{}; (*edge_partition_dcs_nzd_vertices).reserve(edge_partition_edgelist_srcs.size()); @@ -524,8 +582,10 @@ create_graph_from_partitioned_edgelist( rmm::device_uvector offsets(size_t{0}, handle.get_stream()); rmm::device_uvector indices(size_t{0}, handle.get_stream()); std::optional> weights{std::nullopt}; - std::optional> edge_ids{std::nullopt}; + std::optional> edge_ids{std::nullopt}; std::optional> edge_types{std::nullopt}; + std::optional> edge_start_times{std::nullopt}; + std::optional> edge_end_times{std::nullopt}; std::optional> dcs_nzd_vertices{std::nullopt}; auto major_hypersparse_first = use_dcs @@ -534,139 +594,151 @@ create_graph_from_partitioned_edgelist( meta.edge_partition_segment_offsets[num_segments_per_vertex_partition * i + detail::num_sparse_segments_per_vertex_partition]) : std::nullopt; - if (edge_partition_edgelist_weights) { - if (edge_partition_edgelist_edge_ids) { - if (edge_partition_edgelist_edge_types) { - std::forward_as_tuple( - offsets, indices, std::tie(weights, edge_ids, edge_types), dcs_nzd_vertices) = - detail::sort_and_compress_edgelist, - store_transposed>( - std::move(edge_partition_edgelist_srcs[i]), - std::move(edge_partition_edgelist_dsts[i]), - std::make_tuple(std::move((*edge_partition_edgelist_weights)[i]), - std::move((*edge_partition_edgelist_edge_ids)[i]), - std::move((*edge_partition_edgelist_edge_types)[i])), - major_range_first, - major_hypersparse_first, - major_range_last, - minor_range_first, - minor_range_last, - mem_frugal_threshold, - handle.get_stream()); - } else { - std::forward_as_tuple(offsets, indices, std::tie(weights, edge_ids), dcs_nzd_vertices) = - detail::sort_and_compress_edgelist, - store_transposed>( - std::move(edge_partition_edgelist_srcs[i]), - std::move(edge_partition_edgelist_dsts[i]), - std::make_tuple(std::move((*edge_partition_edgelist_weights)[i]), - std::move((*edge_partition_edgelist_edge_ids)[i])), - major_range_first, - major_hypersparse_first, - major_range_last, - minor_range_first, - minor_range_last, - mem_frugal_threshold, - handle.get_stream()); - } - } else { - if (edge_partition_edgelist_edge_types) { - std::forward_as_tuple(offsets, indices, std::tie(weights, edge_types), dcs_nzd_vertices) = - detail::sort_and_compress_edgelist, - store_transposed>( - std::move(edge_partition_edgelist_srcs[i]), - std::move(edge_partition_edgelist_dsts[i]), - std::make_tuple(std::move((*edge_partition_edgelist_weights)[i]), - std::move((*edge_partition_edgelist_edge_types)[i])), - major_range_first, - major_hypersparse_first, - major_range_last, - minor_range_first, - minor_range_last, - mem_frugal_threshold, - handle.get_stream()); - } else { - std::forward_as_tuple(offsets, indices, weights, dcs_nzd_vertices) = - detail::sort_and_compress_edgelist( - std::move(edge_partition_edgelist_srcs[i]), - std::move(edge_partition_edgelist_dsts[i]), - std::move((*edge_partition_edgelist_weights)[i]), - major_range_first, - major_hypersparse_first, - major_range_last, - minor_range_first, - minor_range_last, - mem_frugal_threshold, - handle.get_stream()); - } + + if (edge_property_count == 0) { + std::tie(offsets, indices, dcs_nzd_vertices) = + detail::sort_and_compress_edgelist( + std::move(edge_partition_edgelist_srcs[i]), + std::move(edge_partition_edgelist_dsts[i]), + major_range_first, + major_hypersparse_first, + major_range_last, + minor_range_first, + minor_range_last, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_property_count == 1) { + if (edge_partition_edgelist_weights) { + std::tie(offsets, indices, weights, dcs_nzd_vertices) = + detail::sort_and_compress_edgelist( + std::move(edge_partition_edgelist_srcs[i]), + std::move(edge_partition_edgelist_dsts[i]), + std::move((*edge_partition_edgelist_weights)[i]), + major_range_first, + major_hypersparse_first, + major_range_last, + minor_range_first, + minor_range_last, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_partition_edgelist_edge_ids) { + std::tie(offsets, indices, edge_ids, dcs_nzd_vertices) = + detail::sort_and_compress_edgelist( + std::move(edge_partition_edgelist_srcs[i]), + std::move(edge_partition_edgelist_dsts[i]), + std::move((*edge_partition_edgelist_edge_ids)[i]), + major_range_first, + major_hypersparse_first, + major_range_last, + minor_range_first, + minor_range_last, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_partition_edgelist_edge_types) { + std::tie(offsets, indices, edge_types, dcs_nzd_vertices) = + detail::sort_and_compress_edgelist( + std::move(edge_partition_edgelist_srcs[i]), + std::move(edge_partition_edgelist_dsts[i]), + std::move((*edge_partition_edgelist_edge_types)[i]), + major_range_first, + major_hypersparse_first, + major_range_last, + minor_range_first, + minor_range_last, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_partition_edgelist_edge_start_times) { + std::tie(offsets, indices, edge_start_times, dcs_nzd_vertices) = + detail::sort_and_compress_edgelist( + std::move(edge_partition_edgelist_srcs[i]), + std::move(edge_partition_edgelist_dsts[i]), + std::move((*edge_partition_edgelist_edge_start_times)[i]), + major_range_first, + major_hypersparse_first, + major_range_last, + minor_range_first, + minor_range_last, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_partition_edgelist_edge_end_times) { + std::tie(offsets, indices, edge_end_times, dcs_nzd_vertices) = + detail::sort_and_compress_edgelist( + std::move(edge_partition_edgelist_srcs[i]), + std::move(edge_partition_edgelist_dsts[i]), + std::move((*edge_partition_edgelist_edge_end_times)[i]), + major_range_first, + major_hypersparse_first, + major_range_last, + minor_range_first, + minor_range_last, + mem_frugal_threshold, + handle.get_stream()); } } else { + rmm::device_uvector property_position(edge_partition_edgelist_srcs[i].size(), + handle.get_stream()); + detail::sequence_fill( + handle.get_stream(), property_position.data(), property_position.size(), edge_t{0}); + + std::tie(offsets, indices, property_position, dcs_nzd_vertices) = + detail::sort_and_compress_edgelist( + std::move(edge_partition_edgelist_srcs[i]), + std::move(edge_partition_edgelist_dsts[i]), + std::move(property_position), + major_range_first, + major_hypersparse_first, + major_range_last, + minor_range_first, + minor_range_last, + mem_frugal_threshold, + handle.get_stream()); + + if (edge_partition_edgelist_weights) { + weights = rmm::device_uvector(property_position.size(), handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + (*edge_partition_edgelist_weights)[i].begin(), + weights->begin()); + } + if (edge_partition_edgelist_edge_ids) { - if (edge_partition_edgelist_edge_types) { - std::forward_as_tuple( - offsets, indices, std::tie(edge_ids, edge_types), dcs_nzd_vertices) = - detail::sort_and_compress_edgelist, - store_transposed>( - std::move(edge_partition_edgelist_srcs[i]), - std::move(edge_partition_edgelist_dsts[i]), - std::make_tuple(std::move((*edge_partition_edgelist_edge_ids)[i]), - std::move((*edge_partition_edgelist_edge_types)[i])), - major_range_first, - major_hypersparse_first, - major_range_last, - minor_range_first, - minor_range_last, - mem_frugal_threshold, - handle.get_stream()); - } else { - std::forward_as_tuple(offsets, indices, edge_ids, dcs_nzd_vertices) = - detail::sort_and_compress_edgelist( - std::move(edge_partition_edgelist_srcs[i]), - std::move(edge_partition_edgelist_dsts[i]), - std::move((*edge_partition_edgelist_edge_ids)[i]), - major_range_first, - major_hypersparse_first, - major_range_last, - minor_range_first, - minor_range_last, - mem_frugal_threshold, - handle.get_stream()); - } - } else { - if (edge_partition_edgelist_edge_types) { - std::forward_as_tuple(offsets, indices, edge_types, dcs_nzd_vertices) = - detail::sort_and_compress_edgelist( - std::move(edge_partition_edgelist_srcs[i]), - std::move(edge_partition_edgelist_dsts[i]), - std::move((*edge_partition_edgelist_edge_types)[i]), - major_range_first, - major_hypersparse_first, - major_range_last, - minor_range_first, - minor_range_last, - mem_frugal_threshold, - handle.get_stream()); - } else { - std::forward_as_tuple(offsets, indices, dcs_nzd_vertices) = - detail::sort_and_compress_edgelist( - std::move(edge_partition_edgelist_srcs[i]), - std::move(edge_partition_edgelist_dsts[i]), - major_range_first, - major_hypersparse_first, - major_range_last, - minor_range_first, - minor_range_last, - mem_frugal_threshold, - handle.get_stream()); - } + edge_ids = rmm::device_uvector(property_position.size(), handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + (*edge_partition_edgelist_edge_ids)[i].begin(), + edge_ids->begin()); + } + + if (edge_partition_edgelist_edge_types) { + edge_types = + rmm::device_uvector(property_position.size(), handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + (*edge_partition_edgelist_edge_types)[i].begin(), + edge_types->begin()); + } + + if (edge_partition_edgelist_edge_start_times) { + edge_start_times = + rmm::device_uvector(property_position.size(), handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + (*edge_partition_edgelist_edge_start_times)[i].begin(), + edge_start_times->begin()); + } + + if (edge_partition_edgelist_edge_end_times) { + edge_end_times = + rmm::device_uvector(property_position.size(), handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + (*edge_partition_edgelist_edge_end_times)[i].begin(), + edge_end_times->begin()); } } @@ -677,6 +749,13 @@ create_graph_from_partitioned_edgelist( if (edge_partition_edge_types) { (*edge_partition_edge_types).push_back(std::move(*edge_types)); } + if (edge_partition_edge_start_times) { + (*edge_partition_edge_start_times).push_back(std::move(*edge_start_times)); + } + if (edge_partition_edge_end_times) { + (*edge_partition_edge_end_times).push_back(std::move(*edge_end_times)); + } + if (edge_partition_dcs_nzd_vertices) { (*edge_partition_dcs_nzd_vertices).push_back(std::move(*dcs_nzd_vertices)); } @@ -685,85 +764,111 @@ create_graph_from_partitioned_edgelist( // 3. segmented sort neighbors for (size_t i = 0; i < edge_partition_offsets.size(); ++i) { - if (edge_partition_weights) { - if (edge_partition_edge_ids) { - if (edge_partition_edge_types) { - detail::sort_adjacency_list( - handle, - raft::device_span(edge_partition_offsets[i].data(), - edge_partition_offsets[i].size()), - edge_partition_indices[i].begin(), - edge_partition_indices[i].end(), - thrust::make_zip_iterator((*edge_partition_weights)[i].begin(), - (*edge_partition_edge_ids)[i].begin(), - (*edge_partition_edge_types)[i].begin())); - } else { - detail::sort_adjacency_list( - handle, - raft::device_span(edge_partition_offsets[i].data(), - edge_partition_offsets[i].size()), - edge_partition_indices[i].begin(), - edge_partition_indices[i].end(), - thrust::make_zip_iterator((*edge_partition_weights)[i].begin(), - (*edge_partition_edge_ids)[i].begin())); - } - } else { - if (edge_partition_edge_types) { - detail::sort_adjacency_list( - handle, - raft::device_span(edge_partition_offsets[i].data(), - edge_partition_offsets[i].size()), - edge_partition_indices[i].begin(), - edge_partition_indices[i].end(), - thrust::make_zip_iterator((*edge_partition_weights)[i].begin(), - (*edge_partition_edge_types)[i].begin())); - } else { - detail::sort_adjacency_list( - handle, - raft::device_span(edge_partition_offsets[i].data(), - edge_partition_offsets[i].size()), - edge_partition_indices[i].begin(), - edge_partition_indices[i].end(), - (*edge_partition_weights)[i].begin()); - } + if (edge_property_count == 0) { + detail::sort_adjacency_list(handle, + raft::device_span(edge_partition_offsets[i].data(), + edge_partition_offsets[i].size()), + edge_partition_indices[i].begin(), + edge_partition_indices[i].end()); + } else if (edge_property_count == 1) { + if (edge_partition_edgelist_weights) { + detail::sort_adjacency_list( + handle, + raft::device_span(edge_partition_offsets[i].data(), + edge_partition_offsets[i].size()), + edge_partition_indices[i].begin(), + edge_partition_indices[i].end(), + (*edge_partition_weights)[i].begin()); + } else if (edge_partition_edgelist_edge_ids) { + detail::sort_adjacency_list( + handle, + raft::device_span(edge_partition_offsets[i].data(), + edge_partition_offsets[i].size()), + edge_partition_indices[i].begin(), + edge_partition_indices[i].end(), + (*edge_partition_edge_ids)[i].begin()); + } else if (edge_partition_edgelist_edge_types) { + detail::sort_adjacency_list( + handle, + raft::device_span(edge_partition_offsets[i].data(), + edge_partition_offsets[i].size()), + edge_partition_indices[i].begin(), + edge_partition_indices[i].end(), + (*edge_partition_edge_types)[i].begin()); + } else if (edge_partition_edgelist_edge_start_times) { + detail::sort_adjacency_list( + handle, + raft::device_span(edge_partition_offsets[i].data(), + edge_partition_offsets[i].size()), + edge_partition_indices[i].begin(), + edge_partition_indices[i].end(), + (*edge_partition_edge_start_times)[i].begin()); + } else if (edge_partition_edgelist_edge_end_times) { + detail::sort_adjacency_list( + handle, + raft::device_span(edge_partition_offsets[i].data(), + edge_partition_offsets[i].size()), + edge_partition_indices[i].begin(), + edge_partition_indices[i].end(), + (*edge_partition_edge_end_times)[i].begin()); } } else { - if (edge_partition_edge_ids) { - if (edge_partition_edge_types) { - detail::sort_adjacency_list( - handle, - raft::device_span(edge_partition_offsets[i].data(), - edge_partition_offsets[i].size()), - edge_partition_indices[i].begin(), - edge_partition_indices[i].end(), - thrust::make_zip_iterator((*edge_partition_edge_ids)[i].begin(), - (*edge_partition_edge_types)[i].begin())); - } else { - detail::sort_adjacency_list( - handle, - raft::device_span(edge_partition_offsets[i].data(), - edge_partition_offsets[i].size()), - edge_partition_indices[i].begin(), - edge_partition_indices[i].end(), - thrust::make_zip_iterator((*edge_partition_edge_ids)[i].begin())); - } - } else { - if (edge_partition_edge_types) { - detail::sort_adjacency_list( - handle, - raft::device_span(edge_partition_offsets[i].data(), - edge_partition_offsets[i].size()), - edge_partition_indices[i].begin(), - edge_partition_indices[i].end(), - thrust::make_zip_iterator((*edge_partition_edge_types)[i].begin())); - } else { - detail::sort_adjacency_list( - handle, - raft::device_span(edge_partition_offsets[i].data(), - edge_partition_offsets[i].size()), - edge_partition_indices[i].begin(), - edge_partition_indices[i].end()); - } + rmm::device_uvector property_position(edge_partition_indices[i].size(), + handle.get_stream()); + detail::sequence_fill( + handle.get_stream(), property_position.data(), property_position.size(), edge_t{0}); + + detail::sort_adjacency_list(handle, + raft::device_span(edge_partition_offsets[i].data(), + edge_partition_offsets[i].size()), + edge_partition_indices[i].begin(), + edge_partition_indices[i].end(), + property_position.begin()); + + if (edge_partition_edgelist_weights) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + (*edge_partition_edgelist_weights)[i].begin(), + tmp.begin()); + (*edge_partition_edgelist_weights)[i] = std::move(tmp); + } + if (edge_partition_edgelist_edge_ids) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + (*edge_partition_edgelist_edge_ids)[i].begin(), + tmp.begin()); + (*edge_partition_edgelist_edge_ids)[i] = std::move(tmp); + } + if (edge_partition_edgelist_edge_types) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + (*edge_partition_edgelist_edge_types)[i].begin(), + tmp.begin()); + (*edge_partition_edgelist_edge_types)[i] = std::move(tmp); + } + if (edge_partition_edgelist_edge_end_times) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + (*edge_partition_edgelist_edge_end_times)[i].begin(), + tmp.begin()); + (*edge_partition_edgelist_edge_end_times)[i] = std::move(tmp); + } + if (edge_partition_edgelist_edge_end_times) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + (*edge_partition_edgelist_edge_end_times)[i].begin(), + tmp.begin()); + (*edge_partition_edgelist_edge_end_times)[i] = std::move(tmp); } } } @@ -778,10 +883,10 @@ create_graph_from_partitioned_edgelist( std::move(*edge_partition_weights)); } - std::optional, edge_id_t>> + std::optional, edge_t>> edge_ids{std::nullopt}; if (edge_partition_edge_ids) { - edge_ids = edge_property_t, edge_id_t>( + edge_ids = edge_property_t, edge_t>( std::move(*edge_partition_edge_ids)); } @@ -794,6 +899,24 @@ create_graph_from_partitioned_edgelist( std::move(*edge_partition_edge_types)); } + std::optional< + edge_property_t, edge_time_t>> + edge_start_times{std::nullopt}; + if (edge_partition_edge_start_times) { + edge_start_times = + edge_property_t, edge_time_t>( + std::move(*edge_partition_edge_start_times)); + } + + std::optional< + edge_property_t, edge_time_t>> + edge_end_times{std::nullopt}; + if (edge_partition_edge_end_times) { + edge_end_times = + edge_property_t, edge_time_t>( + std::move(*edge_partition_edge_end_times)); + } + return std::make_tuple( cugraph::graph_t( handle, @@ -810,14 +933,16 @@ create_graph_from_partitioned_edgelist( std::move(edge_weights), std::move(edge_ids), std::move(edge_types), + std::move(edge_start_times), + std::move(edge_end_times), std::optional>{std::move(renumber_map_labels)}); } template std::enable_if_t< @@ -827,9 +952,13 @@ std::enable_if_t< std::optional< edge_property_t, weight_t>>, std::optional< - edge_property_t, edge_id_t>>, + edge_property_t, edge_t>>, std::optional< edge_property_t, edge_type_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional< + edge_property_t, edge_time_t>>, std::optional>>> create_graph_from_edgelist_impl( raft::handle_t const& handle, @@ -837,8 +966,10 @@ create_graph_from_edgelist_impl( rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, - std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_ids, std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, graph_properties_t graph_properties, bool renumber, bool do_expensive_check) @@ -859,6 +990,14 @@ create_graph_from_edgelist_impl( CUGRAPH_EXPECTS(!edgelist_edge_types || (edgelist_srcs.size() == (*edgelist_edge_types).size()), "Invalid input arguments: edgelist_edge_types.has_value() is true, " "edgelist_srcs.size() != (*edgelist_edge_types).size()."); + CUGRAPH_EXPECTS( + !edgelist_edge_start_times || (edgelist_srcs.size() == (*edgelist_edge_start_times).size()), + "Invalid input arguments: edgelist_edge_start_times.has_value() is true, " + "edgelist_srcs.size() != (*edgelist_edge_start_times).size()."); + CUGRAPH_EXPECTS( + !edgelist_edge_end_times || (edgelist_srcs.size() == (*edgelist_edge_end_times).size()), + "Invalid input arguments: edgelist_edge_end_times.has_value() is true, " + "edgelist_srcs.size() != (*edgelist_edge_end_times).size()."); CUGRAPH_EXPECTS(renumber, "Invalid input arguments: renumber should be true if multi_gpu is true."); @@ -892,7 +1031,6 @@ create_graph_from_edgelist_impl( // 1. groupby edges to their target local adjacency matrix partition (and further groupby within // the local partition by applying the compute_gpu_id_from_vertex_t to minor vertex IDs). - auto d_edge_counts = cugraph::detail::groupby_and_count_edgelist_by_local_partition_id( handle, store_transposed ? edgelist_dsts : edgelist_srcs, @@ -900,6 +1038,8 @@ create_graph_from_edgelist_impl( edgelist_weights, edgelist_edge_ids, edgelist_edge_types, + edgelist_edge_start_times, + edgelist_edge_end_times, true); std::vector h_edge_counts(d_edge_counts.size()); @@ -924,7 +1064,6 @@ create_graph_from_edgelist_impl( edgelist_displacements.begin() + 1); // 2. split the input edges to local partitions - std::vector> edge_partition_edgelist_srcs{}; edge_partition_edgelist_srcs.reserve(minor_comm_size); for (int i = 0; i < minor_comm_size; ++i) { @@ -968,12 +1107,12 @@ create_graph_from_edgelist_impl( (*edgelist_weights).shrink_to_fit(handle.get_stream()); } - std::optional>> edge_partition_edgelist_edge_ids{}; + std::optional>> edge_partition_edgelist_edge_ids{}; if (edgelist_edge_ids) { - edge_partition_edgelist_edge_ids = std::vector>{}; + edge_partition_edgelist_edge_ids = std::vector>{}; (*edge_partition_edgelist_edge_ids).reserve(minor_comm_size); for (int i = 0; i < minor_comm_size; ++i) { - rmm::device_uvector tmp_edge_ids(edgelist_edge_counts[i], handle.get_stream()); + rmm::device_uvector tmp_edge_ids(edgelist_edge_counts[i], handle.get_stream()); thrust::copy( handle.get_thrust_policy(), (*edgelist_edge_ids).begin() + edgelist_displacements[i], @@ -1002,11 +1141,48 @@ create_graph_from_edgelist_impl( (*edgelist_edge_types).shrink_to_fit(handle.get_stream()); } + std::optional>> + edge_partition_edgelist_edge_start_times{}; + if (edgelist_edge_start_times) { + edge_partition_edgelist_edge_start_times = std::vector>{}; + (*edge_partition_edgelist_edge_start_times).reserve(minor_comm_size); + for (int i = 0; i < minor_comm_size; ++i) { + rmm::device_uvector tmp_edge_start_times(edgelist_edge_counts[i], + handle.get_stream()); + thrust::copy( + handle.get_thrust_policy(), + (*edgelist_edge_start_times).begin() + edgelist_displacements[i], + (*edgelist_edge_start_times).begin() + edgelist_displacements[i] + edgelist_edge_counts[i], + tmp_edge_start_times.begin()); + (*edge_partition_edgelist_edge_start_times).push_back(std::move(tmp_edge_start_times)); + } + (*edgelist_edge_start_times).resize(0, handle.get_stream()); + (*edgelist_edge_start_times).shrink_to_fit(handle.get_stream()); + } + + std::optional>> + edge_partition_edgelist_edge_end_times{}; + if (edgelist_edge_end_times) { + edge_partition_edgelist_edge_end_times = std::vector>{}; + (*edge_partition_edgelist_edge_end_times).reserve(minor_comm_size); + for (int i = 0; i < minor_comm_size; ++i) { + rmm::device_uvector tmp_edge_end_times(edgelist_edge_counts[i], + handle.get_stream()); + thrust::copy( + handle.get_thrust_policy(), + (*edgelist_edge_end_times).begin() + edgelist_displacements[i], + (*edgelist_edge_end_times).begin() + edgelist_displacements[i] + edgelist_edge_counts[i], + tmp_edge_end_times.begin()); + (*edge_partition_edgelist_edge_end_times).push_back(std::move(tmp_edge_end_times)); + } + (*edgelist_edge_end_times).resize(0, handle.get_stream()); + (*edgelist_edge_end_times).shrink_to_fit(handle.get_stream()); + } return create_graph_from_partitioned_edgelist( handle, @@ -1016,6 +1192,8 @@ create_graph_from_edgelist_impl( std::move(edge_partition_edgelist_weights), std::move(edge_partition_edgelist_edge_ids), std::move(edge_partition_edgelist_edge_types), + std::move(edge_partition_edgelist_edge_start_times), + std::move(edge_partition_edgelist_edge_end_times), edgelist_intra_partition_segment_offset_vectors, graph_properties, renumber); @@ -1024,8 +1202,8 @@ create_graph_from_edgelist_impl( template std::enable_if_t< @@ -1035,9 +1213,13 @@ std::enable_if_t< std::optional< edge_property_t, weight_t>>, std::optional< - edge_property_t, edge_id_t>>, + edge_property_t, edge_t>>, std::optional< edge_property_t, edge_type_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional< + edge_property_t, edge_time_t>>, std::optional>>> create_graph_from_edgelist_impl( raft::handle_t const& handle, @@ -1045,8 +1227,10 @@ create_graph_from_edgelist_impl( std::vector>&& edgelist_srcs, std::vector>&& edgelist_dsts, std::optional>>&& edgelist_weights, - std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_ids, std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, graph_properties_t graph_properties, bool renumber, bool do_expensive_check) @@ -1067,6 +1251,14 @@ create_graph_from_edgelist_impl( CUGRAPH_EXPECTS(!edgelist_edge_types || (edgelist_srcs.size() == (*edgelist_edge_types).size()), "Invalid input arguments: edgelist_edge_types.has_value() is true, " "edgelist_srcs.size() != (*edgelist_edge_types).size()."); + CUGRAPH_EXPECTS( + !edgelist_edge_start_times || (edgelist_srcs.size() == (*edgelist_edge_start_times).size()), + "Invalid input arguments: edgelist_edge_start_times.has_value() is true, " + "edgelist_srcs.size() != (*edgelist_edge_start_times).size()."); + CUGRAPH_EXPECTS( + !edgelist_edge_end_times || (edgelist_srcs.size() == (*edgelist_edge_end_times).size()), + "Invalid input arguments: edgelist_edge_end_times.has_value() is true, " + "edgelist_srcs.size() != (*edgelist_edge_end_times).size()."); for (size_t i = 0; i < edgelist_srcs.size(); ++i) { CUGRAPH_EXPECTS(edgelist_srcs[i].size() == edgelist_dsts[i].size(), "Invalid input arguments: edgelist_srcs[i].size() != edgelist_dsts[i].size()."); @@ -1081,6 +1273,14 @@ create_graph_from_edgelist_impl( !edgelist_edge_types || (edgelist_srcs[i].size() == (*edgelist_edge_types)[i].size()), "Invalid input arguments: edgelist_edge_types.has_value() is true, " "edgelist_srcs[i].size() != (*edgelist_edge_types)[i].size()."); + CUGRAPH_EXPECTS(!edgelist_edge_start_times || + (edgelist_srcs[i].size() == (*edgelist_edge_start_times)[i].size()), + "Invalid input arguments: edgelist_edge_start_times.has_value() is true, " + "edgelist_srcs[i].size() != (*edgelist_edge_start_times)[i].size()."); + CUGRAPH_EXPECTS( + !edgelist_edge_end_times || (edgelist_srcs[i].size() == (*edgelist_edge_end_times)[i].size()), + "Invalid input arguments: edgelist_edge_end_times.has_value() is true, " + "edgelist_srcs[i].size() != (*edgelist_edge_end_times)[i].size()."); } CUGRAPH_EXPECTS(renumber, "Invalid input arguments: renumber should be true if multi_gpu is true."); @@ -1154,8 +1354,10 @@ create_graph_from_edgelist_impl( auto total_global_mem = handle.get_device_properties().totalGlobalMem; size_t element_size = sizeof(vertex_t) * 2; if (edgelist_weights) { element_size += sizeof(weight_t); } - if (edgelist_edge_ids) { element_size += sizeof(edge_id_t); } + if (edgelist_edge_ids) { element_size += sizeof(edge_t); } if (edgelist_edge_types) { element_size += sizeof(edge_type_t); } + if (edgelist_edge_start_times) { element_size += sizeof(edge_time_t); } + if (edgelist_edge_end_times) { element_size += sizeof(edge_time_t); } edge_t num_edges{0}; for (size_t i = 0; i < edgelist_srcs.size(); ++i) { num_edges += edgelist_srcs[i].size(); @@ -1196,15 +1398,23 @@ create_graph_from_edgelist_impl( // 2. groupby each edge chunks to their target local adjacency matrix partition (and further // groupby within the local partition by applying the compute_gpu_id_from_vertex_t to minor vertex // IDs). - std::vector> edgelist_edge_offset_vectors(num_chunks); for (size_t i = 0; i < num_chunks; ++i) { // iterate over input edge chunks std::optional> this_chunk_weights{std::nullopt}; if (edgelist_weights) { this_chunk_weights = std::move((*edgelist_weights)[i]); } - std::optional> this_chunk_edge_ids{std::nullopt}; + std::optional> this_chunk_edge_ids{std::nullopt}; if (edgelist_edge_ids) { this_chunk_edge_ids = std::move((*edgelist_edge_ids)[i]); } std::optional> this_chunk_edge_types{std::nullopt}; if (edgelist_edge_types) { this_chunk_edge_types = std::move((*edgelist_edge_types)[i]); } + std::optional> this_chunk_edge_start_times{std::nullopt}; + if (edgelist_edge_start_times) { + this_chunk_edge_start_times = std::move((*edgelist_edge_start_times)[i]); + } + std::optional> this_chunk_edge_end_times{std::nullopt}; + if (edgelist_edge_end_times) { + this_chunk_edge_end_times = std::move((*edgelist_edge_end_times)[i]); + } + auto d_this_chunk_edge_counts = cugraph::detail::groupby_and_count_edgelist_by_local_partition_id( handle, @@ -1213,10 +1423,18 @@ create_graph_from_edgelist_impl( this_chunk_weights, this_chunk_edge_ids, this_chunk_edge_types, + this_chunk_edge_start_times, + this_chunk_edge_end_times, true); if (this_chunk_weights) { (*edgelist_weights)[i] = std::move(*this_chunk_weights); } if (this_chunk_edge_ids) { (*edgelist_edge_ids)[i] = std::move(*this_chunk_edge_ids); } if (this_chunk_edge_types) { (*edgelist_edge_types)[i] = std::move(*this_chunk_edge_types); } + if (this_chunk_edge_start_times) { + (*edgelist_edge_start_times)[i] = std::move(*this_chunk_edge_start_times); + } + if (this_chunk_edge_end_times) { + (*edgelist_edge_end_times)[i] = std::move(*this_chunk_edge_end_times); + } std::vector h_this_chunk_edge_counts(d_this_chunk_edge_counts.size()); raft::update_host(h_this_chunk_edge_counts.data(), @@ -1235,7 +1453,6 @@ create_graph_from_edgelist_impl( } // 3. compress edge chunk source/destination vertices to cut intermediate peak memory requirement - std::optional>> edgelist_compressed_srcs{std::nullopt}; std::optional>> edgelist_compressed_dsts{std::nullopt}; if (compressed_v_size < sizeof(vertex_t)) { @@ -1284,7 +1501,6 @@ create_graph_from_edgelist_impl( } // 4. compute additional copy_offset vectors - std::vector edge_partition_edge_counts(minor_comm_size); std::vector> edge_partition_intra_partition_segment_offset_vectors( minor_comm_size); @@ -1318,15 +1534,18 @@ create_graph_from_edgelist_impl( } // 5. split the grouped edge chunks to local partitions - std::vector> edge_partition_edgelist_srcs{}; std::vector> edge_partition_edgelist_dsts{}; std::optional>> edge_partition_edgelist_weights{ std::nullopt}; - std::optional>> edge_partition_edgelist_edge_ids{ + std::optional>> edge_partition_edgelist_edge_ids{ std::nullopt}; std::optional>> edge_partition_edgelist_edge_types{ std::nullopt}; + std::optional>> + edge_partition_edgelist_edge_start_times{std::nullopt}; + std::optional>> + edge_partition_edgelist_edge_end_times{std::nullopt}; std::optional>> edge_partition_edgelist_compressed_srcs{}; @@ -1385,7 +1604,7 @@ create_graph_from_edgelist_impl( } if (edgelist_edge_ids) { edge_partition_edgelist_edge_ids = - split_edge_chunk_elements_to_local_edge_partitions( + split_edge_chunk_elements_to_local_edge_partitions( handle, std::move(*edgelist_edge_ids), edgelist_edge_offset_vectors, @@ -1403,10 +1622,29 @@ create_graph_from_edgelist_impl( edge_partition_intra_partition_segment_offset_vectors, edge_partition_intra_segment_copy_output_displacement_vectors); } + if (edgelist_edge_start_times) { + edge_partition_edgelist_edge_start_times = + split_edge_chunk_elements_to_local_edge_partitions( + handle, + std::move(*edgelist_edge_start_times), + edgelist_edge_offset_vectors, + edge_partition_edge_counts, + edge_partition_intra_partition_segment_offset_vectors, + edge_partition_intra_segment_copy_output_displacement_vectors); + } + if (edgelist_edge_end_times) { + edge_partition_edgelist_edge_end_times = + split_edge_chunk_elements_to_local_edge_partitions( + handle, + std::move(*edgelist_edge_end_times), + edgelist_edge_offset_vectors, + edge_partition_edge_counts, + edge_partition_intra_partition_segment_offset_vectors, + edge_partition_intra_segment_copy_output_displacement_vectors); + } // 6. decompress edge chunk source/destination vertices to cut intermediate peak memory // requirement - if (compressed_v_size < sizeof(vertex_t)) { assert(edge_partition_edgelist_compressed_srcs); assert(edge_partition_edgelist_compressed_dsts); @@ -1442,8 +1680,8 @@ create_graph_from_edgelist_impl( return create_graph_from_partitioned_edgelist( handle, @@ -1453,6 +1691,8 @@ create_graph_from_edgelist_impl( std::move(edge_partition_edgelist_weights), std::move(edge_partition_edgelist_edge_ids), std::move(edge_partition_edgelist_edge_types), + std::move(edge_partition_edgelist_edge_start_times), + std::move(edge_partition_edgelist_edge_end_times), edge_partition_intra_partition_segment_offset_vectors, graph_properties, renumber); @@ -1461,8 +1701,8 @@ create_graph_from_edgelist_impl( template std::enable_if_t< @@ -1472,9 +1712,13 @@ std::enable_if_t< std::optional< edge_property_t, weight_t>>, std::optional< - edge_property_t, edge_id_t>>, + edge_property_t, edge_t>>, std::optional< edge_property_t, edge_type_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional< + edge_property_t, edge_time_t>>, std::optional>>> create_graph_from_edgelist_impl( raft::handle_t const& handle, @@ -1482,8 +1726,10 @@ create_graph_from_edgelist_impl( rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, - std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_ids, std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, graph_properties_t graph_properties, bool renumber, bool do_expensive_check) @@ -1502,6 +1748,14 @@ create_graph_from_edgelist_impl( CUGRAPH_EXPECTS(!edgelist_edge_types || (edgelist_srcs.size() == (*edgelist_edge_types).size()), "Invalid input arguments: edgelist_srcs.size() != " "(*edgelist_edge_types).size()."); + CUGRAPH_EXPECTS( + !edgelist_edge_start_times || (edgelist_srcs.size() == (*edgelist_edge_start_times).size()), + "Invalid input arguments: edgelist_srcs.size() != " + "(*edgelist_edge_start_times).size()."); + CUGRAPH_EXPECTS( + !edgelist_edge_end_times || (edgelist_srcs.size() == (*edgelist_edge_end_times).size()), + "Invalid input arguments: edgelist_srcs.size() != " + "(*edgelist_edge_end_times).size()."); if (do_expensive_check) { expensive_check_edgelist(handle, @@ -1534,7 +1788,6 @@ create_graph_from_edgelist_impl( } // 1. renumber - auto renumber_map_labels = renumber ? std::make_optional>(0, handle.get_stream()) : std::nullopt; @@ -1562,12 +1815,34 @@ create_graph_from_edgelist_impl( } // 2. convert edge list (COO) to compressed sparse format (CSR or CSC) + int edge_property_count = 0; + size_t element_size = sizeof(vertex_t) * 2; + + if (edgelist_weights) { + ++edge_property_count; + element_size += sizeof(weight_t); + } + + if (edgelist_edge_ids) { + ++edge_property_count; + element_size += sizeof(edge_t); + } + if (edgelist_edge_types) { + ++edge_property_count; + element_size += sizeof(edge_type_t); + } + if (edgelist_edge_start_times) { + ++edge_property_count; + element_size += sizeof(edge_time_t); + } + if (edgelist_edge_end_times) { + ++edge_property_count; + element_size += sizeof(edge_time_t); + } + + if (edge_property_count > 1) { element_size = sizeof(vertex_t) * 2 + sizeof(size_t); } auto total_global_mem = handle.get_device_properties().totalGlobalMem; - size_t element_size = sizeof(vertex_t) * 2; - if (edgelist_weights) { element_size += sizeof(weight_t); } - if (edgelist_edge_ids) { element_size += sizeof(edge_id_t); } - if (edgelist_edge_types) { element_size += sizeof(edge_type_t); } auto constexpr mem_frugal_ratio = 0.25; // if the expected temporary buffer size exceeds the mem_frugal_ratio of the // total_global_mem, switch to the memory frugal approach @@ -1577,137 +1852,152 @@ create_graph_from_edgelist_impl( rmm::device_uvector offsets(size_t{0}, handle.get_stream()); rmm::device_uvector indices(size_t{0}, handle.get_stream()); std::optional> weights{std::nullopt}; - std::optional> ids{std::nullopt}; + std::optional> ids{std::nullopt}; std::optional> types{std::nullopt}; + std::optional> start_times{std::nullopt}; + std::optional> end_times{std::nullopt}; - if (edgelist_weights) { - if (edgelist_edge_ids) { - if (edgelist_edge_types) { - std::forward_as_tuple(offsets, indices, std::tie(weights, ids, types), std::ignore) = - detail::sort_and_compress_edgelist, - store_transposed>( - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_weights), - std::move(*edgelist_edge_ids), - std::move(*edgelist_edge_types)), - vertex_t{0}, - std::optional{std::nullopt}, - num_vertices, - vertex_t{0}, - num_vertices, - mem_frugal_threshold, - handle.get_stream()); - } else { - std::forward_as_tuple(offsets, indices, std::tie(weights, ids), std::ignore) = - detail::sort_and_compress_edgelist, - store_transposed>( - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_weights), std::move(*edgelist_edge_ids)), - vertex_t{0}, - std::optional{std::nullopt}, - num_vertices, - vertex_t{0}, - num_vertices, - mem_frugal_threshold, - handle.get_stream()); - } - } else { - if (edgelist_edge_types) { - std::forward_as_tuple(offsets, indices, std::tie(weights, types), std::ignore) = - detail::sort_and_compress_edgelist, - store_transposed>( - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_weights), std::move(*edgelist_edge_types)), - vertex_t{0}, - std::optional{std::nullopt}, - num_vertices, - vertex_t{0}, - num_vertices, - mem_frugal_threshold, - handle.get_stream()); - } else { - std::forward_as_tuple(offsets, indices, weights, std::ignore) = - detail::sort_and_compress_edgelist( - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(*edgelist_weights), - vertex_t{0}, - std::optional{std::nullopt}, - num_vertices, - vertex_t{0}, - num_vertices, - mem_frugal_threshold, - handle.get_stream()); - } + if (edge_property_count == 0) { + std::forward_as_tuple(offsets, indices, std::ignore) = + detail::sort_and_compress_edgelist( + std::move(edgelist_srcs), + std::move(edgelist_dsts), + vertex_t{0}, + std::optional{std::nullopt}, + num_vertices, + vertex_t{0}, + num_vertices, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_property_count == 1) { + if (edgelist_weights) { + std::forward_as_tuple(offsets, indices, weights, std::ignore) = + detail::sort_and_compress_edgelist( + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(*edgelist_weights), + vertex_t{0}, + std::optional{std::nullopt}, + num_vertices, + vertex_t{0}, + num_vertices, + mem_frugal_threshold, + handle.get_stream()); + } else if (edgelist_edge_ids) { + std::forward_as_tuple(offsets, indices, ids, std::ignore) = + detail::sort_and_compress_edgelist( + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(*edgelist_edge_ids), + vertex_t{0}, + std::optional{std::nullopt}, + num_vertices, + vertex_t{0}, + num_vertices, + mem_frugal_threshold, + handle.get_stream()); + } else if (edgelist_edge_types) { + std::forward_as_tuple(offsets, indices, types, std::ignore) = + detail::sort_and_compress_edgelist( + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(*edgelist_edge_types), + vertex_t{0}, + std::optional{std::nullopt}, + num_vertices, + vertex_t{0}, + num_vertices, + mem_frugal_threshold, + handle.get_stream()); + } else if (edgelist_edge_start_times) { + std::forward_as_tuple(offsets, indices, start_times, std::ignore) = + detail::sort_and_compress_edgelist( + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(*edgelist_edge_start_times), + vertex_t{0}, + std::optional{std::nullopt}, + num_vertices, + vertex_t{0}, + num_vertices, + mem_frugal_threshold, + handle.get_stream()); + } else if (edgelist_edge_end_times) { + std::forward_as_tuple(offsets, indices, end_times, std::ignore) = + detail::sort_and_compress_edgelist( + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(*edgelist_edge_end_times), + vertex_t{0}, + std::optional{std::nullopt}, + num_vertices, + vertex_t{0}, + num_vertices, + mem_frugal_threshold, + handle.get_stream()); } } else { + rmm::device_uvector property_position(edgelist_srcs.size(), handle.get_stream()); + detail::sequence_fill( + handle.get_stream(), property_position.data(), property_position.size(), edge_t{0}); + + std::tie(offsets, indices, property_position, std::ignore) = + detail::sort_and_compress_edgelist( + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(property_position), + vertex_t{0}, + std::optional{std::nullopt}, + num_vertices, + vertex_t{0}, + num_vertices, + mem_frugal_threshold, + handle.get_stream()); + + if (edgelist_weights) { + weights = std::make_optional>(property_position.size(), + handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_weights->begin(), + weights->begin()); + } if (edgelist_edge_ids) { - if (edgelist_edge_types) { - std::forward_as_tuple(offsets, indices, std::tie(ids, types), std::ignore) = - detail::sort_and_compress_edgelist, - store_transposed>( - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_edge_ids), std::move(*edgelist_edge_types)), - vertex_t{0}, - std::optional{std::nullopt}, - num_vertices, - vertex_t{0}, - num_vertices, - mem_frugal_threshold, - handle.get_stream()); - } else { - std::forward_as_tuple(offsets, indices, ids, std::ignore) = - detail::sort_and_compress_edgelist( - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(*edgelist_edge_ids), - vertex_t{0}, - std::optional{std::nullopt}, - num_vertices, - vertex_t{0}, - num_vertices, - mem_frugal_threshold, - handle.get_stream()); - } - } else { - if (edgelist_edge_types) { - std::forward_as_tuple(offsets, indices, types, std::ignore) = - detail::sort_and_compress_edgelist( - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(*edgelist_edge_types), - vertex_t{0}, - std::optional{std::nullopt}, - num_vertices, - vertex_t{0}, - num_vertices, - mem_frugal_threshold, - handle.get_stream()); - } else { - std::forward_as_tuple(offsets, indices, std::ignore) = - detail::sort_and_compress_edgelist( - std::move(edgelist_srcs), - std::move(edgelist_dsts), - vertex_t{0}, - std::optional{std::nullopt}, - num_vertices, - vertex_t{0}, - num_vertices, - mem_frugal_threshold, - handle.get_stream()); - } + ids = std::make_optional>(property_position.size(), + handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_ids->begin(), + ids->begin()); + } + if (edgelist_edge_types) { + types = std::make_optional>(property_position.size(), + handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_types->begin(), + types->begin()); + } + if (edgelist_edge_start_times) { + start_times = std::make_optional>(property_position.size(), + handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_start_times->begin(), + start_times->begin()); + } + if (edgelist_edge_end_times) { + end_times = std::make_optional>(property_position.size(), + handle.get_stream()); + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_end_times->begin(), + end_times->begin()); } } @@ -1725,14 +2015,13 @@ create_graph_from_edgelist_impl( } std::optional< - edge_property_t, edge_id_t>> + edge_property_t, edge_t>> edge_ids{std::nullopt}; if (ids) { - std::vector> buffers{}; + std::vector> buffers{}; buffers.push_back(std::move(*ids)); - edge_ids = - edge_property_t, edge_id_t>( - std::move(buffers)); + edge_ids = edge_property_t, edge_t>( + std::move(buffers)); } std::optional< @@ -1746,6 +2035,28 @@ create_graph_from_edgelist_impl( std::move(buffers)); } + std::optional< + edge_property_t, edge_time_t>> + edge_start_times{std::nullopt}; + if (start_times) { + std::vector> buffers{}; + buffers.push_back(std::move(*start_times)); + edge_start_times = + edge_property_t, edge_time_t>( + std::move(buffers)); + } + + std::optional< + edge_property_t, edge_time_t>> + edge_end_times{std::nullopt}; + if (end_times) { + std::vector> buffers{}; + buffers.push_back(std::move(*end_times)); + edge_end_times = + edge_property_t, edge_time_t>( + std::move(buffers)); + } + // 4. graph_t constructor return std::make_tuple( @@ -1761,14 +2072,16 @@ create_graph_from_edgelist_impl( std::move(edge_weights), std::move(edge_ids), std::move(edge_types), + std::move(edge_start_times), + std::move(edge_end_times), std::move(renumber_map_labels)); } template std::enable_if_t< @@ -1778,9 +2091,13 @@ std::enable_if_t< std::optional< edge_property_t, weight_t>>, std::optional< - edge_property_t, edge_id_t>>, + edge_property_t, edge_t>>, std::optional< edge_property_t, edge_type_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional< + edge_property_t, edge_time_t>>, std::optional>>> create_graph_from_edgelist_impl( raft::handle_t const& handle, @@ -1788,8 +2105,10 @@ create_graph_from_edgelist_impl( std::vector>&& edgelist_srcs, std::vector>&& edgelist_dsts, std::optional>>&& edgelist_weights, - std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_ids, std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, graph_properties_t graph_properties, bool renumber, bool do_expensive_check) @@ -1805,6 +2124,14 @@ create_graph_from_edgelist_impl( CUGRAPH_EXPECTS(!edgelist_edge_types || (edgelist_srcs.size() == (*edgelist_edge_types).size()), "Invalid input arguments: edgelist_edge_types.has_value() is true, " "edgelist_srcs.size() != (*edgelist_edge_types).size()."); + CUGRAPH_EXPECTS( + !edgelist_edge_start_times || (edgelist_srcs.size() == (*edgelist_edge_start_times).size()), + "Invalid input arguments: edgelist_edge_start_times.has_value() is true, " + "edgelist_srcs.size() != (*edgelist_edge_start_times).size()."); + CUGRAPH_EXPECTS( + !edgelist_edge_end_times || (edgelist_srcs.size() == (*edgelist_edge_end_times).size()), + "Invalid input arguments: edgelist_edge_end_times.has_value() is true, " + "edgelist_srcs.size() != (*edgelist_edge_end_times).size()."); for (size_t i = 0; i < edgelist_srcs.size(); ++i) { CUGRAPH_EXPECTS(edgelist_srcs[i].size() == edgelist_dsts[i].size(), "Invalid input arguments: edgelist_srcs[i].size() != edgelist_dsts[i].size()."); @@ -1819,6 +2146,14 @@ create_graph_from_edgelist_impl( !edgelist_edge_types || (edgelist_srcs[i].size() == (*edgelist_edge_types)[i].size()), "Invalid input arguments: edgelist_edge_types.has_value() is true, " "edgelist_srcs[i].size() != (*edgelist_edge_types)[i].size()."); + CUGRAPH_EXPECTS(!edgelist_edge_start_times || + (edgelist_srcs[i].size() == (*edgelist_edge_start_times)[i].size()), + "Invalid input arguments: edgelist_edge_start_times.has_value() is true, " + "edgelist_srcs[i].size() != (*edgelist_edge_start_times)[i].size()."); + CUGRAPH_EXPECTS( + !edgelist_edge_end_times || (edgelist_srcs[i].size() == (*edgelist_edge_end_times)[i].size()), + "Invalid input arguments: edgelist_edge_end_times.has_value() is true, " + "edgelist_srcs[i].size() != (*edgelist_edge_end_times)[i].size()."); } std::vector chunk_edge_counts(edgelist_srcs.size()); @@ -1870,10 +2205,10 @@ create_graph_from_edgelist_impl( (*edgelist_weights).clear(); } - auto aggregate_edgelist_edge_ids = edgelist_edge_ids - ? std::make_optional>( - aggregate_edge_count, handle.get_stream()) - : std::nullopt; + auto aggregate_edgelist_edge_ids = + edgelist_edge_ids + ? std::make_optional>(aggregate_edge_count, handle.get_stream()) + : std::nullopt; if (aggregate_edgelist_edge_ids) { for (size_t i = 0; i < (*edgelist_edge_ids).size(); ++i) { thrust::copy(handle.get_thrust_policy(), @@ -1902,6 +2237,38 @@ create_graph_from_edgelist_impl( (*edgelist_edge_types).clear(); } + auto aggregate_edgelist_edge_start_times = + edgelist_edge_start_times ? std::make_optional>( + aggregate_edge_count, handle.get_stream()) + : std::nullopt; + if (aggregate_edgelist_edge_start_times) { + for (size_t i = 0; i < (*edgelist_edge_start_times).size(); ++i) { + thrust::copy(handle.get_thrust_policy(), + (*edgelist_edge_start_times)[i].begin(), + (*edgelist_edge_start_times)[i].end(), + (*aggregate_edgelist_edge_start_times).begin() + chunk_edge_displacements[i]); + (*edgelist_edge_start_times)[i].resize(0, handle.get_stream()); + (*edgelist_edge_start_times)[i].shrink_to_fit(handle.get_stream()); + } + (*edgelist_edge_start_times).clear(); + } + + auto aggregate_edgelist_edge_end_times = edgelist_edge_end_times + ? std::make_optional>( + aggregate_edge_count, handle.get_stream()) + : std::nullopt; + if (aggregate_edgelist_edge_end_times) { + for (size_t i = 0; i < (*edgelist_edge_end_times).size(); ++i) { + thrust::copy(handle.get_thrust_policy(), + (*edgelist_edge_end_times)[i].begin(), + (*edgelist_edge_end_times)[i].end(), + (*aggregate_edgelist_edge_end_times).begin() + chunk_edge_displacements[i]); + (*edgelist_edge_end_times)[i].resize(0, handle.get_stream()); + (*edgelist_edge_end_times)[i].shrink_to_fit(handle.get_stream()); + } + (*edgelist_edge_end_times).clear(); + } + if (do_expensive_check) { expensive_check_edgelist( handle, @@ -1938,8 +2305,8 @@ create_graph_from_edgelist_impl( return create_graph_from_edgelist_impl(handle, std::move(local_vertices), @@ -1948,6 +2315,8 @@ create_graph_from_edgelist_impl( std::move(aggregate_edgelist_weights), std::move(aggregate_edgelist_edge_ids), std::move(aggregate_edgelist_edge_types), + std::move(aggregate_edgelist_edge_start_times), + std::move(aggregate_edgelist_edge_end_times), graph_properties, renumber, do_expensive_check); @@ -1958,16 +2327,15 @@ create_graph_from_edgelist_impl( template std::tuple< - cugraph::graph_t, + graph_t, std::optional< edge_property_t, weight_t>>, std::optional< - edge_property_t, edge_id_t>>, + edge_property_t, edge_t>>, std::optional< edge_property_t, edge_type_t>>, std::optional>> @@ -1976,17 +2344,132 @@ create_graph_from_edgelist(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, - std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_ids, std::optional>&& edgelist_edge_types, graph_properties_t graph_properties, bool renumber, bool do_expensive_check) +{ + auto [graph, weights, edge_ids, edge_types, edge_start_times, edge_end_times, number_map] = + create_graph_from_edgelist_impl(handle, + std::move(vertices), + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::nullopt, + std::nullopt, + graph_properties, + renumber, + do_expensive_check); + + return std::make_tuple(std::move(graph), + std::move(weights), + std::move(edge_ids), + std::move(edge_types), + std::move(number_map)); +} + +template +std::tuple< + graph_t, + std::optional< + edge_property_t, weight_t>>, + std::optional< + edge_property_t, edge_t>>, + std::optional< + edge_property_t, edge_type_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check) +{ + auto [graph, weights, edge_ids, edge_types, edge_start_times, edge_end_times, number_map] = + create_graph_from_edgelist_impl(handle, + std::move(vertices), + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::nullopt, + std::nullopt, + graph_properties, + renumber, + do_expensive_check); + + return std::make_tuple(std::move(graph), + std::move(weights), + std::move(edge_ids), + std::move(edge_types), + std::move(number_map)); +} + +template +std::tuple< + graph_t, + std::optional< + edge_property_t, weight_t>>, + std::optional< + edge_property_t, edge_t>>, + std::optional< + edge_property_t, edge_type_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check) { return create_graph_from_edgelist_impl(handle, std::move(vertices), @@ -1995,6 +2478,8 @@ create_graph_from_edgelist(raft::handle_t const& handle, std::move(edgelist_weights), std::move(edgelist_edge_ids), std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times), graph_properties, renumber, do_expensive_check); @@ -2003,8 +2488,8 @@ create_graph_from_edgelist(raft::handle_t const& handle, template std::tuple< @@ -2012,9 +2497,13 @@ std::tuple< std::optional< edge_property_t, weight_t>>, std::optional< - edge_property_t, edge_id_t>>, + edge_property_t, edge_t>>, std::optional< edge_property_t, edge_type_t>>, + std::optional< + edge_property_t, edge_time_t>>, + std::optional< + edge_property_t, edge_time_t>>, std::optional>> create_graph_from_edgelist( raft::handle_t const& handle, @@ -2022,8 +2511,10 @@ create_graph_from_edgelist( std::vector>&& edgelist_srcs, std::vector>&& edgelist_dsts, std::optional>>&& edgelist_weights, - std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_ids, std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, graph_properties_t graph_properties, bool renumber, bool do_expensive_check) @@ -2031,8 +2522,8 @@ create_graph_from_edgelist( return create_graph_from_edgelist_impl(handle, std::move(vertices), @@ -2041,6 +2532,8 @@ create_graph_from_edgelist( std::move(edgelist_weights), std::move(edgelist_edge_ids), std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times), graph_properties, renumber, do_expensive_check); diff --git a/cpp/src/structure/create_graph_from_edgelist_mg_v32_e32.cu b/cpp/src/structure/create_graph_from_edgelist_mg_v32_e32.cu index d0e41734365..58a407420d7 100644 --- a/cpp/src/structure/create_graph_from_edgelist_mg_v32_e32.cu +++ b/cpp/src/structure/create_graph_from_edgelist_mg_v32_e32.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -49,7 +49,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -70,7 +70,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -91,7 +91,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -112,7 +112,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -133,7 +133,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -154,7 +154,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -175,7 +175,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, diff --git a/cpp/src/structure/create_graph_from_edgelist_mg_v32_e32_t32.cu b/cpp/src/structure/create_graph_from_edgelist_mg_v32_e32_t32.cu new file mode 100644 index 00000000000..5c053b5b2c2 --- /dev/null +++ b/cpp/src/structure/create_graph_from_edgelist_mg_v32_e32_t32.cu @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024-2025, 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 "create_graph_from_edgelist_impl.cuh" + +namespace cugraph { + +// explicit instantiations + +template std::tuple< + graph_t, + std::optional, float>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, float>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, double>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, double>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, float>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, float>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, double>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, double>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +} // namespace cugraph diff --git a/cpp/src/structure/create_graph_from_edgelist_mg_v32_e32_t64.cu b/cpp/src/structure/create_graph_from_edgelist_mg_v32_e32_t64.cu new file mode 100644 index 00000000000..25f26f287b1 --- /dev/null +++ b/cpp/src/structure/create_graph_from_edgelist_mg_v32_e32_t64.cu @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2024-2025, 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 "structure/create_graph_from_edgelist_impl.cuh" + +namespace cugraph { + +// explicit instantiations + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +} // namespace cugraph diff --git a/cpp/src/structure/create_graph_from_edgelist_mg_v64_e64.cu b/cpp/src/structure/create_graph_from_edgelist_mg_v64_e64.cu index cbbaf025856..36ca4f880c4 100644 --- a/cpp/src/structure/create_graph_from_edgelist_mg_v64_e64.cu +++ b/cpp/src/structure/create_graph_from_edgelist_mg_v64_e64.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -49,7 +49,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -70,7 +70,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -91,7 +91,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -112,7 +112,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -133,7 +133,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -154,7 +154,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -175,7 +175,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, diff --git a/cpp/src/structure/create_graph_from_edgelist_mg_v64_e64_t32.cu b/cpp/src/structure/create_graph_from_edgelist_mg_v64_e64_t32.cu new file mode 100644 index 00000000000..d1c42b66b70 --- /dev/null +++ b/cpp/src/structure/create_graph_from_edgelist_mg_v64_e64_t32.cu @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2024-2025, 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 "structure/create_graph_from_edgelist_impl.cuh" + +namespace cugraph { + +// explicit instantiations + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +} // namespace cugraph diff --git a/cpp/src/structure/create_graph_from_edgelist_mg_v64_e64_t64.cu b/cpp/src/structure/create_graph_from_edgelist_mg_v64_e64_t64.cu new file mode 100644 index 00000000000..75e2fbbba0c --- /dev/null +++ b/cpp/src/structure/create_graph_from_edgelist_mg_v64_e64_t64.cu @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2024-2025, 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 "structure/create_graph_from_edgelist_impl.cuh" + +namespace cugraph { + +// explicit instantiations + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +} // namespace cugraph diff --git a/cpp/src/structure/create_graph_from_edgelist_sg_v32_e32.cu b/cpp/src/structure/create_graph_from_edgelist_sg_v32_e32.cu index 28dc3befd8d..eadc6aa7935 100644 --- a/cpp/src/structure/create_graph_from_edgelist_sg_v32_e32.cu +++ b/cpp/src/structure/create_graph_from_edgelist_sg_v32_e32.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -49,7 +49,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -70,7 +70,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -91,7 +91,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -112,7 +112,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -133,7 +133,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -154,7 +154,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -175,7 +175,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, diff --git a/cpp/src/structure/create_graph_from_edgelist_sg_v32_e32_t32.cu b/cpp/src/structure/create_graph_from_edgelist_sg_v32_e32_t32.cu new file mode 100644 index 00000000000..c00b965c686 --- /dev/null +++ b/cpp/src/structure/create_graph_from_edgelist_sg_v32_e32_t32.cu @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024-2025, 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 "create_graph_from_edgelist_impl.cuh" + +namespace cugraph { + +// explicit instantiations + +template std::tuple< + graph_t, + std::optional, float>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, float>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, double>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, double>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, float>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, float>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, double>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + graph_t, + std::optional, double>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +} // namespace cugraph diff --git a/cpp/src/structure/create_graph_from_edgelist_sg_v32_e32_t64.cu b/cpp/src/structure/create_graph_from_edgelist_sg_v32_e32_t64.cu new file mode 100644 index 00000000000..09bb5de06a3 --- /dev/null +++ b/cpp/src/structure/create_graph_from_edgelist_sg_v32_e32_t64.cu @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2024-2025, 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 "structure/create_graph_from_edgelist_impl.cuh" + +namespace cugraph { + +// explicit instantiations + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +} // namespace cugraph diff --git a/cpp/src/structure/create_graph_from_edgelist_sg_v64_e64.cu b/cpp/src/structure/create_graph_from_edgelist_sg_v64_e64.cu index 7db38452c72..7d873deddc8 100644 --- a/cpp/src/structure/create_graph_from_edgelist_sg_v64_e64.cu +++ b/cpp/src/structure/create_graph_from_edgelist_sg_v64_e64.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -49,7 +49,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -70,7 +70,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -91,7 +91,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, rmm::device_uvector&& edgelist_srcs, @@ -112,7 +112,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -133,7 +133,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -154,7 +154,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, @@ -175,7 +175,7 @@ template std::tuple< std::optional< cugraph::edge_property_t, int32_t>>, std::optional>> -create_graph_from_edgelist( +create_graph_from_edgelist( raft::handle_t const& handle, std::optional>&& vertices, std::vector>&& edgelist_srcs, diff --git a/cpp/src/structure/create_graph_from_edgelist_sg_v64_e64_t32.cu b/cpp/src/structure/create_graph_from_edgelist_sg_v64_e64_t32.cu new file mode 100644 index 00000000000..d65fdff438c --- /dev/null +++ b/cpp/src/structure/create_graph_from_edgelist_sg_v64_e64_t32.cu @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2024-2025, 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 "structure/create_graph_from_edgelist_impl.cuh" + +namespace cugraph { + +// explicit instantiations + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +} // namespace cugraph diff --git a/cpp/src/structure/create_graph_from_edgelist_sg_v64_e64_t64.cu b/cpp/src/structure/create_graph_from_edgelist_sg_v64_e64_t64.cu new file mode 100644 index 00000000000..b96d04a1e6e --- /dev/null +++ b/cpp/src/structure/create_graph_from_edgelist_sg_v64_e64_t64.cu @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2024-2025, 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 "structure/create_graph_from_edgelist_impl.cuh" + +namespace cugraph { + +// explicit instantiations + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, float>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +template std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, double>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int32_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional< + cugraph::edge_property_t, int64_t>>, + std::optional>> +create_graph_from_edgelist( + raft::handle_t const& handle, + std::optional>&& vertices, + std::vector>&& edgelist_srcs, + std::vector>&& edgelist_dsts, + std::optional>>&& edgelist_weights, + std::optional>>&& edgelist_edge_ids, + std::optional>>&& edgelist_edge_types, + std::optional>>&& edgelist_edge_start_times, + std::optional>>&& edgelist_edge_end_times, + graph_properties_t graph_properties, + bool renumber, + bool do_expensive_check); + +} // namespace cugraph diff --git a/cpp/src/structure/remove_multi_edges_impl.cuh b/cpp/src/structure/remove_multi_edges_impl.cuh index 7e266ab2caf..23ce6055348 100644 --- a/cpp/src/structure/remove_multi_edges_impl.cuh +++ b/cpp/src/structure/remove_multi_edges_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, NVIDIA CORPORATION. + * Copyright (c) 2023-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ #include "structure/detail/structure_utils.cuh" +#include #include // FIXME: mem_frugal_partition should probably not be in shuffle_comm.hpp // It's used here without any notion of shuffling @@ -101,14 +102,13 @@ std::tuple, rmm::device_uvector> group_m template std::tuple, rmm::device_uvector, - decltype(allocate_dataframe_buffer(size_t{0}, rmm::cuda_stream_view{}))> -group_multi_edges( - raft::handle_t const& handle, - rmm::device_uvector&& edgelist_srcs, - rmm::device_uvector&& edgelist_dsts, - decltype(allocate_dataframe_buffer(0, rmm::cuda_stream_view{}))&& edgelist_values, - size_t mem_frugal_threshold, - bool keep_min_value_edge) + dataframe_buffer_type_t> +group_multi_edges(raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + dataframe_buffer_type_t&& edgelist_values, + size_t mem_frugal_threshold, + bool keep_min_value_edge) { auto pair_first = thrust::make_zip_iterator(edgelist_srcs.begin(), edgelist_dsts.begin()); auto value_first = get_dataframe_buffer_begin(edgelist_values); @@ -163,25 +163,55 @@ group_multi_edges( } // namespace detail -template +template std::tuple, rmm::device_uvector, std::optional>, std::optional>, - std::optional>> + std::optional>, + std::optional>, + std::optional>> remove_multi_edges(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool keep_min_value_edge) { - auto total_global_mem = handle.get_device_properties().totalGlobalMem; - size_t element_size = sizeof(vertex_t) * 2; - if (edgelist_weights) { element_size += sizeof(weight_t); } - if (edgelist_edge_ids) { element_size += sizeof(edge_t); } - if (edgelist_edge_types) { element_size += sizeof(edge_type_t); } + auto total_global_mem = handle.get_device_properties().totalGlobalMem; + int edge_property_count = 0; + size_t element_size = sizeof(vertex_t) * 2; + + if (edgelist_weights) { + ++edge_property_count; + element_size += sizeof(weight_t); + } + + if (edgelist_edge_ids) { + ++edge_property_count; + element_size += sizeof(edge_t); + } + if (edgelist_edge_types) { + ++edge_property_count; + element_size += sizeof(edge_type_t); + } + if (edgelist_edge_start_times) { + ++edge_property_count; + element_size += sizeof(edge_time_t); + } + if (edgelist_edge_end_times) { + ++edge_property_count; + element_size += sizeof(edge_time_t); + } + + if (edge_property_count > 1) { element_size = sizeof(vertex_t) * 2 + sizeof(size_t); } auto constexpr mem_frugal_ratio = 0.25; // if the expected temporary buffer size exceeds the mem_frugal_ratio of the @@ -189,90 +219,122 @@ remove_multi_edges(raft::handle_t const& handle, auto mem_frugal_threshold = static_cast(static_cast(total_global_mem / element_size) * mem_frugal_ratio); - if (edgelist_weights) { - if (edgelist_edge_ids) { - if (edgelist_edge_types) { - std::forward_as_tuple(edgelist_srcs, - edgelist_dsts, - std::tie(edgelist_weights, edgelist_edge_ids, edgelist_edge_types)) = - detail::group_multi_edges>( - handle, - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_weights), - std::move(*edgelist_edge_ids), - std::move(*edgelist_edge_types)), - mem_frugal_threshold, - keep_min_value_edge); - } else { - std::forward_as_tuple( - edgelist_srcs, edgelist_dsts, std::tie(edgelist_weights, edgelist_edge_ids)) = - detail::group_multi_edges>( - handle, - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_weights), std::move(*edgelist_edge_ids)), - mem_frugal_threshold, - keep_min_value_edge); - } - } else { - if (edgelist_edge_types) { - std::forward_as_tuple( - edgelist_srcs, edgelist_dsts, std::tie(edgelist_weights, edgelist_edge_types)) = - detail::group_multi_edges>( - handle, - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_weights), std::move(*edgelist_edge_types)), - mem_frugal_threshold, - keep_min_value_edge); - } else { - std::forward_as_tuple(edgelist_srcs, edgelist_dsts, std::tie(edgelist_weights)) = - detail::group_multi_edges>( - handle, - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_weights)), - mem_frugal_threshold, - keep_min_value_edge); - } + if (edge_property_count == 0) { + std::tie(edgelist_srcs, edgelist_dsts) = detail::group_multi_edges( + handle, std::move(edgelist_srcs), std::move(edgelist_dsts), mem_frugal_threshold); + } else if (edge_property_count == 1) { + if (edgelist_weights) { + std::tie(edgelist_srcs, edgelist_dsts, edgelist_weights) = + detail::group_multi_edges(handle, + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(*edgelist_weights), + mem_frugal_threshold, + keep_min_value_edge); + } else if (edgelist_edge_ids) { + std::tie(edgelist_srcs, edgelist_dsts, edgelist_edge_ids) = + detail::group_multi_edges(handle, + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(*edgelist_edge_ids), + mem_frugal_threshold, + keep_min_value_edge); + } else if (edgelist_edge_types) { + std::tie(edgelist_srcs, edgelist_dsts, edgelist_edge_types) = + detail::group_multi_edges(handle, + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(*edgelist_edge_types), + mem_frugal_threshold, + keep_min_value_edge); + } else if (edgelist_edge_start_times) { + std::tie(edgelist_srcs, edgelist_dsts, edgelist_edge_start_times) = + detail::group_multi_edges(handle, + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(*edgelist_edge_start_times), + mem_frugal_threshold, + keep_min_value_edge); + } else if (edgelist_edge_end_times) { + std::tie(edgelist_srcs, edgelist_dsts, edgelist_edge_end_times) = + detail::group_multi_edges(handle, + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(*edgelist_edge_end_times), + mem_frugal_threshold, + keep_min_value_edge); } } else { + rmm::device_uvector property_position(edgelist_srcs.size(), handle.get_stream()); + detail::sequence_fill( + handle.get_stream(), property_position.data(), property_position.size(), edge_t{0}); + + std::tie(edgelist_srcs, edgelist_dsts, property_position) = + detail::group_multi_edges(handle, + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(property_position), + mem_frugal_threshold, + keep_min_value_edge); + + if (edgelist_weights) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_weights->begin(), + tmp.begin()); + + edgelist_weights = std::move(tmp); + } + if (edgelist_edge_ids) { - if (edgelist_edge_types) { - std::forward_as_tuple( - edgelist_srcs, edgelist_dsts, std::tie(edgelist_edge_ids, edgelist_edge_types)) = - detail::group_multi_edges>( - handle, - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_edge_ids), std::move(*edgelist_edge_types)), - mem_frugal_threshold, - keep_min_value_edge); - } else { - std::forward_as_tuple(edgelist_srcs, edgelist_dsts, std::tie(edgelist_edge_ids)) = - detail::group_multi_edges>( - handle, - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_edge_ids)), - mem_frugal_threshold, - keep_min_value_edge); - } - } else { - if (edgelist_edge_types) { - std::forward_as_tuple(edgelist_srcs, edgelist_dsts, std::tie(edgelist_edge_types)) = - detail::group_multi_edges>( - handle, - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::make_tuple(std::move(*edgelist_edge_types)), - mem_frugal_threshold, - keep_min_value_edge); - } else { - std::tie(edgelist_srcs, edgelist_dsts) = detail::group_multi_edges( - handle, std::move(edgelist_srcs), std::move(edgelist_dsts), mem_frugal_threshold); - } + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_ids->begin(), + tmp.begin()); + + edgelist_edge_ids = std::move(tmp); + } + + if (edgelist_edge_types) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_types->begin(), + tmp.begin()); + + edgelist_edge_types = std::move(tmp); + } + + if (edgelist_edge_start_times) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_start_times->begin(), + tmp.begin()); + + edgelist_edge_start_times = std::move(tmp); + } + + if (edgelist_edge_end_times) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_end_times->begin(), + tmp.begin()); + + edgelist_edge_end_times = std::move(tmp); } } @@ -323,7 +385,9 @@ remove_multi_edges(raft::handle_t const& handle, std::move(edgelist_dsts), std::move(edgelist_weights), std::move(edgelist_edge_ids), - std::move(edgelist_edge_types)); + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times)); } } // namespace cugraph diff --git a/cpp/src/structure/remove_multi_edges_sg_v32_e32.cu b/cpp/src/structure/remove_multi_edges_sg_v32_e32.cu index 18b8da512f4..060bd7fad61 100644 --- a/cpp/src/structure/remove_multi_edges_sg_v32_e32.cu +++ b/cpp/src/structure/remove_multi_edges_sg_v32_e32.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, NVIDIA CORPORATION. + * Copyright (c) 2023-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,8 @@ template std::tuple, rmm::device_uvector, std::optional>, std::optional>, + std::optional>, + std::optional>, std::optional>> remove_multi_edges(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, @@ -28,12 +30,16 @@ remove_multi_edges(raft::handle_t const& handle, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool keep_min_value_edge); template std::tuple, rmm::device_uvector, std::optional>, std::optional>, + std::optional>, + std::optional>, std::optional>> remove_multi_edges(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, @@ -41,6 +47,42 @@ remove_multi_edges(raft::handle_t const& handle, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool keep_min_value_edge); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +remove_multi_edges(raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool keep_min_value_edge); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +remove_multi_edges(raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool keep_min_value_edge); } // namespace cugraph diff --git a/cpp/src/structure/remove_multi_edges_sg_v64_e64.cu b/cpp/src/structure/remove_multi_edges_sg_v64_e64.cu index 0dad6988a5c..5c51d6cdbe5 100644 --- a/cpp/src/structure/remove_multi_edges_sg_v64_e64.cu +++ b/cpp/src/structure/remove_multi_edges_sg_v64_e64.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, NVIDIA CORPORATION. + * Copyright (c) 2023-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,8 @@ template std::tuple, rmm::device_uvector, std::optional>, std::optional>, + std::optional>, + std::optional>, std::optional>> remove_multi_edges(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, @@ -28,12 +30,16 @@ remove_multi_edges(raft::handle_t const& handle, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool keep_min_value_edge); template std::tuple, rmm::device_uvector, std::optional>, std::optional>, + std::optional>, + std::optional>, std::optional>> remove_multi_edges(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, @@ -41,6 +47,42 @@ remove_multi_edges(raft::handle_t const& handle, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool keep_min_value_edge); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +remove_multi_edges(raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool keep_min_value_edge); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +remove_multi_edges(raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool keep_min_value_edge); } // namespace cugraph diff --git a/cpp/src/structure/remove_self_loops_impl.cuh b/cpp/src/structure/remove_self_loops_impl.cuh index b8647a8966d..d1c7013201a 100644 --- a/cpp/src/structure/remove_self_loops_impl.cuh +++ b/cpp/src/structure/remove_self_loops_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, NVIDIA CORPORATION. + * Copyright (c) 2023-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,18 +32,26 @@ namespace cugraph { -template +template std::tuple, rmm::device_uvector, std::optional>, std::optional>, - std::optional>> + std::optional>, + std::optional>, + std::optional>> remove_self_loops(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, - std::optional>&& edgelist_edge_types) + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times) { auto [keep_count, keep_flags] = detail::mark_entries(handle, @@ -83,13 +91,29 @@ remove_self_loops(raft::handle_t const& handle, std::move(*edgelist_edge_types), raft::device_span{keep_flags.data(), keep_flags.size()}, keep_count); + + if (edgelist_edge_start_times) + edgelist_edge_start_times = detail::keep_flagged_elements( + handle, + std::move(*edgelist_edge_start_times), + raft::device_span{keep_flags.data(), keep_flags.size()}, + keep_count); + + if (edgelist_edge_end_times) + edgelist_edge_end_times = detail::keep_flagged_elements( + handle, + std::move(*edgelist_edge_end_times), + raft::device_span{keep_flags.data(), keep_flags.size()}, + keep_count); } return std::make_tuple(std::move(edgelist_srcs), std::move(edgelist_dsts), std::move(edgelist_weights), std::move(edgelist_edge_ids), - std::move(edgelist_edge_types)); + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times)); } } // namespace cugraph diff --git a/cpp/src/structure/remove_self_loops_sg_v32_e32.cu b/cpp/src/structure/remove_self_loops_sg_v32_e32.cu index 355eb846f29..4bb6f126cd5 100644 --- a/cpp/src/structure/remove_self_loops_sg_v32_e32.cu +++ b/cpp/src/structure/remove_self_loops_sg_v32_e32.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, NVIDIA CORPORATION. + * Copyright (c) 2023-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,24 +21,64 @@ template std::tuple, rmm::device_uvector, std::optional>, std::optional>, + std::optional>, + std::optional>, std::optional>> remove_self_loops(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, - std::optional>&& edgelist_edge_types); + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times); template std::tuple, rmm::device_uvector, std::optional>, std::optional>, + std::optional>, + std::optional>, std::optional>> remove_self_loops(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, - std::optional>&& edgelist_edge_types); + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +remove_self_loops(raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +remove_self_loops(raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times); } // namespace cugraph diff --git a/cpp/src/structure/remove_self_loops_sg_v64_e64.cu b/cpp/src/structure/remove_self_loops_sg_v64_e64.cu index 76ae89387e4..6e97074a37c 100644 --- a/cpp/src/structure/remove_self_loops_sg_v64_e64.cu +++ b/cpp/src/structure/remove_self_loops_sg_v64_e64.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, NVIDIA CORPORATION. + * Copyright (c) 2023-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,24 +21,64 @@ template std::tuple, rmm::device_uvector, std::optional>, std::optional>, + std::optional>, + std::optional>, std::optional>> remove_self_loops(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, - std::optional>&& edgelist_edge_types); + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times); template std::tuple, rmm::device_uvector, std::optional>, std::optional>, + std::optional>, + std::optional>, std::optional>> remove_self_loops(raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, std::optional>&& edgelist_edge_ids, - std::optional>&& edgelist_edge_types); + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +remove_self_loops(raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +remove_self_loops(raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times); } // namespace cugraph diff --git a/cpp/src/structure/symmetrize_edgelist_impl.cuh b/cpp/src/structure/symmetrize_edgelist_impl.cuh index 1fd566938eb..2685f6f0656 100644 --- a/cpp/src/structure/symmetrize_edgelist_impl.cuh +++ b/cpp/src/structure/symmetrize_edgelist_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2024, NVIDIA CORPORATION. + * Copyright (c) 2020-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ #pragma once #include +#include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -96,7 +98,7 @@ struct symmetrize_op_t { if (i < min_run_length) { thrust::get<2>(*(edge_first + i)) = (thrust::get<2>(*(edge_first + i)) + thrust::get<2>(*(edge_first + lower_run_length + i))) / - weight_t{2.0}; // average + weight_t{2}; // average *(include_first + i) = true; *(include_first + lower_run_length + i) = false; } else { @@ -175,71 +177,406 @@ struct to_lower_triangular_t { } }; +template +struct pick_from_lower_upper_t { + raft::device_span lower_{}; + raft::device_span upper_{}; + + __device__ property_t operator()(size_t pos) + { + return (pos < lower_.size()) ? lower_[pos] : upper_[pos - lower_.size()]; + } +}; + } // namespace namespace detail { -// FIXME: This function should be modified to support edge id/type -template +template std::tuple, rmm::device_uvector, - std::optional>> + rmm::device_uvector> +merge_lower_triangular(raft::handle_t const& handle, + rmm::device_uvector&& lower_triangular_majors, + rmm::device_uvector&& lower_triangular_minors, + rmm::device_uvector&& lower_triangular_properties, + rmm::device_uvector&& upper_triangular_majors, + rmm::device_uvector&& upper_triangular_minors, + rmm::device_uvector&& upper_triangular_properties, + size_t num_lower_triangular_edges, + bool reciprocal) +{ + rmm::device_uvector merged_majors(0, handle.get_stream()); + rmm::device_uvector merged_minors(0, handle.get_stream()); + rmm::device_uvector merged_properties(0, handle.get_stream()); + + auto lower_triangular_edge_first = thrust::make_zip_iterator(lower_triangular_majors.begin(), + lower_triangular_minors.begin(), + lower_triangular_properties.begin()); + thrust::sort(handle.get_thrust_policy(), + lower_triangular_edge_first, + lower_triangular_edge_first + lower_triangular_majors.size()); + auto upper_triangular_edge_first = thrust::make_zip_iterator( + upper_triangular_majors.begin(), + upper_triangular_minors.begin(), + upper_triangular_properties + .begin()); // do not flip here to use "lower_triangular = major > minor" + thrust::sort(handle.get_thrust_policy(), + upper_triangular_edge_first, + upper_triangular_edge_first + upper_triangular_majors.size(), + compare_upper_triangular_edges_as_lower_triangular_t{}); + + merged_majors.resize(lower_triangular_majors.size() + upper_triangular_majors.size(), + handle.get_stream()); + merged_minors.resize(merged_majors.size(), handle.get_stream()); + merged_properties.resize(merged_majors.size(), handle.get_stream()); + auto merged_first = thrust::make_zip_iterator( + thrust::make_tuple(merged_majors.begin(), merged_minors.begin(), merged_properties.begin())); + thrust::merge(handle.get_thrust_policy(), + lower_triangular_edge_first, + lower_triangular_edge_first + lower_triangular_majors.size(), + upper_triangular_edge_first, + upper_triangular_edge_first + upper_triangular_majors.size(), + merged_first, + compare_lower_and_upper_triangular_edges_t{}); + + lower_triangular_majors.resize(0, handle.get_stream()); + lower_triangular_majors.shrink_to_fit(handle.get_stream()); + lower_triangular_minors.resize(0, handle.get_stream()); + lower_triangular_minors.shrink_to_fit(handle.get_stream()); + lower_triangular_properties.resize(0, handle.get_stream()); + lower_triangular_properties.shrink_to_fit(handle.get_stream()); + + upper_triangular_majors.resize(0, handle.get_stream()); + upper_triangular_majors.shrink_to_fit(handle.get_stream()); + upper_triangular_minors.resize(0, handle.get_stream()); + upper_triangular_minors.shrink_to_fit(handle.get_stream()); + upper_triangular_properties.resize(0, handle.get_stream()); + upper_triangular_properties.shrink_to_fit(handle.get_stream()); + + rmm::device_uvector includes(merged_majors.size(), handle.get_stream()); + symmetrize_op_t symm_op{reciprocal}; + thrust::for_each(handle.get_thrust_policy(), + thrust::make_counting_iterator(size_t{0}), + thrust::make_counting_iterator(merged_majors.size()), + update_edge_weights_and_flags_t{ + merged_first, includes.data(), merged_majors.size(), symm_op}); + + auto merged_edge_and_flag_first = thrust::make_zip_iterator( + merged_majors.begin(), merged_minors.begin(), merged_properties.begin(), includes.begin()); + merged_majors.resize( + thrust::distance(merged_edge_and_flag_first, + thrust::remove_if(handle.get_thrust_policy(), + merged_edge_and_flag_first, + merged_edge_and_flag_first + merged_majors.size(), + [] __device__(auto t) { return !thrust::get<3>(t); })), + handle.get_stream()); + merged_majors.shrink_to_fit(handle.get_stream()); + merged_minors.resize(merged_majors.size(), handle.get_stream()); + merged_minors.shrink_to_fit(handle.get_stream()); + merged_properties.resize(merged_majors.size(), handle.get_stream()); + merged_properties.shrink_to_fit(handle.get_stream()); + + auto merged_major_minor_range_first = + thrust::make_zip_iterator(merged_majors.begin(), merged_minors.begin()); + thrust::transform(handle.get_thrust_policy(), + merged_major_minor_range_first, + merged_major_minor_range_first + merged_majors.size(), + merged_major_minor_range_first, + to_lower_triangular_t{}); + + return std::make_tuple( + std::move(merged_majors), std::move(merged_minors), std::move(merged_properties)); +} + +template +std::tuple, rmm::device_uvector> merge_lower_triangular( + raft::handle_t const& handle, + rmm::device_uvector&& lower_triangular_majors, + rmm::device_uvector&& lower_triangular_minors, + rmm::device_uvector&& upper_triangular_majors, + rmm::device_uvector&& upper_triangular_minors, + size_t num_lower_triangular_edges, + bool reciprocal) +{ + rmm::device_uvector merged_majors(0, handle.get_stream()); + rmm::device_uvector merged_minors(0, handle.get_stream()); + + auto lower_triangular_edge_first = thrust::make_zip_iterator( + thrust::make_tuple(lower_triangular_majors.begin(), lower_triangular_minors.begin())); + thrust::sort(handle.get_thrust_policy(), + lower_triangular_edge_first, + lower_triangular_edge_first + lower_triangular_majors.size()); + auto upper_triangular_edge_first = thrust::make_zip_iterator( + thrust::make_tuple(upper_triangular_minors.begin(), upper_triangular_majors.begin())); // flip + thrust::sort(handle.get_thrust_policy(), + upper_triangular_edge_first, + upper_triangular_edge_first + upper_triangular_majors.size()); + + merged_majors.resize(reciprocal + ? std::min(num_lower_triangular_edges, upper_triangular_majors.size()) + : num_lower_triangular_edges + upper_triangular_majors.size(), + handle.get_stream()); + merged_minors.resize(merged_majors.size(), handle.get_stream()); + auto merged_first = + thrust::make_zip_iterator(thrust::make_tuple(merged_majors.begin(), merged_minors.begin())); + auto merged_last = + reciprocal + ? thrust::set_intersection(handle.get_thrust_policy(), + lower_triangular_edge_first, + lower_triangular_edge_first + lower_triangular_majors.size(), + upper_triangular_edge_first, + upper_triangular_edge_first + upper_triangular_majors.size(), + merged_first) + : thrust::set_union(handle.get_thrust_policy(), + lower_triangular_edge_first, + lower_triangular_edge_first + lower_triangular_majors.size(), + upper_triangular_edge_first, + upper_triangular_edge_first + upper_triangular_majors.size(), + merged_first); + + lower_triangular_majors.resize(0, handle.get_stream()); + lower_triangular_majors.shrink_to_fit(handle.get_stream()); + lower_triangular_minors.resize(0, handle.get_stream()); + lower_triangular_minors.shrink_to_fit(handle.get_stream()); + + upper_triangular_majors.resize(0, handle.get_stream()); + upper_triangular_majors.shrink_to_fit(handle.get_stream()); + upper_triangular_minors.resize(0, handle.get_stream()); + upper_triangular_minors.shrink_to_fit(handle.get_stream()); + + merged_majors.resize(thrust::distance(merged_first, merged_last), handle.get_stream()); + merged_majors.shrink_to_fit(handle.get_stream()); + merged_minors.resize(merged_majors.size(), handle.get_stream()); + merged_minors.shrink_to_fit(handle.get_stream()); + + return std::make_tuple(std::move(merged_majors), std::move(merged_minors)); +} + +template +std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> symmetrize_edgelist(raft::handle_t const& handle, rmm::device_uvector&& edgelist_majors, rmm::device_uvector&& edgelist_minors, std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool reciprocal) { + int edge_property_count = 0; + if (edgelist_weights) ++edge_property_count; + if (edgelist_edge_ids) ++edge_property_count; + if (edgelist_edge_types) ++edge_property_count; + if (edgelist_edge_start_times) ++edge_property_count; + if (edgelist_edge_end_times) ++edge_property_count; + // 1. separate lower triangular, diagonal (self-loop), and upper triangular edges size_t num_lower_triangular_edges{0}; size_t num_diagonal_edges{0}; - if (edgelist_weights) { - auto edge_first = thrust::make_zip_iterator(thrust::make_tuple( - edgelist_majors.begin(), edgelist_minors.begin(), (*edgelist_weights).begin())); + + auto lower_triangular_compare = [] __device__(auto e) { + auto major = thrust::get<0>(e); + auto minor = thrust::get<1>(e); + return major > minor; + }; + + auto diagonal_compare = [] __device__(auto e) { + auto major = thrust::get<0>(e); + auto minor = thrust::get<1>(e); + return major == minor; + }; + + if (edge_property_count == 0) { + auto edge_first = thrust::make_zip_iterator(edgelist_majors.begin(), edgelist_minors.begin()); auto lower_triangular_last = thrust::partition(handle.get_thrust_policy(), edge_first, edge_first + edgelist_majors.size(), - [] __device__(auto e) { - auto major = thrust::get<0>(e); - auto minor = thrust::get<1>(e); - return major > minor; - }); + lower_triangular_compare); num_lower_triangular_edges = static_cast(thrust::distance(edge_first, lower_triangular_last)); auto diagonal_last = thrust::partition(handle.get_thrust_policy(), edge_first + num_lower_triangular_edges, edge_first + edgelist_majors.size(), - [] __device__(auto e) { - auto major = thrust::get<0>(e); - auto minor = thrust::get<1>(e); - return major == minor; - }); + diagonal_compare); num_diagonal_edges = static_cast(thrust::distance(lower_triangular_last, diagonal_last)); + } else if (edge_property_count == 1) { + if (edgelist_weights) { + auto edge_first = thrust::make_zip_iterator( + edgelist_majors.begin(), edgelist_minors.begin(), edgelist_weights->begin()); + auto lower_triangular_last = thrust::partition(handle.get_thrust_policy(), + edge_first, + edge_first + edgelist_majors.size(), + lower_triangular_compare); + num_lower_triangular_edges = + static_cast(thrust::distance(edge_first, lower_triangular_last)); + auto diagonal_last = thrust::partition(handle.get_thrust_policy(), + edge_first + num_lower_triangular_edges, + edge_first + edgelist_majors.size(), + diagonal_compare); + num_diagonal_edges = + static_cast(thrust::distance(lower_triangular_last, diagonal_last)); + } + + if (edgelist_edge_ids) { + auto edge_first = thrust::make_zip_iterator( + edgelist_majors.begin(), edgelist_minors.begin(), edgelist_edge_ids->begin()); + auto lower_triangular_last = thrust::partition(handle.get_thrust_policy(), + edge_first, + edge_first + edgelist_majors.size(), + lower_triangular_compare); + num_lower_triangular_edges = + static_cast(thrust::distance(edge_first, lower_triangular_last)); + auto diagonal_last = thrust::partition(handle.get_thrust_policy(), + edge_first + num_lower_triangular_edges, + edge_first + edgelist_majors.size(), + diagonal_compare); + num_diagonal_edges = + static_cast(thrust::distance(lower_triangular_last, diagonal_last)); + } + + if (edgelist_edge_types) { + auto edge_first = thrust::make_zip_iterator( + edgelist_majors.begin(), edgelist_minors.begin(), edgelist_edge_types->begin()); + auto lower_triangular_last = thrust::partition(handle.get_thrust_policy(), + edge_first, + edge_first + edgelist_majors.size(), + lower_triangular_compare); + num_lower_triangular_edges = + static_cast(thrust::distance(edge_first, lower_triangular_last)); + auto diagonal_last = thrust::partition(handle.get_thrust_policy(), + edge_first + num_lower_triangular_edges, + edge_first + edgelist_majors.size(), + diagonal_compare); + num_diagonal_edges = + static_cast(thrust::distance(lower_triangular_last, diagonal_last)); + } + + if (edgelist_edge_start_times) { + auto edge_first = thrust::make_zip_iterator( + edgelist_majors.begin(), edgelist_minors.begin(), edgelist_edge_start_times->begin()); + auto lower_triangular_last = thrust::partition(handle.get_thrust_policy(), + edge_first, + edge_first + edgelist_majors.size(), + lower_triangular_compare); + num_lower_triangular_edges = + static_cast(thrust::distance(edge_first, lower_triangular_last)); + auto diagonal_last = thrust::partition(handle.get_thrust_policy(), + edge_first + num_lower_triangular_edges, + edge_first + edgelist_majors.size(), + diagonal_compare); + num_diagonal_edges = + static_cast(thrust::distance(lower_triangular_last, diagonal_last)); + } + + if (edgelist_edge_end_times) { + auto edge_first = thrust::make_zip_iterator( + edgelist_majors.begin(), edgelist_minors.begin(), edgelist_edge_end_times->begin()); + auto lower_triangular_last = thrust::partition(handle.get_thrust_policy(), + edge_first, + edge_first + edgelist_majors.size(), + lower_triangular_compare); + num_lower_triangular_edges = + static_cast(thrust::distance(edge_first, lower_triangular_last)); + auto diagonal_last = thrust::partition(handle.get_thrust_policy(), + edge_first + num_lower_triangular_edges, + edge_first + edgelist_majors.size(), + diagonal_compare); + num_diagonal_edges = + static_cast(thrust::distance(lower_triangular_last, diagonal_last)); + } } else { + rmm::device_uvector property_position(edgelist_majors.size(), handle.get_stream()); + detail::sequence_fill( + handle.get_stream(), property_position.data(), property_position.size(), edge_t{0}); + auto edge_first = thrust::make_zip_iterator( - thrust::make_tuple(edgelist_majors.begin(), edgelist_minors.begin())); + edgelist_majors.begin(), edgelist_minors.begin(), property_position.begin()); auto lower_triangular_last = thrust::partition(handle.get_thrust_policy(), edge_first, edge_first + edgelist_majors.size(), - [] __device__(auto e) { - auto major = thrust::get<0>(e); - auto minor = thrust::get<1>(e); - return major > minor; - }); + lower_triangular_compare); num_lower_triangular_edges = static_cast(thrust::distance(edge_first, lower_triangular_last)); auto diagonal_last = thrust::partition(handle.get_thrust_policy(), edge_first + num_lower_triangular_edges, edge_first + edgelist_majors.size(), - [] __device__(auto e) { - auto major = thrust::get<0>(e); - auto minor = thrust::get<1>(e); - return major == minor; - }); + diagonal_compare); num_diagonal_edges = static_cast(thrust::distance(lower_triangular_last, diagonal_last)); + + if (edgelist_weights) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_weights->begin(), + tmp.begin()); + edgelist_weights = std::move(tmp); + } + + if (edgelist_edge_ids) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_ids->begin(), + tmp.begin()); + + edgelist_edge_ids = std::move(tmp); + } + + if (edgelist_edge_types) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_types->begin(), + tmp.begin()); + + edgelist_edge_types = std::move(tmp); + } + + if (edgelist_edge_start_times) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_start_times->begin(), + tmp.begin()); + + edgelist_edge_start_times = std::move(tmp); + } + + if (edgelist_edge_end_times) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edgelist_edge_end_times->begin(), + tmp.begin()); + + edgelist_edge_end_times = std::move(tmp); + } } rmm::device_uvector diagonal_majors(num_diagonal_edges, handle.get_stream()); @@ -267,35 +604,116 @@ symmetrize_edgelist(raft::handle_t const& handle, edgelist_minors.shrink_to_fit(handle.get_stream()); auto lower_triangular_minors = std::move(edgelist_minors); - auto diagonal_weights = edgelist_weights ? std::make_optional>( - diagonal_majors.size(), handle.get_stream()) - : std::nullopt; - auto upper_triangular_weights = edgelist_weights - ? std::make_optional>( - upper_triangular_majors.size(), handle.get_stream()) - : std::nullopt; + std::optional> diagonal_weights{std::nullopt}; + std::optional> diagonal_edge_ids{std::nullopt}; + std::optional> diagonal_edge_types{std::nullopt}; + std::optional> diagonal_edge_start_times{std::nullopt}; + std::optional> diagonal_edge_end_times{std::nullopt}; + std::optional> upper_triangular_weights{std::nullopt}; + std::optional> upper_triangular_edge_ids{std::nullopt}; + std::optional> upper_triangular_edge_types{std::nullopt}; + std::optional> upper_triangular_edge_start_times{std::nullopt}; + std::optional> upper_triangular_edge_end_times{std::nullopt}; + if (edgelist_weights) { + diagonal_weights = rmm::device_uvector(num_diagonal_edges, handle.get_stream()); + upper_triangular_weights = + rmm::device_uvector(upper_triangular_majors.size(), handle.get_stream()); thrust::copy(handle.get_thrust_policy(), - (*edgelist_weights).begin() + num_lower_triangular_edges, - (*edgelist_weights).begin() + num_lower_triangular_edges + num_diagonal_edges, - (*diagonal_weights).begin()); + edgelist_weights->begin() + num_lower_triangular_edges, + edgelist_weights->begin() + num_lower_triangular_edges + num_diagonal_edges, + diagonal_weights->begin()); thrust::copy(handle.get_thrust_policy(), - (*edgelist_weights).begin() + num_lower_triangular_edges + num_diagonal_edges, - (*edgelist_weights).end(), - (*upper_triangular_weights).begin()); - (*edgelist_weights).resize(lower_triangular_majors.size(), handle.get_stream()); - (*edgelist_weights).shrink_to_fit(handle.get_stream()); + edgelist_weights->begin() + num_lower_triangular_edges + num_diagonal_edges, + edgelist_weights->end(), + upper_triangular_weights->begin()); + edgelist_weights->resize(lower_triangular_majors.size(), handle.get_stream()); + edgelist_weights->shrink_to_fit(handle.get_stream()); } auto lower_triangular_weights = std::move(edgelist_weights); + if (edgelist_edge_ids) { + diagonal_edge_ids = rmm::device_uvector(num_diagonal_edges, handle.get_stream()); + upper_triangular_edge_ids = + rmm::device_uvector(upper_triangular_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + edgelist_edge_ids->begin() + num_lower_triangular_edges, + edgelist_edge_ids->begin() + num_lower_triangular_edges + num_diagonal_edges, + diagonal_edge_ids->begin()); + thrust::copy(handle.get_thrust_policy(), + edgelist_edge_ids->begin() + num_lower_triangular_edges + num_diagonal_edges, + edgelist_edge_ids->end(), + upper_triangular_edge_ids->begin()); + edgelist_edge_ids->resize(lower_triangular_majors.size(), handle.get_stream()); + edgelist_edge_ids->shrink_to_fit(handle.get_stream()); + } + auto lower_triangular_edge_ids = std::move(edgelist_edge_ids); + + if (edgelist_edge_types) { + diagonal_edge_types = rmm::device_uvector(num_diagonal_edges, handle.get_stream()); + upper_triangular_edge_types = + rmm::device_uvector(upper_triangular_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + edgelist_edge_types->begin() + num_lower_triangular_edges, + edgelist_edge_types->begin() + num_lower_triangular_edges + num_diagonal_edges, + diagonal_edge_types->begin()); + thrust::copy(handle.get_thrust_policy(), + edgelist_edge_types->begin() + num_lower_triangular_edges + num_diagonal_edges, + edgelist_edge_types->end(), + upper_triangular_edge_types->begin()); + edgelist_edge_types->resize(lower_triangular_majors.size(), handle.get_stream()); + edgelist_edge_types->shrink_to_fit(handle.get_stream()); + } + auto lower_triangular_edge_types = std::move(edgelist_edge_types); + + if (edgelist_edge_start_times) { + diagonal_edge_start_times = + rmm::device_uvector(num_diagonal_edges, handle.get_stream()); + upper_triangular_edge_start_times = + rmm::device_uvector(upper_triangular_majors.size(), handle.get_stream()); + thrust::copy( + handle.get_thrust_policy(), + edgelist_edge_start_times->begin() + num_lower_triangular_edges, + edgelist_edge_start_times->begin() + num_lower_triangular_edges + num_diagonal_edges, + diagonal_edge_start_times->begin()); + thrust::copy( + handle.get_thrust_policy(), + edgelist_edge_start_times->begin() + num_lower_triangular_edges + num_diagonal_edges, + edgelist_edge_start_times->end(), + upper_triangular_edge_start_times->begin()); + edgelist_edge_start_times->resize(lower_triangular_majors.size(), handle.get_stream()); + edgelist_edge_start_times->shrink_to_fit(handle.get_stream()); + } + auto lower_triangular_edge_start_times = std::move(edgelist_edge_start_times); + + if (edgelist_edge_end_times) { + diagonal_edge_end_times = + rmm::device_uvector(num_diagonal_edges, handle.get_stream()); + upper_triangular_edge_end_times = + rmm::device_uvector(upper_triangular_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + edgelist_edge_end_times->begin() + num_lower_triangular_edges, + edgelist_edge_end_times->begin() + num_lower_triangular_edges + num_diagonal_edges, + diagonal_edge_end_times->begin()); + thrust::copy(handle.get_thrust_policy(), + edgelist_edge_end_times->begin() + num_lower_triangular_edges + num_diagonal_edges, + edgelist_edge_end_times->end(), + upper_triangular_edge_end_times->begin()); + edgelist_edge_end_times->resize(lower_triangular_majors.size(), handle.get_stream()); + edgelist_edge_end_times->shrink_to_fit(handle.get_stream()); + } + auto lower_triangular_edge_end_times = std::move(edgelist_edge_end_times); + // 2. shuffle the (to-be-flipped) upper triangular edges if constexpr (multi_gpu) { std::tie(upper_triangular_minors, upper_triangular_majors, upper_triangular_weights, - std::ignore, - std::ignore, + upper_triangular_edge_ids, + upper_triangular_edge_types, + upper_triangular_edge_start_times, + upper_triangular_edge_end_times, std::ignore) = detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning>(0, handle.get_stream()) : std::nullopt; - if (edgelist_weights) { - auto lower_triangular_edge_first = - thrust::make_zip_iterator(thrust::make_tuple(lower_triangular_majors.begin(), - lower_triangular_minors.begin(), - (*lower_triangular_weights).begin())); - thrust::sort(handle.get_thrust_policy(), - lower_triangular_edge_first, - lower_triangular_edge_first + lower_triangular_majors.size()); - auto upper_triangular_edge_first = thrust::make_zip_iterator(thrust::make_tuple( - upper_triangular_majors.begin(), - upper_triangular_minors.begin(), - (*upper_triangular_weights) - .begin())); // do not flip here to use "lower_triangular = major > minor" - thrust::sort(handle.get_thrust_policy(), - upper_triangular_edge_first, - upper_triangular_edge_first + upper_triangular_majors.size(), - compare_upper_triangular_edges_as_lower_triangular_t{}); - - merged_lower_triangular_majors.resize( - lower_triangular_majors.size() + upper_triangular_majors.size(), handle.get_stream()); - merged_lower_triangular_minors.resize(merged_lower_triangular_majors.size(), - handle.get_stream()); - (*merged_lower_triangular_weights) - .resize(merged_lower_triangular_majors.size(), handle.get_stream()); - auto merged_first = - thrust::make_zip_iterator(thrust::make_tuple(merged_lower_triangular_majors.begin(), - merged_lower_triangular_minors.begin(), - (*merged_lower_triangular_weights).begin())); - thrust::merge(handle.get_thrust_policy(), - lower_triangular_edge_first, - lower_triangular_edge_first + lower_triangular_majors.size(), - upper_triangular_edge_first, - upper_triangular_edge_first + upper_triangular_majors.size(), - merged_first, - compare_lower_and_upper_triangular_edges_t{}); - - lower_triangular_majors.resize(0, handle.get_stream()); - lower_triangular_majors.shrink_to_fit(handle.get_stream()); - lower_triangular_minors.resize(0, handle.get_stream()); - lower_triangular_minors.shrink_to_fit(handle.get_stream()); - (*lower_triangular_weights).resize(0, handle.get_stream()); - (*lower_triangular_weights).shrink_to_fit(handle.get_stream()); - - upper_triangular_majors.resize(0, handle.get_stream()); - upper_triangular_majors.shrink_to_fit(handle.get_stream()); - upper_triangular_minors.resize(0, handle.get_stream()); - upper_triangular_minors.shrink_to_fit(handle.get_stream()); - (*upper_triangular_weights).resize(0, handle.get_stream()); - (*upper_triangular_weights).shrink_to_fit(handle.get_stream()); + auto merged_lower_triangular_edge_ids = + edgelist_edge_ids ? std::make_optional>(0, handle.get_stream()) + : std::nullopt; + auto merged_lower_triangular_edge_types = + edgelist_edge_types + ? std::make_optional>(0, handle.get_stream()) + : std::nullopt; + auto merged_lower_triangular_edge_start_times = + edgelist_edge_start_times + ? std::make_optional>(0, handle.get_stream()) + : std::nullopt; + auto merged_lower_triangular_edge_end_times = + edgelist_edge_end_times + ? std::make_optional>(0, handle.get_stream()) + : std::nullopt; - rmm::device_uvector includes(merged_lower_triangular_majors.size(), - handle.get_stream()); - symmetrize_op_t symm_op{reciprocal}; - thrust::for_each( - handle.get_thrust_policy(), - thrust::make_counting_iterator(size_t{0}), - thrust::make_counting_iterator(merged_lower_triangular_majors.size()), - update_edge_weights_and_flags_t{ - merged_first, includes.data(), merged_lower_triangular_majors.size(), symm_op}); - - auto merged_edge_and_flag_first = - thrust::make_zip_iterator(thrust::make_tuple(merged_lower_triangular_majors.begin(), - merged_lower_triangular_minors.begin(), - (*merged_lower_triangular_weights).begin(), - includes.begin())); - merged_lower_triangular_majors.resize( - thrust::distance( - merged_edge_and_flag_first, - thrust::remove_if(handle.get_thrust_policy(), - merged_edge_and_flag_first, - merged_edge_and_flag_first + merged_lower_triangular_majors.size(), - [] __device__(auto t) { return !thrust::get<3>(t); })), - handle.get_stream()); - merged_lower_triangular_majors.shrink_to_fit(handle.get_stream()); - merged_lower_triangular_minors.resize(merged_lower_triangular_majors.size(), - handle.get_stream()); - merged_lower_triangular_minors.shrink_to_fit(handle.get_stream()); - (*merged_lower_triangular_weights) - .resize(merged_lower_triangular_majors.size(), handle.get_stream()); - (*merged_lower_triangular_weights).shrink_to_fit(handle.get_stream()); - - auto merged_major_minor_range_first = thrust::make_zip_iterator(thrust::make_tuple( - merged_lower_triangular_majors.begin(), merged_lower_triangular_minors.begin())); - thrust::transform(handle.get_thrust_policy(), - merged_major_minor_range_first, - merged_major_minor_range_first + merged_lower_triangular_majors.size(), - merged_major_minor_range_first, - to_lower_triangular_t{}); + if (edge_property_count == 0) { + std::tie(merged_lower_triangular_majors, merged_lower_triangular_minors) = + merge_lower_triangular(handle, + std::move(lower_triangular_majors), + std::move(lower_triangular_minors), + std::move(upper_triangular_majors), + std::move(upper_triangular_minors), + num_lower_triangular_edges, + reciprocal); + } else if (edge_property_count == 1) { + if (edgelist_weights) { + std::tie(merged_lower_triangular_majors, + merged_lower_triangular_minors, + merged_lower_triangular_weights) = + merge_lower_triangular(handle, + std::move(lower_triangular_majors), + std::move(lower_triangular_minors), + std::move(*lower_triangular_weights), + std::move(upper_triangular_majors), + std::move(upper_triangular_minors), + std::move(*upper_triangular_weights), + num_lower_triangular_edges, + reciprocal); + } else if (edgelist_edge_ids) { + std::tie(merged_lower_triangular_majors, + merged_lower_triangular_minors, + merged_lower_triangular_edge_ids) = + merge_lower_triangular(handle, + std::move(lower_triangular_majors), + std::move(lower_triangular_minors), + std::move(*lower_triangular_edge_ids), + std::move(upper_triangular_majors), + std::move(upper_triangular_minors), + std::move(*upper_triangular_edge_ids), + num_lower_triangular_edges, + reciprocal); + } else if (edgelist_edge_types) { + std::tie(merged_lower_triangular_majors, + merged_lower_triangular_minors, + merged_lower_triangular_edge_types) = + merge_lower_triangular(handle, + std::move(lower_triangular_majors), + std::move(lower_triangular_minors), + std::move(*lower_triangular_edge_types), + std::move(upper_triangular_majors), + std::move(upper_triangular_minors), + std::move(*upper_triangular_edge_types), + num_lower_triangular_edges, + reciprocal); + } else if (edgelist_edge_start_times) { + std::tie(merged_lower_triangular_majors, + merged_lower_triangular_minors, + merged_lower_triangular_edge_start_times) = + merge_lower_triangular(handle, + std::move(lower_triangular_majors), + std::move(lower_triangular_minors), + std::move(*lower_triangular_edge_start_times), + std::move(upper_triangular_majors), + std::move(upper_triangular_minors), + std::move(*upper_triangular_edge_start_times), + num_lower_triangular_edges, + reciprocal); + } else if (edgelist_edge_end_times) { + std::tie(merged_lower_triangular_majors, + merged_lower_triangular_minors, + merged_lower_triangular_edge_end_times) = + merge_lower_triangular(handle, + std::move(lower_triangular_majors), + std::move(lower_triangular_minors), + std::move(*lower_triangular_edge_end_times), + std::move(upper_triangular_majors), + std::move(upper_triangular_minors), + std::move(*upper_triangular_edge_end_times), + num_lower_triangular_edges, + reciprocal); + } } else { - auto lower_triangular_edge_first = thrust::make_zip_iterator( - thrust::make_tuple(lower_triangular_majors.begin(), lower_triangular_minors.begin())); - thrust::sort(handle.get_thrust_policy(), - lower_triangular_edge_first, - lower_triangular_edge_first + lower_triangular_majors.size()); - auto upper_triangular_edge_first = thrust::make_zip_iterator(thrust::make_tuple( - upper_triangular_minors.begin(), upper_triangular_majors.begin())); // flip - thrust::sort(handle.get_thrust_policy(), - upper_triangular_edge_first, - upper_triangular_edge_first + upper_triangular_majors.size()); - - merged_lower_triangular_majors.resize( - reciprocal ? std::min(num_lower_triangular_edges, upper_triangular_majors.size()) - : num_lower_triangular_edges + upper_triangular_majors.size(), - handle.get_stream()); - merged_lower_triangular_minors.resize(merged_lower_triangular_majors.size(), - handle.get_stream()); - auto merged_first = thrust::make_zip_iterator(thrust::make_tuple( - merged_lower_triangular_majors.begin(), merged_lower_triangular_minors.begin())); - auto merged_last = - reciprocal - ? thrust::set_intersection(handle.get_thrust_policy(), - lower_triangular_edge_first, - lower_triangular_edge_first + lower_triangular_majors.size(), - upper_triangular_edge_first, - upper_triangular_edge_first + upper_triangular_majors.size(), - merged_first) - : thrust::set_union(handle.get_thrust_policy(), - lower_triangular_edge_first, - lower_triangular_edge_first + lower_triangular_majors.size(), - upper_triangular_edge_first, - upper_triangular_edge_first + upper_triangular_majors.size(), - merged_first); - - lower_triangular_majors.resize(0, handle.get_stream()); - lower_triangular_majors.shrink_to_fit(handle.get_stream()); - lower_triangular_minors.resize(0, handle.get_stream()); - lower_triangular_minors.shrink_to_fit(handle.get_stream()); - - upper_triangular_majors.resize(0, handle.get_stream()); - upper_triangular_majors.shrink_to_fit(handle.get_stream()); - upper_triangular_minors.resize(0, handle.get_stream()); - upper_triangular_minors.shrink_to_fit(handle.get_stream()); - - merged_lower_triangular_majors.resize(thrust::distance(merged_first, merged_last), - handle.get_stream()); - merged_lower_triangular_majors.shrink_to_fit(handle.get_stream()); - merged_lower_triangular_minors.resize(merged_lower_triangular_majors.size(), - handle.get_stream()); - merged_lower_triangular_minors.shrink_to_fit(handle.get_stream()); + rmm::device_uvector property_position( + lower_triangular_majors.size() + upper_triangular_majors.size(), handle.get_stream()); + detail::sequence_fill( + handle.get_stream(), property_position.data(), property_position.size(), edge_t{0}); + + std::tie(merged_lower_triangular_majors, merged_lower_triangular_minors, property_position) = + merge_lower_triangular(handle, + std::move(lower_triangular_majors), + std::move(lower_triangular_minors), + std::move(property_position), + std::move(upper_triangular_majors), + std::move(upper_triangular_minors), + std::move(property_position), + num_lower_triangular_edges, + reciprocal); + + if (edgelist_weights) { + merged_lower_triangular_weights->resize(merged_lower_triangular_majors.size(), + handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + thrust::make_transform_iterator( + edgelist_weights->begin(), + pick_from_lower_upper_t{ + raft::device_span{lower_triangular_weights->data(), + lower_triangular_weights->size()}, + raft::device_span{upper_triangular_weights->data(), + upper_triangular_weights->size()}}), + merged_lower_triangular_weights->begin()); + } + if (edgelist_edge_ids) { + merged_lower_triangular_edge_ids->resize(merged_lower_triangular_majors.size(), + handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + thrust::make_transform_iterator( + edgelist_edge_ids->begin(), + pick_from_lower_upper_t{ + raft::device_span{lower_triangular_edge_ids->data(), + lower_triangular_edge_ids->size()}, + raft::device_span{upper_triangular_edge_ids->data(), + upper_triangular_edge_ids->size()}}), + merged_lower_triangular_edge_ids->begin()); + } + if (edgelist_edge_types) { + merged_lower_triangular_edge_types->resize(merged_lower_triangular_majors.size(), + handle.get_stream()); + + thrust::gather( + handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + thrust::make_transform_iterator( + edgelist_edge_types->begin(), + pick_from_lower_upper_t{ + raft::device_span{lower_triangular_edge_types->data(), + lower_triangular_edge_types->size()}, + raft::device_span{upper_triangular_edge_types->data(), + upper_triangular_edge_types->size()}}), + merged_lower_triangular_edge_types->begin()); + } + if (edgelist_edge_start_times) { + merged_lower_triangular_edge_start_times->resize(merged_lower_triangular_majors.size(), + handle.get_stream()); + + thrust::gather( + handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + thrust::make_transform_iterator( + edgelist_edge_start_times->begin(), + pick_from_lower_upper_t{ + raft::device_span{lower_triangular_edge_start_times->data(), + lower_triangular_edge_start_times->size()}, + raft::device_span{upper_triangular_edge_start_times->data(), + upper_triangular_edge_start_times->size()}}), + merged_lower_triangular_edge_start_times->begin()); + } + if (edgelist_edge_end_times) { + merged_lower_triangular_edge_end_times->resize(merged_lower_triangular_majors.size(), + handle.get_stream()); + + thrust::gather( + handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + thrust::make_transform_iterator( + edgelist_edge_end_times->begin(), + pick_from_lower_upper_t{ + raft::device_span{lower_triangular_edge_end_times->data(), + lower_triangular_edge_end_times->size()}, + raft::device_span{upper_triangular_edge_end_times->data(), + upper_triangular_edge_end_times->size()}}), + merged_lower_triangular_edge_end_times->begin()); + } } // 4. symmetrize from the merged lower triangular edges & diagonal edges @@ -476,29 +949,67 @@ symmetrize_edgelist(raft::handle_t const& handle, (*merged_lower_triangular_weights).end(), (*upper_triangular_weights).begin()); } + if (edgelist_edge_ids) { + (*upper_triangular_edge_ids).resize(upper_triangular_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + (*merged_lower_triangular_edge_ids).begin(), + (*merged_lower_triangular_edge_ids).end(), + (*upper_triangular_edge_ids).begin()); + } + if (edgelist_edge_types) { + (*upper_triangular_edge_types).resize(upper_triangular_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + (*merged_lower_triangular_edge_types).begin(), + (*merged_lower_triangular_edge_types).end(), + (*upper_triangular_edge_types).begin()); + } + if (edgelist_edge_start_times) { + (*upper_triangular_edge_start_times) + .resize(upper_triangular_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + (*merged_lower_triangular_edge_start_times).begin(), + (*merged_lower_triangular_edge_start_times).end(), + (*upper_triangular_edge_start_times).begin()); + } + if (edgelist_edge_end_times) { + (*upper_triangular_edge_end_times).resize(upper_triangular_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + (*merged_lower_triangular_edge_end_times).begin(), + (*merged_lower_triangular_edge_end_times).end(), + (*upper_triangular_edge_end_times).begin()); + } if constexpr (multi_gpu) { std::tie(upper_triangular_majors, upper_triangular_minors, upper_triangular_weights, - std::ignore, - std::ignore, + upper_triangular_edge_ids, + upper_triangular_edge_types, + upper_triangular_edge_start_times, + upper_triangular_edge_end_times, std::ignore) = detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + edge_type_t, + edge_time_t>( handle, std::move(upper_triangular_majors), std::move(upper_triangular_minors), std::move(upper_triangular_weights), - std::nullopt, - std::nullopt); + std::move(upper_triangular_edge_ids), + std::move(upper_triangular_edge_types), + std::move(upper_triangular_edge_start_times), + std::move(upper_triangular_edge_end_times)); } - edgelist_majors = std::move(merged_lower_triangular_majors); - edgelist_minors = std::move(merged_lower_triangular_minors); - edgelist_weights = std::move(merged_lower_triangular_weights); + edgelist_majors = std::move(merged_lower_triangular_majors); + edgelist_minors = std::move(merged_lower_triangular_minors); + edgelist_weights = std::move(merged_lower_triangular_weights); + edgelist_edge_ids = std::move(merged_lower_triangular_edge_ids); + edgelist_edge_types = std::move(merged_lower_triangular_edge_types); + edgelist_edge_start_times = std::move(merged_lower_triangular_edge_start_times); + edgelist_edge_end_times = std::move(merged_lower_triangular_edge_end_times); edgelist_majors.resize( edgelist_majors.size() + diagonal_majors.size() + upper_triangular_majors.size(), @@ -546,8 +1057,81 @@ symmetrize_edgelist(raft::handle_t const& handle, (*upper_triangular_weights).shrink_to_fit(handle.get_stream()); } - return std::make_tuple( - std::move(edgelist_majors), std::move(edgelist_minors), std::move(edgelist_weights)); + if (edgelist_edge_ids) { + (*edgelist_edge_ids).resize(edgelist_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + (*diagonal_edge_ids).begin(), + (*diagonal_edge_ids).end(), + (*edgelist_edge_ids).end() - (*diagonal_edge_ids).size() - + (*upper_triangular_edge_ids).size()); + thrust::copy(handle.get_thrust_policy(), + (*upper_triangular_edge_ids).begin(), + (*upper_triangular_edge_ids).end(), + (*edgelist_edge_ids).end() - (*upper_triangular_edge_ids).size()); + (*diagonal_edge_ids).resize(0, handle.get_stream()); + (*diagonal_edge_ids).shrink_to_fit(handle.get_stream()); + (*upper_triangular_edge_ids).resize(0, handle.get_stream()); + (*upper_triangular_edge_ids).shrink_to_fit(handle.get_stream()); + } + + if (edgelist_edge_types) { + (*edgelist_edge_types).resize(edgelist_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + (*diagonal_edge_types).begin(), + (*diagonal_edge_types).end(), + (*edgelist_edge_types).end() - (*diagonal_edge_types).size() - + (*upper_triangular_edge_types).size()); + thrust::copy(handle.get_thrust_policy(), + (*upper_triangular_edge_types).begin(), + (*upper_triangular_edge_types).end(), + (*edgelist_edge_types).end() - (*upper_triangular_edge_types).size()); + (*diagonal_edge_types).resize(0, handle.get_stream()); + (*diagonal_edge_types).shrink_to_fit(handle.get_stream()); + (*upper_triangular_edge_types).resize(0, handle.get_stream()); + (*upper_triangular_edge_types).shrink_to_fit(handle.get_stream()); + } + + if (edgelist_edge_start_times) { + (*edgelist_edge_start_times).resize(edgelist_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + (*diagonal_edge_start_times).begin(), + (*diagonal_edge_start_times).end(), + (*edgelist_edge_start_times).end() - (*diagonal_edge_start_times).size() - + (*upper_triangular_edge_start_times).size()); + thrust::copy(handle.get_thrust_policy(), + (*upper_triangular_edge_start_times).begin(), + (*upper_triangular_edge_start_times).end(), + (*edgelist_edge_start_times).end() - (*upper_triangular_edge_start_times).size()); + (*diagonal_edge_start_times).resize(0, handle.get_stream()); + (*diagonal_edge_start_times).shrink_to_fit(handle.get_stream()); + (*upper_triangular_edge_start_times).resize(0, handle.get_stream()); + (*upper_triangular_edge_start_times).shrink_to_fit(handle.get_stream()); + } + + if (edgelist_edge_end_times) { + (*edgelist_edge_end_times).resize(edgelist_majors.size(), handle.get_stream()); + thrust::copy(handle.get_thrust_policy(), + (*diagonal_edge_end_times).begin(), + (*diagonal_edge_end_times).end(), + (*edgelist_edge_end_times).end() - (*diagonal_edge_end_times).size() - + (*upper_triangular_edge_end_times).size()); + thrust::copy(handle.get_thrust_policy(), + (*upper_triangular_edge_end_times).begin(), + (*upper_triangular_edge_end_times).end(), + (*edgelist_edge_end_times).end() - (*upper_triangular_edge_end_times).size()); + (*diagonal_edge_end_times).resize(0, handle.get_stream()); + (*diagonal_edge_end_times).shrink_to_fit(handle.get_stream()); + (*upper_triangular_edge_end_times).resize(0, handle.get_stream()); + (*upper_triangular_edge_end_times).shrink_to_fit(handle.get_stream()); + } + + return std::make_tuple(std::move(edgelist_majors), + std::move(edgelist_minors), + std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times)); } } // namespace detail @@ -564,17 +1148,78 @@ symmetrize_edgelist(raft::handle_t const& handle, { rmm::device_uvector edgelist_majors(0, handle.get_stream()); rmm::device_uvector edgelist_minors(0, handle.get_stream()); - std::tie(edgelist_majors, edgelist_minors, edgelist_weights) = - detail::symmetrize_edgelist( + std::tie(edgelist_majors, + edgelist_minors, + edgelist_weights, + std::ignore, + std::ignore, + std::ignore, + std::ignore) = + detail::symmetrize_edgelist( + handle, + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + reciprocal); + + return std::make_tuple( + std::move(edgelist_majors), std::move(edgelist_minors), std::move(edgelist_weights)); +} + +template +std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist(raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool reciprocal) +{ + rmm::device_uvector edgelist_majors(0, handle.get_stream()); + rmm::device_uvector edgelist_minors(0, handle.get_stream()); + std::tie(edgelist_majors, + edgelist_minors, + edgelist_weights, + edgelist_edge_ids, + edgelist_edge_types, + edgelist_edge_start_times, + edgelist_edge_end_times) = + detail::symmetrize_edgelist( handle, - store_transposed ? std::move(edgelist_dsts) : std::move(edgelist_srcs), - store_transposed ? std::move(edgelist_srcs) : std::move(edgelist_dsts), + std::move(edgelist_srcs), + std::move(edgelist_dsts), std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times), reciprocal); - return std::make_tuple(store_transposed ? std::move(edgelist_minors) : std::move(edgelist_majors), - store_transposed ? std::move(edgelist_majors) : std::move(edgelist_minors), - std::move(edgelist_weights)); + return std::make_tuple(std::move(edgelist_majors), + std::move(edgelist_minors), + std::move(edgelist_weights), + std::move(edgelist_edge_ids), + std::move(edgelist_edge_types), + std::move(edgelist_edge_start_times), + std::move(edgelist_edge_end_times)); } } // namespace cugraph diff --git a/cpp/src/structure/symmetrize_edgelist_mg_v32_e32.cu b/cpp/src/structure/symmetrize_edgelist_mg_v32_e32.cu index da744a410c0..bf2ac1f741b 100644 --- a/cpp/src/structure/symmetrize_edgelist_mg_v32_e32.cu +++ b/cpp/src/structure/symmetrize_edgelist_mg_v32_e32.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,4 +59,76 @@ symmetrize_edgelist( std::optional>&& edgelist_weights, bool reciprocal); +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( + raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool reciprocal); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( + raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool reciprocal); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( + raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool reciprocal); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( + raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool reciprocal); + } // namespace cugraph diff --git a/cpp/src/structure/symmetrize_edgelist_mg_v64_e64.cu b/cpp/src/structure/symmetrize_edgelist_mg_v64_e64.cu index c4192fef43b..0713e5cae09 100644 --- a/cpp/src/structure/symmetrize_edgelist_mg_v64_e64.cu +++ b/cpp/src/structure/symmetrize_edgelist_mg_v64_e64.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,4 +59,76 @@ symmetrize_edgelist( std::optional>&& edgelist_weights, bool reciprocal); +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( + raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool reciprocal); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( + raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool reciprocal); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( + raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool reciprocal); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( + raft::handle_t const& handle, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, + bool reciprocal); + } // namespace cugraph diff --git a/cpp/src/structure/symmetrize_edgelist_sg_v32_e32.cu b/cpp/src/structure/symmetrize_edgelist_sg_v32_e32.cu index 6b446627b3f..de3038415a7 100644 --- a/cpp/src/structure/symmetrize_edgelist_sg_v32_e32.cu +++ b/cpp/src/structure/symmetrize_edgelist_sg_v32_e32.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,44 +59,76 @@ symmetrize_edgelist( std::optional>&& edgelist_weights, bool reciprocal); -template std::tuple, - rmm::device_uvector, - std::optional>> -symmetrize_edgelist( +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( raft::handle_t const& handle, - rmm::device_uvector&& edgelist_srcs, - rmm::device_uvector&& edgelist_dsts, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool reciprocal); -template std::tuple, - rmm::device_uvector, - std::optional>> -symmetrize_edgelist( +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( raft::handle_t const& handle, - rmm::device_uvector&& edgelist_srcs, - rmm::device_uvector&& edgelist_dsts, - std::optional>&& edgelist_weights, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool reciprocal); -template std::tuple, - rmm::device_uvector, - std::optional>> -symmetrize_edgelist( +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( raft::handle_t const& handle, - rmm::device_uvector&& edgelist_srcs, - rmm::device_uvector&& edgelist_dsts, - std::optional>&& edgelist_weights, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool reciprocal); -template std::tuple, - rmm::device_uvector, - std::optional>> -symmetrize_edgelist( +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( raft::handle_t const& handle, - rmm::device_uvector&& edgelist_srcs, - rmm::device_uvector&& edgelist_dsts, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool reciprocal); } // namespace cugraph diff --git a/cpp/src/structure/symmetrize_edgelist_sg_v64_e64.cu b/cpp/src/structure/symmetrize_edgelist_sg_v64_e64.cu index 6b446627b3f..788e764a931 100644 --- a/cpp/src/structure/symmetrize_edgelist_sg_v64_e64.cu +++ b/cpp/src/structure/symmetrize_edgelist_sg_v64_e64.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,84 +19,116 @@ namespace cugraph { // SG instantiation -template std::tuple, - rmm::device_uvector, +template std::tuple, + rmm::device_uvector, std::optional>> -symmetrize_edgelist( +symmetrize_edgelist( raft::handle_t const& handle, - rmm::device_uvector&& edgelist_srcs, - rmm::device_uvector&& edgelist_dsts, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, bool reciprocal); -template std::tuple, - rmm::device_uvector, +template std::tuple, + rmm::device_uvector, std::optional>> -symmetrize_edgelist( +symmetrize_edgelist( raft::handle_t const& handle, - rmm::device_uvector&& edgelist_srcs, - rmm::device_uvector&& edgelist_dsts, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, bool reciprocal); -template std::tuple, - rmm::device_uvector, +template std::tuple, + rmm::device_uvector, std::optional>> -symmetrize_edgelist( +symmetrize_edgelist( raft::handle_t const& handle, - rmm::device_uvector&& edgelist_srcs, - rmm::device_uvector&& edgelist_dsts, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, bool reciprocal); -template std::tuple, - rmm::device_uvector, +template std::tuple, + rmm::device_uvector, std::optional>> -symmetrize_edgelist( +symmetrize_edgelist( raft::handle_t const& handle, - rmm::device_uvector&& edgelist_srcs, - rmm::device_uvector&& edgelist_dsts, + rmm::device_uvector&& edgelist_srcs, + rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, bool reciprocal); template std::tuple, rmm::device_uvector, - std::optional>> -symmetrize_edgelist( + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool reciprocal); template std::tuple, rmm::device_uvector, - std::optional>> -symmetrize_edgelist( + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, - std::optional>&& edgelist_weights, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool reciprocal); template std::tuple, rmm::device_uvector, - std::optional>> -symmetrize_edgelist( + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, - std::optional>&& edgelist_weights, + std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool reciprocal); template std::tuple, rmm::device_uvector, - std::optional>> -symmetrize_edgelist( + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +symmetrize_edgelist( raft::handle_t const& handle, rmm::device_uvector&& edgelist_srcs, rmm::device_uvector&& edgelist_dsts, std::optional>&& edgelist_weights, + std::optional>&& edgelist_edge_ids, + std::optional>&& edgelist_edge_types, + std::optional>&& edgelist_edge_start_times, + std::optional>&& edgelist_edge_end_times, bool reciprocal); } // namespace cugraph diff --git a/cpp/src/structure/symmetrize_graph_impl.cuh b/cpp/src/structure/symmetrize_graph_impl.cuh index ae8f2b0a608..aeae7361163 100644 --- a/cpp/src/structure/symmetrize_graph_impl.cuh +++ b/cpp/src/structure/symmetrize_graph_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,12 +91,22 @@ symmetrize_graph_impl( (*renumber_map).size())); graph = graph_t(handle); - std::tie(edgelist_srcs, edgelist_dsts, edgelist_weights) = - symmetrize_edgelist( + std::tie(edgelist_srcs, + edgelist_dsts, + edgelist_weights, + std::ignore, + std::ignore, + std::ignore, + std::ignore) = + symmetrize_edgelist( handle, std::move(edgelist_srcs), std::move(edgelist_dsts), std::move(edgelist_weights), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, reciprocal); graph_t symmetrized_graph(handle); @@ -106,21 +116,16 @@ symmetrize_graph_impl( std::optional> new_renumber_map{std::nullopt}; std::tie( symmetrized_graph, symmetrized_edge_weights, std::ignore, std::ignore, new_renumber_map) = - create_graph_from_edgelist(handle, - std::move(renumber_map), - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(edgelist_weights), - std::nullopt, - std::nullopt, - graph_properties_t{true, is_multigraph}, - true); + create_graph_from_edgelist( + handle, + std::move(renumber_map), + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::nullopt, + std::nullopt, + graph_properties_t{true, is_multigraph}, + true); return std::make_tuple( std::move(symmetrized_graph), std::move(symmetrized_edge_weights), std::move(new_renumber_map)); @@ -184,12 +189,22 @@ symmetrize_graph_impl( : std::nullopt); graph = graph_t(handle); - std::tie(edgelist_srcs, edgelist_dsts, edgelist_weights) = - symmetrize_edgelist( + std::tie(edgelist_srcs, + edgelist_dsts, + edgelist_weights, + std::ignore, + std::ignore, + std::ignore, + std::ignore) = + symmetrize_edgelist( handle, std::move(edgelist_srcs), std::move(edgelist_dsts), std::move(edgelist_weights), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, reciprocal); auto vertices = renumber ? std::move(renumber_map) @@ -207,21 +222,16 @@ symmetrize_graph_impl( std::optional> new_renumber_map{std::nullopt}; std::tie( symmetrized_graph, symmetrized_edge_weights, std::ignore, std::ignore, new_renumber_map) = - create_graph_from_edgelist(handle, - std::move(vertices), - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(edgelist_weights), - std::nullopt, - std::nullopt, - graph_properties_t{true, is_multigraph}, - renumber); + create_graph_from_edgelist( + handle, + std::move(vertices), + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::nullopt, + std::nullopt, + graph_properties_t{true, is_multigraph}, + renumber); return std::make_tuple( std::move(symmetrized_graph), std::move(symmetrized_edge_weights), std::move(new_renumber_map)); diff --git a/cpp/src/structure/transpose_graph_impl.cuh b/cpp/src/structure/transpose_graph_impl.cuh index 6786b52faed..28eff9f2edb 100644 --- a/cpp/src/structure/transpose_graph_impl.cuh +++ b/cpp/src/structure/transpose_graph_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -97,16 +97,21 @@ transpose_graph_impl( edgelist_weights, std::ignore, std::ignore, + std::ignore, + std::ignore, std::ignore) = detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( handle, std::move(store_transposed ? edgelist_srcs : edgelist_dsts), std::move(store_transposed ? edgelist_dsts : edgelist_srcs), std::move(edgelist_weights), std::nullopt, + std::nullopt, + std::nullopt, std::nullopt); graph_t transposed_graph(handle); @@ -115,21 +120,16 @@ transpose_graph_impl( transposed_edge_weights{}; std::optional> new_renumber_map{std::nullopt}; std::tie(transposed_graph, transposed_edge_weights, std::ignore, std::ignore, new_renumber_map) = - create_graph_from_edgelist(handle, - std::move(renumber_map), - std::move(edgelist_dsts), - std::move(edgelist_srcs), - std::move(edgelist_weights), - std::nullopt, - std::nullopt, - graph_properties_t{false, is_multigraph}, - true); + create_graph_from_edgelist( + handle, + std::move(renumber_map), + std::move(edgelist_dsts), + std::move(edgelist_srcs), + std::move(edgelist_weights), + std::nullopt, + std::nullopt, + graph_properties_t{false, is_multigraph}, + true); return std::make_tuple( std::move(transposed_graph), std::move(transposed_edge_weights), std::move(new_renumber_map)); @@ -205,21 +205,16 @@ transpose_graph_impl( transposed_edge_weights{}; std::optional> new_renumber_map{std::nullopt}; std::tie(transposed_graph, transposed_edge_weights, std::ignore, std::ignore, new_renumber_map) = - create_graph_from_edgelist(handle, - std::move(vertices), - std::move(edgelist_dsts), - std::move(edgelist_srcs), - std::move(edgelist_weights), - std::nullopt, - std::nullopt, - graph_properties_t{false, is_multigraph}, - renumber); + create_graph_from_edgelist( + handle, + std::move(vertices), + std::move(edgelist_dsts), + std::move(edgelist_srcs), + std::move(edgelist_weights), + std::nullopt, + std::nullopt, + graph_properties_t{false, is_multigraph}, + renumber); return std::make_tuple( std::move(transposed_graph), std::move(transposed_edge_weights), std::move(new_renumber_map)); diff --git a/cpp/src/structure/transpose_graph_storage_impl.cuh b/cpp/src/structure/transpose_graph_storage_impl.cuh index 374bfd05c40..a015782eb55 100644 --- a/cpp/src/structure/transpose_graph_storage_impl.cuh +++ b/cpp/src/structure/transpose_graph_storage_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -97,16 +97,21 @@ transpose_graph_storage_impl( edgelist_weights, std::ignore, std::ignore, + std::ignore, + std::ignore, std::ignore) = detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( handle, std::move(!store_transposed ? edgelist_dsts : edgelist_srcs), std::move(!store_transposed ? edgelist_srcs : edgelist_dsts), std::move(edgelist_weights), std::nullopt, + std::nullopt, + std::nullopt, std::nullopt); graph_t storage_transposed_graph(handle); @@ -119,21 +124,16 @@ transpose_graph_storage_impl( std::ignore, std::ignore, new_renumber_map) = - create_graph_from_edgelist(handle, - std::move(renumber_map), - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(edgelist_weights), - std::nullopt, - std::nullopt, - graph_properties_t{is_symmetric, is_multigraph}, - true); + create_graph_from_edgelist( + handle, + std::move(renumber_map), + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::nullopt, + std::nullopt, + graph_properties_t{is_symmetric, is_multigraph}, + true); return std::make_tuple(std::move(storage_transposed_graph), std::move(storage_transposed_edge_weights), @@ -214,21 +214,16 @@ transpose_graph_storage_impl( std::ignore, std::ignore, new_renumber_map) = - create_graph_from_edgelist(handle, - std::move(vertices), - std::move(edgelist_srcs), - std::move(edgelist_dsts), - std::move(edgelist_weights), - std::nullopt, - std::nullopt, - graph_properties_t{is_symmetric, is_multigraph}, - renumber); + create_graph_from_edgelist( + handle, + std::move(vertices), + std::move(edgelist_srcs), + std::move(edgelist_dsts), + std::move(edgelist_weights), + std::nullopt, + std::nullopt, + graph_properties_t{is_symmetric, is_multigraph}, + renumber); return std::make_tuple(std::move(storage_transposed_graph), std::move(storage_transposed_edge_weights), diff --git a/cpp/src/utilities/shuffle_vertex_pairs.cuh b/cpp/src/utilities/shuffle_vertex_pairs.cuh index 1cf2493cd28..a9b081b753c 100644 --- a/cpp/src/utilities/shuffle_vertex_pairs.cuh +++ b/cpp/src/utilities/shuffle_vertex_pairs.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,13 @@ #include "detail/graph_partition_utils.cuh" #include +#include #include #include #include #include +#include #include #include @@ -37,12 +39,15 @@ template std::tuple, rmm::device_uvector, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_vertex_pairs_with_values_by_gpu_id_impl( raft::handle_t const& handle, @@ -51,15 +56,41 @@ shuffle_vertex_pairs_with_values_by_gpu_id_impl( std::optional>&& weights, std::optional>&& edge_ids, std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, func_t func) { auto& comm = handle.get_comms(); auto const comm_size = comm.get_size(); + int edge_property_count = 0; + size_t element_size = sizeof(vertex_t) * 2; + + if (weights) { + ++edge_property_count; + element_size += sizeof(weight_t); + } + + if (edge_ids) { + ++edge_property_count; + element_size += sizeof(edge_t); + } + if (edge_types) { + ++edge_property_count; + element_size += sizeof(edge_type_t); + } + if (edge_start_times) { + ++edge_property_count; + element_size += sizeof(edge_time_t); + } + if (edge_end_times) { + ++edge_property_count; + element_size += sizeof(edge_time_t); + } + + if (edge_property_count > 1) { element_size = sizeof(vertex_t) * 2 + sizeof(size_t); } + auto total_global_mem = handle.get_device_properties().totalGlobalMem; - auto element_size = sizeof(vertex_t) * 2 + (weights ? sizeof(weight_t) : size_t{0}) + - (edge_ids ? sizeof(edge_t) : size_t{0}) + - (edge_types ? sizeof(edge_type_t) : size_t{0}); auto constexpr mem_frugal_ratio = 0.05; // if the expected temporary buffer size exceeds the mem_frugal_ratio of the // total_global_mem, switch to the memory frugal approach (thrust::sort is used to @@ -82,93 +113,129 @@ shuffle_vertex_pairs_with_values_by_gpu_id_impl( // (due to fragmentation) even when the remaining free memory in aggregate is significantly larger // than the requested size). - // FIXME: Consider a generic function that takes a value tuple of optionals - // to eliminate this complexity rmm::device_uvector d_tx_value_counts(0, handle.get_stream()); - if (weights) { - if (edge_ids) { - if (edge_types) { - d_tx_value_counts = cugraph::groupby_and_count( - thrust::make_zip_iterator(majors.begin(), - minors.begin(), - weights->begin(), - edge_ids->begin(), - edge_types->begin()), - thrust::make_zip_iterator( - majors.end(), minors.end(), weights->end(), edge_ids->end(), edge_types->end()), - [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - d_tx_value_counts = cugraph::groupby_and_count( - thrust::make_zip_iterator( - majors.begin(), minors.begin(), weights->begin(), edge_ids->begin()), - thrust::make_zip_iterator(majors.end(), minors.end(), weights->end(), edge_ids->end()), - [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } - } else { - if (edge_types) { - d_tx_value_counts = cugraph::groupby_and_count( - thrust::make_zip_iterator( - majors.begin(), minors.begin(), weights->begin(), edge_types->begin()), - thrust::make_zip_iterator(majors.end(), minors.end(), weights->end(), edge_types->end()), - [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - d_tx_value_counts = cugraph::groupby_and_count( - thrust::make_zip_iterator(majors.begin(), minors.begin(), weights->begin()), - thrust::make_zip_iterator(majors.end(), minors.end(), weights->end()), - [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } + if (edge_property_count == 0) { + d_tx_value_counts = cugraph::groupby_and_count( + thrust::make_zip_iterator(majors.begin(), minors.begin()), + thrust::make_zip_iterator(majors.end(), minors.end()), + [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_property_count == 1) { + if (weights) { + d_tx_value_counts = cugraph::groupby_and_count( + thrust::make_zip_iterator(majors.begin(), minors.begin(), weights->begin()), + thrust::make_zip_iterator(majors.end(), minors.end(), weights->end()), + [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_ids) { + d_tx_value_counts = cugraph::groupby_and_count( + thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_ids->begin()), + thrust::make_zip_iterator(majors.end(), minors.end(), edge_ids->end()), + [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_types) { + d_tx_value_counts = cugraph::groupby_and_count( + thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_types->begin()), + thrust::make_zip_iterator(majors.end(), minors.end(), edge_types->end()), + [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_start_times) { + d_tx_value_counts = cugraph::groupby_and_count( + thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_start_times->begin()), + thrust::make_zip_iterator(majors.end(), minors.end(), edge_start_times->end()), + [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + } else if (edge_end_times) { + d_tx_value_counts = cugraph::groupby_and_count( + thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_end_times->begin()), + thrust::make_zip_iterator(majors.end(), minors.end(), edge_end_times->end()), + [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, + comm_size, + mem_frugal_threshold, + handle.get_stream()); } } else { + rmm::device_uvector property_position(majors.size(), handle.get_stream()); + detail::sequence_fill( + handle.get_stream(), property_position.data(), property_position.size(), edge_t{0}); + + d_tx_value_counts = cugraph::groupby_and_count( + thrust::make_zip_iterator(majors.begin(), minors.begin(), property_position.begin()), + thrust::make_zip_iterator(majors.end(), minors.end(), property_position.end()), + [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, + comm_size, + mem_frugal_threshold, + handle.get_stream()); + + if (weights) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + weights->begin(), + tmp.begin()); + + weights = std::move(tmp); + } + if (edge_ids) { - if (edge_types) { - d_tx_value_counts = cugraph::groupby_and_count( - thrust::make_zip_iterator( - majors.begin(), minors.begin(), edge_ids->begin(), edge_types->begin()), - thrust::make_zip_iterator(majors.end(), minors.end(), edge_ids->end(), edge_types->end()), - [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - d_tx_value_counts = cugraph::groupby_and_count( - thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_ids->begin()), - thrust::make_zip_iterator(majors.end(), minors.end(), edge_ids->end()), - [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } - } else { - if (edge_types) { - d_tx_value_counts = cugraph::groupby_and_count( - thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_types->begin()), - thrust::make_zip_iterator(majors.end(), minors.end(), edge_types->end()), - [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } else { - d_tx_value_counts = cugraph::groupby_and_count( - thrust::make_zip_iterator(majors.begin(), minors.begin()), - thrust::make_zip_iterator(majors.end(), minors.end()), - [func] __device__(auto val) { return func(thrust::get<0>(val), thrust::get<1>(val)); }, - comm_size, - mem_frugal_threshold, - handle.get_stream()); - } + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edge_ids->begin(), + tmp.begin()); + + edge_ids = std::move(tmp); + } + + if (edge_types) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edge_types->begin(), + tmp.begin()); + + edge_types = std::move(tmp); + } + + if (edge_start_times) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edge_start_times->begin(), + tmp.begin()); + + edge_start_times = std::move(tmp); + } + + if (edge_end_times) { + rmm::device_uvector tmp(property_position.size(), handle.get_stream()); + + thrust::gather(handle.get_thrust_policy(), + property_position.begin(), + property_position.end(), + edge_end_times->begin(), + tmp.begin()); + + edge_end_times = std::move(tmp); } } @@ -181,7 +248,8 @@ shuffle_vertex_pairs_with_values_by_gpu_id_impl( std::vector rx_counts{}; - if (mem_frugal_flag) { // trade-off potential parallelism to lower peak memory + if (mem_frugal_flag || + (edge_property_count > 1)) { // trade-off potential parallelism to lower peak memory std::tie(majors, rx_counts) = shuffle_values(comm, majors.begin(), h_tx_value_counts, handle.get_stream()); @@ -202,76 +270,54 @@ shuffle_vertex_pairs_with_values_by_gpu_id_impl( std::tie(edge_types, rx_counts) = shuffle_values(comm, (*edge_types).begin(), h_tx_value_counts, handle.get_stream()); } + + if (edge_start_times) { + std::tie(edge_start_times, rx_counts) = + shuffle_values(comm, (*edge_start_times).begin(), h_tx_value_counts, handle.get_stream()); + } + + if (edge_end_times) { + std::tie(edge_end_times, rx_counts) = + shuffle_values(comm, (*edge_end_times).begin(), h_tx_value_counts, handle.get_stream()); + } } else { + // There is at most one edge property set if (weights) { - if (edge_ids) { - if (edge_types) { - std::forward_as_tuple(std::tie(majors, minors, weights, edge_ids, edge_types), - rx_counts) = - shuffle_values(comm, - thrust::make_zip_iterator(majors.begin(), - minors.begin(), - weights->begin(), - edge_ids->begin(), - edge_types->begin()), - h_tx_value_counts, - handle.get_stream()); - } else { - std::forward_as_tuple(std::tie(majors, minors, weights, edge_ids), rx_counts) = - shuffle_values(comm, - thrust::make_zip_iterator( - majors.begin(), minors.begin(), weights->begin(), edge_ids->begin()), - h_tx_value_counts, - handle.get_stream()); - } - } else { - if (edge_types) { - std::forward_as_tuple(std::tie(majors, minors, weights, edge_types), rx_counts) = - shuffle_values(comm, - thrust::make_zip_iterator( - majors.begin(), minors.begin(), weights->begin(), edge_types->begin()), - h_tx_value_counts, - handle.get_stream()); - } else { - std::forward_as_tuple(std::tie(majors, minors, weights), rx_counts) = shuffle_values( - comm, - thrust::make_zip_iterator(majors.begin(), minors.begin(), weights->begin()), - h_tx_value_counts, - handle.get_stream()); - } - } + std::forward_as_tuple(std::tie(majors, minors, weights), rx_counts) = + shuffle_values(comm, + thrust::make_zip_iterator(majors.begin(), minors.begin(), weights->begin()), + h_tx_value_counts, + handle.get_stream()); + } else if (edge_ids) { + std::forward_as_tuple(std::tie(majors, minors, edge_ids), rx_counts) = + shuffle_values(comm, + thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_ids->begin()), + h_tx_value_counts, + handle.get_stream()); + } else if (edge_types) { + std::forward_as_tuple(std::tie(majors, minors, edge_types), rx_counts) = shuffle_values( + comm, + thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_types->begin()), + h_tx_value_counts, + handle.get_stream()); + } else if (edge_start_times) { + std::forward_as_tuple(std::tie(majors, minors, edge_start_times), rx_counts) = shuffle_values( + comm, + thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_start_times->begin()), + h_tx_value_counts, + handle.get_stream()); + } else if (edge_end_times) { + std::forward_as_tuple(std::tie(majors, minors, edge_end_times), rx_counts) = shuffle_values( + comm, + thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_end_times->begin()), + h_tx_value_counts, + handle.get_stream()); } else { - if (edge_ids) { - if (edge_types) { - std::forward_as_tuple(std::tie(majors, minors, edge_ids, edge_types), rx_counts) = - shuffle_values( - comm, - thrust::make_zip_iterator( - majors.begin(), minors.begin(), edge_ids->begin(), edge_types->begin()), - h_tx_value_counts, - handle.get_stream()); - } else { - std::forward_as_tuple(std::tie(majors, minors, edge_ids), rx_counts) = shuffle_values( - comm, - thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_ids->begin()), - h_tx_value_counts, - handle.get_stream()); - } - } else { - if (edge_types) { - std::forward_as_tuple(std::tie(majors, minors, edge_types), rx_counts) = shuffle_values( - comm, - thrust::make_zip_iterator(majors.begin(), minors.begin(), edge_types->begin()), - h_tx_value_counts, - handle.get_stream()); - } else { - std::forward_as_tuple(std::tie(majors, minors), rx_counts) = - shuffle_values(comm, - thrust::make_zip_iterator(majors.begin(), minors.begin()), - h_tx_value_counts, - handle.get_stream()); - } - } + std::forward_as_tuple(std::tie(majors, minors), rx_counts) = + shuffle_values(comm, + thrust::make_zip_iterator(majors.begin(), minors.begin()), + h_tx_value_counts, + handle.get_stream()); } } @@ -280,6 +326,8 @@ shuffle_vertex_pairs_with_values_by_gpu_id_impl( std::move(weights), std::move(edge_ids), std::move(edge_types), + std::move(edge_start_times), + std::move(edge_end_times), std::move(rx_counts)); } @@ -287,12 +335,18 @@ shuffle_vertex_pairs_with_values_by_gpu_id_impl( namespace detail { -template +template std::tuple, rmm::device_uvector, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -300,7 +354,9 @@ shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types) + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times) { auto& comm = handle.get_comms(); auto const comm_size = comm.get_size(); @@ -316,16 +372,24 @@ shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( std::move(weights), std::move(edge_ids), std::move(edge_types), + std::move(edge_start_times), + std::move(edge_start_times), cugraph::detail::compute_gpu_id_from_ext_edge_endpoints_t{ comm_size, major_comm_size, minor_comm_size}); } -template +template std::tuple, rmm::device_uvector, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -334,6 +398,8 @@ shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( std::optional>&& weights, std::optional>&& edge_ids, std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, std::vector const& vertex_partition_range_lasts) { auto& comm = handle.get_comms(); @@ -357,6 +423,8 @@ shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( std::move(weights), std::move(edge_ids), std::move(edge_types), + std::move(edge_start_times), + std::move(edge_start_times), cugraph::detail::compute_gpu_id_from_int_edge_endpoints_t{ raft::device_span(d_vertex_partition_range_lasts.data(), d_vertex_partition_range_lasts.size()), @@ -367,19 +435,27 @@ shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( } // namespace detail -template +template std::tuple, rmm::device_uvector, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_external_edges(raft::handle_t const& handle, rmm::device_uvector&& edge_srcs, rmm::device_uvector&& edge_dsts, std::optional>&& edge_weights, std::optional>&& edge_ids, - std::optional>&& edge_types) + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times) { auto& comm = handle.get_comms(); auto const comm_size = comm.get_size(); @@ -394,7 +470,9 @@ shuffle_external_edges(raft::handle_t const& handle, std::move(edge_dsts), std::move(edge_weights), std::move(edge_ids), - std::move(edge_types)); + std::move(edge_types), + std::move(edge_start_times), + std::move(edge_end_times)); } } // namespace cugraph diff --git a/cpp/src/utilities/shuffle_vertex_pairs_mg_v32_e32.cu b/cpp/src/utilities/shuffle_vertex_pairs_mg_v32_e32.cu index db5a7c0e9bd..c87cdd9e0ed 100644 --- a/cpp/src/utilities/shuffle_vertex_pairs_mg_v32_e32.cu +++ b/cpp/src/utilities/shuffle_vertex_pairs_mg_v32_e32.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,82 @@ template std::tuple, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, + std::vector const& vertex_partition_range_lasts); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, + std::vector const& vertex_partition_range_lasts); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -44,13 +120,17 @@ shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types); + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); template std::tuple, rmm::device_uvector, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -58,13 +138,17 @@ shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types); + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); template std::tuple, rmm::device_uvector, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -73,6 +157,8 @@ shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( std::optional>&& weights, std::optional>&& edge_ids, std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, std::vector const& vertex_partition_range_lasts); template std::tuple, @@ -80,6 +166,8 @@ template std::tuple, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -88,6 +176,8 @@ shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( std::optional>&& weights, std::optional>&& edge_ids, std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, std::vector const& vertex_partition_range_lasts); } // namespace detail @@ -97,25 +187,67 @@ template std::tuple, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_external_edges(raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_external_edges(raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_external_edges(raft::handle_t const& handle, rmm::device_uvector&& majors, rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types); + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); template std::tuple, rmm::device_uvector, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_external_edges(raft::handle_t const& handle, rmm::device_uvector&& majors, rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types); + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); } // namespace cugraph diff --git a/cpp/src/utilities/shuffle_vertex_pairs_mg_v64_e64.cu b/cpp/src/utilities/shuffle_vertex_pairs_mg_v64_e64.cu index 605976f7076..55af44a9d42 100644 --- a/cpp/src/utilities/shuffle_vertex_pairs_mg_v64_e64.cu +++ b/cpp/src/utilities/shuffle_vertex_pairs_mg_v64_e64.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,82 @@ template std::tuple, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, + std::vector const& vertex_partition_range_lasts); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( + raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, + std::vector const& vertex_partition_range_lasts); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -44,13 +120,17 @@ shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types); + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); template std::tuple, rmm::device_uvector, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -58,13 +138,17 @@ shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types); + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); template std::tuple, rmm::device_uvector, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -73,6 +157,8 @@ shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( std::optional>&& weights, std::optional>&& edge_ids, std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, std::vector const& vertex_partition_range_lasts); template std::tuple, @@ -80,6 +166,8 @@ template std::tuple, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( raft::handle_t const& handle, @@ -88,6 +176,8 @@ shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning( std::optional>&& weights, std::optional>&& edge_ids, std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times, std::vector const& vertex_partition_range_lasts); } // namespace detail @@ -97,25 +187,67 @@ template std::tuple, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_external_edges(raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::vector> +shuffle_external_edges(raft::handle_t const& handle, + rmm::device_uvector&& majors, + rmm::device_uvector&& minors, + std::optional>&& weights, + std::optional>&& edge_ids, + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); + +template std::tuple, + rmm::device_uvector, + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_external_edges(raft::handle_t const& handle, rmm::device_uvector&& majors, rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types); + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); template std::tuple, rmm::device_uvector, std::optional>, std::optional>, std::optional>, + std::optional>, + std::optional>, std::vector> shuffle_external_edges(raft::handle_t const& handle, rmm::device_uvector&& majors, rmm::device_uvector&& minors, std::optional>&& weights, std::optional>&& edge_ids, - std::optional>&& edge_types); + std::optional>&& edge_types, + std::optional>&& edge_start_times, + std::optional>&& edge_end_times); } // namespace cugraph diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 4cc9f2d94bf..6800b9c4769 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,5 +1,5 @@ #============================================================================= -# Copyright (c) 2019-2024, NVIDIA CORPORATION. +# Copyright (c) 2019-2025, NVIDIA CORPORATION. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -418,6 +418,10 @@ ConfigureTest(COARSEN_GRAPH_TEST structure/coarsen_graph_test.cpp) # - Induced subgraph tests ------------------------------------------------------------------------ ConfigureTest(INDUCED_SUBGRAPH_TEST structure/induced_subgraph_test.cpp) +################################################################################################## +# - Temporal tests ------------------------------------------------------------------------------- +ConfigureTest(TEMPORAL_GRAPH_TEST structure/temporal_graph_test.cpp) + ################################################################################################### # - BFS tests ------------------------------------------------------------------------------------- ConfigureTest(BFS_TEST traversal/bfs_test.cpp) @@ -579,6 +583,10 @@ if(BUILD_CUGRAPH_MG_TESTS) # - MG SYMMETRIZE tests ----------------------------------------------------------------------- ConfigureTestMG(MG_SYMMETRIZE_TEST structure/mg_symmetrize_test.cpp) + ############################################################################################### + # - MG Temporal Graph tests ----------------------------------------------------------------------- + ConfigureTestMG(MG_TEMPORAL_GRAPH_TEST structure/mg_temporal_graph_test.cpp) + ############################################################################################### # - MG Transpose tests ------------------------------------------------------------------------ ConfigureTestMG(MG_TRANSPOSE_TEST structure/mg_transpose_test.cpp) diff --git a/cpp/tests/c_api/mg_count_multi_edges_test.c b/cpp/tests/c_api/mg_count_multi_edges_test.c index 02a5fd75dd1..bacee55b8fc 100644 --- a/cpp/tests/c_api/mg_count_multi_edges_test.c +++ b/cpp/tests/c_api/mg_count_multi_edges_test.c @@ -98,7 +98,7 @@ int test_multi_edges_count(const cugraph_resource_handle_t* handle) 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); + handle, h_src, h_dst, h_wgt, num_vertices, num_edges, TRUE, FALSE, TRUE, multi_edge_count); } /******************************************************************************/ diff --git a/cpp/tests/c_api/mg_test_utils.cpp b/cpp/tests/c_api/mg_test_utils.cpp index f96be61468f..d238b501a6a 100644 --- a/cpp/tests/c_api/mg_test_utils.cpp +++ b/cpp/tests/c_api/mg_test_utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024, NVIDIA CORPORATION. + * Copyright (c) 2022-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -196,11 +196,11 @@ extern "C" int create_mg_test_graph(const cugraph_resource_handle_t* handle, NULL, &src_view, &dst_view, - &wgt_view, + wgt_view == nullptr ? NULL : &wgt_view, NULL, NULL, store_transposed, - original_num_edges, // UNUSED + 1, FALSE, FALSE, FALSE, @@ -294,11 +294,11 @@ extern "C" int create_mg_test_graph_double(const cugraph_resource_handle_t* hand NULL, &src_view, &dst_view, - &wgt_view, + wgt_view == nullptr ? NULL : &wgt_view, NULL, NULL, store_transposed, - original_num_edges, // UNUSED + 1, FALSE, FALSE, FALSE, @@ -387,10 +387,10 @@ extern "C" int create_mg_test_graph_with_edge_ids(const cugraph_resource_handle_ &src_view, &dst_view, NULL, - &idx_view, + idx_view == nullptr ? NULL : &idx_view, NULL, store_transposed, - original_num_edges, // UNUSED + 1, FALSE, FALSE, FALSE, @@ -513,11 +513,11 @@ extern "C" int create_mg_test_graph_with_properties(const cugraph_resource_handl NULL, &src_view, &dst_view, - &wgt_view, - &idx_view, - &type_view, + wgt_view == nullptr ? NULL : &wgt_view, + idx_view == nullptr ? NULL : &idx_view, + type_view == nullptr ? NULL : &type_view, store_transposed, - original_num_edges, // UNUSED + 1, FALSE, FALSE, FALSE, @@ -606,6 +606,7 @@ int create_mg_test_graph_new(const cugraph_resource_handle_t* handle, TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "dst copy_from_host failed."); if (h_wgt != NULL) { + std::cout << "has edge weight" << std::endl; ret_code = cugraph_type_erased_device_array_create(handle, num_edges, weight_tid, &wgt, ret_error); TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "wgt create failed."); @@ -618,6 +619,7 @@ int create_mg_test_graph_new(const cugraph_resource_handle_t* handle, } if (h_edge_type != NULL) { + std::cout << "has edge type" << std::endl; ret_code = cugraph_type_erased_device_array_create( handle, num_edges, edge_type_tid, &edge_type, ret_error); TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "edge_type create failed."); @@ -630,6 +632,7 @@ int create_mg_test_graph_new(const cugraph_resource_handle_t* handle, } if (h_edge_id != NULL) { + std::cout << "has edge id" << std::endl; ret_code = cugraph_type_erased_device_array_create(handle, num_edges, edge_id_tid, &edge_id, ret_error); TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "edge_id create failed."); @@ -641,22 +644,24 @@ int create_mg_test_graph_new(const cugraph_resource_handle_t* handle, TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "edge_id copy_from_host failed."); } + std::cout << "calling cugraph_graph_create_mg" << std::endl; ret_code = cugraph_graph_create_mg(handle, &properties, NULL, &src_view, &dst_view, - &wgt_view, - &edge_id_view, - &edge_type_view, + wgt_view == nullptr ? NULL : &wgt_view, + edge_id_view == nullptr ? NULL : &edge_id_view, + edge_type_view == nullptr ? NULL : &edge_type_view, store_transposed, - original_num_edges, // UNUSED - FALSE, + 1, FALSE, FALSE, FALSE, + TRUE, graph, ret_error); + std::cout << "ret_code = " << ret_code << std::endl; TEST_ASSERT(test_ret_value, ret_code == CUGRAPH_SUCCESS, "graph creation failed."); if (edge_id != NULL) { diff --git a/cpp/tests/link_prediction/mg_similarity_test.cpp b/cpp/tests/link_prediction/mg_similarity_test.cpp index 87214c808da..b734e787de6 100644 --- a/cpp/tests/link_prediction/mg_similarity_test.cpp +++ b/cpp/tests/link_prediction/mg_similarity_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024, NVIDIA CORPORATION. + * Copyright (c) 2022-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -148,17 +148,21 @@ class Tests_MGSimilarity std::tie(v1, v2) = cugraph::test::remove_self_loops(*handle_, std::move(v1), std::move(v2)); - std::tie(v1, v2, std::ignore, std::ignore, std::ignore, std::ignore) = + std::tie( + v1, v2, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) = cugraph::detail::shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, edge_t, weight_t, + int32_t, int32_t>(*handle_, std::move(v1), std::move(v2), std::nullopt, std::nullopt, std::nullopt, + std::nullopt, + std::nullopt, mg_graph_view.vertex_partition_range_lasts()); std::tuple, raft::device_span> vertex_pairs{ diff --git a/cpp/tests/link_prediction/mg_weighted_similarity_test.cpp b/cpp/tests/link_prediction/mg_weighted_similarity_test.cpp index 2076d4ff79e..6fa66a1a01e 100644 --- a/cpp/tests/link_prediction/mg_weighted_similarity_test.cpp +++ b/cpp/tests/link_prediction/mg_weighted_similarity_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024, NVIDIA CORPORATION. + * Copyright (c) 2022-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -108,17 +108,21 @@ class Tests_MGSimilarity auto d_v1 = cugraph::test::to_device(*handle_, h_v1); auto d_v2 = std::move(two_hop_nbrs); - std::tie(d_v1, d_v2, std::ignore, std::ignore, std::ignore, std::ignore) = + std::tie( + d_v1, d_v2, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) = cugraph::detail::shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, edge_t, weight_t, + int32_t, int32_t>(*handle_, std::move(d_v1), std::move(d_v2), std::nullopt, std::nullopt, std::nullopt, + std::nullopt, + std::nullopt, mg_graph_view.vertex_partition_range_lasts()); std::tuple, raft::device_span> vertex_pairs{ diff --git a/cpp/tests/prims/mg_per_v_pair_transform_dst_nbr_intersection.cu b/cpp/tests/prims/mg_per_v_pair_transform_dst_nbr_intersection.cu index 48c308746f1..76545fb04cd 100644 --- a/cpp/tests/prims/mg_per_v_pair_transform_dst_nbr_intersection.cu +++ b/cpp/tests/prims/mg_per_v_pair_transform_dst_nbr_intersection.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -150,17 +150,22 @@ class Tests_MGPerVPairTransformDstNbrIntersection std::ignore, std::ignore, std::ignore, + std::ignore, + std::ignore, std::ignore) = cugraph::detail::shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, edge_t, weight_t, + int32_t, int32_t>(*handle_, std::move(std::get<0>(mg_vertex_pair_buffer)), std::move(std::get<1>(mg_vertex_pair_buffer)), std::nullopt, std::nullopt, std::nullopt, + std::nullopt, + std::nullopt, h_vertex_partition_range_lasts); auto mg_result_buffer = cugraph::allocate_dataframe_buffer>( diff --git a/cpp/tests/prims/mg_per_v_pair_transform_dst_nbr_weighted_intersection.cu b/cpp/tests/prims/mg_per_v_pair_transform_dst_nbr_weighted_intersection.cu index 4e12cf608cb..1cba7885ce6 100644 --- a/cpp/tests/prims/mg_per_v_pair_transform_dst_nbr_weighted_intersection.cu +++ b/cpp/tests/prims/mg_per_v_pair_transform_dst_nbr_weighted_intersection.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -176,17 +176,22 @@ class Tests_MGPerVPairTransformDstNbrIntersection std::ignore, std::ignore, std::ignore, + std::ignore, + std::ignore, std::ignore) = cugraph::detail::shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, edge_t, weight_t, + int32_t, int32_t>(*handle_, std::move(std::get<0>(mg_vertex_pair_buffer)), std::move(std::get<1>(mg_vertex_pair_buffer)), std::nullopt, std::nullopt, std::nullopt, + std::nullopt, + std::nullopt, h_vertex_partition_range_lasts); auto mg_result_buffer = cugraph::allocate_dataframe_buffer>( diff --git a/cpp/tests/sampling/detail/nbr_sampling_validate.cu b/cpp/tests/sampling/detail/nbr_sampling_validate.cu index 70828e559f1..f399b7542eb 100644 --- a/cpp/tests/sampling/detail/nbr_sampling_validate.cu +++ b/cpp/tests/sampling/detail/nbr_sampling_validate.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024, NVIDIA CORPORATION. + * Copyright (c) 2022-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -218,8 +218,8 @@ bool validate_sampling_depth(raft::handle_t const& handle, { graph_t graph(handle); std::optional> number_map{std::nullopt}; - std::tie(graph, std::ignore, std::ignore, std::ignore, number_map) = - create_graph_from_edgelist( + std::tie(graph, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, number_map) = + create_graph_from_edgelist( handle, std::nullopt, std::move(d_src), @@ -227,6 +227,8 @@ bool validate_sampling_depth(raft::handle_t const& handle, std::move(d_wgt), std::nullopt, std::nullopt, + std::nullopt, + std::nullopt, graph_properties_t{false, true}, true); diff --git a/cpp/tests/structure/mg_has_edge_and_compute_multiplicity_test.cpp b/cpp/tests/structure/mg_has_edge_and_compute_multiplicity_test.cpp index 9da8dfeb595..92b66d0260c 100644 --- a/cpp/tests/structure/mg_has_edge_and_compute_multiplicity_test.cpp +++ b/cpp/tests/structure/mg_has_edge_and_compute_multiplicity_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, NVIDIA CORPORATION. + * Copyright (c) 2024-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,8 +65,9 @@ class Tests_MGHasEdgeAndComputeMultiplicity HasEdgeAndComputeMultiplicity_Usecase const& has_edge_and_compute_multiplicity_usecase, input_usecase_t const& input_usecase) { - using weight_t = float; - using edge_type_id_t = int32_t; + using weight_t = float; + using edge_type_t = int32_t; + using edge_time_t = int32_t; HighResTimer hr_timer{}; @@ -124,18 +125,23 @@ class Tests_MGHasEdgeAndComputeMultiplicity std::ignore, std::ignore, std::ignore, + std::ignore, + std::ignore, std::ignore) = cugraph::detail::shuffle_int_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, edge_t, weight_t, - edge_type_id_t>(*handle_, - std::move(store_transposed ? d_mg_edge_dsts : d_mg_edge_srcs), - std::move(store_transposed ? d_mg_edge_srcs : d_mg_edge_dsts), - std::nullopt, - std::nullopt, - std::nullopt, - mg_graph_view.vertex_partition_range_lasts()); + edge_type_t, + edge_time_t>(*handle_, + std::move(store_transposed ? d_mg_edge_dsts : d_mg_edge_srcs), + std::move(store_transposed ? d_mg_edge_srcs : d_mg_edge_dsts), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + mg_graph_view.vertex_partition_range_lasts()); // 3. run MG has_edge & compute_multiplicity diff --git a/cpp/tests/structure/mg_symmetrize_test.cpp b/cpp/tests/structure/mg_symmetrize_test.cpp index ebdec278db1..4d56a6e2a95 100644 --- a/cpp/tests/structure/mg_symmetrize_test.cpp +++ b/cpp/tests/structure/mg_symmetrize_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/cpp/tests/structure/mg_temporal_graph_test.cpp b/cpp/tests/structure/mg_temporal_graph_test.cpp new file mode 100644 index 00000000000..a718c2dad94 --- /dev/null +++ b/cpp/tests/structure/mg_temporal_graph_test.cpp @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2024-2025, 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 governin_from_mtxg permissions and + * limitations under the License. + */ + +#include "utilities/base_fixture.hpp" +#include "utilities/conversion_utilities.hpp" +#include "utilities/device_comm_wrapper.hpp" +#include "utilities/property_generator_utilities.hpp" +#include "utilities/test_graphs.hpp" +#include "utilities/thrust_wrapper.hpp" +#include "utilities/validation_utilities.hpp" + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +struct TemporalGraph_Usecase { + std::optional weight_type{std::nullopt}; + bool use_end_time{false}; + bool check_correctness{true}; +}; + +using edge_type_t = int32_t; +using edge_time_t = int32_t; + +template +class Tests_MGTemporalGraph + : public ::testing::TestWithParam> { + public: + Tests_MGTemporalGraph() {} + + static void SetUpTestCase() { handle_ = cugraph::test::initialize_mg_handle(); } + + static void TearDownTestCase() { handle_.reset(); } + + virtual void SetUp() {} + virtual void TearDown() {} + + template + void run_current_test( + std::tuple const& param) + { + constexpr bool renumber = true; + auto [temporal_graph_usecase, input_usecase] = param; + + HighResTimer hr_timer{}; + + if (cugraph::test::g_perf) { + RAFT_CUDA_TRY(cudaDeviceSynchronize()); // for consistent performance measurement + hr_timer.start("Construct graph"); + } + + auto [edge_src_chunks, edge_dst_chunks, edge_weight_chunks, d_vertices_v, is_symmetric] = + input_usecase.template construct_edgelist( + *handle_, temporal_graph_usecase.weight_type.has_value(), store_transposed, true); + + size_t num_edges{0}; + for (size_t i = 0; i < edge_src_chunks.size(); ++i) { + num_edges += edge_src_chunks[i].size(); + } + + CUGRAPH_EXPECTS(num_edges <= static_cast(std::numeric_limits::max()), + "Invalid template parameter: edge_t overflow."); + + size_t base_offset{0}; + auto base_offsets = + cugraph::host_scalar_allgather(handle_->get_comms(), num_edges, handle_->get_stream()); + handle_->sync_stream(); + std::exclusive_scan(base_offsets.begin(), base_offsets.end(), base_offsets.begin(), size_t{0}); + base_offset = base_offsets[handle_->get_comms().get_rank()]; + + auto edge_start_time_chunks = + std::make_optional>>(); + auto edge_end_time_chunks = + temporal_graph_usecase.use_end_time + ? std::make_optional>>() + : std::nullopt; + constexpr uint64_t seed{0}; + raft::random::RngState rng_state(seed); + + for (size_t i = 0; i < edge_src_chunks.size(); ++i) { + edge_start_time_chunks->push_back( + rmm::device_uvector(edge_src_chunks[i].size(), handle_->get_stream())); + cugraph::detail::uniform_random_fill(handle_->get_stream(), + edge_start_time_chunks->back().data(), + edge_start_time_chunks->back().size(), + edge_time_t{0}, + edge_time_t{20000}, + rng_state); + + if (temporal_graph_usecase.use_end_time) { + edge_end_time_chunks->push_back( + rmm::device_uvector(edge_src_chunks[i].size(), handle_->get_stream())); + cugraph::detail::uniform_random_fill(handle_->get_stream(), + edge_end_time_chunks->back().data(), + edge_end_time_chunks->back().size(), + edge_time_t{20000}, + edge_time_t{40000}, + rng_state); + } + } + + cugraph::graph_t graph(*handle_); + std::optional< + cugraph::edge_property_t, + weight_t>> + edge_weights{std::nullopt}; + std::optional< + cugraph::edge_property_t, + edge_time_t>> + edge_start_times{std::nullopt}; + std::optional< + cugraph::edge_property_t, + edge_time_t>> + edge_end_times{std::nullopt}; + std::optional> renumber_map{std::nullopt}; + + size_t size = std::transform_reduce(edge_src_chunks.begin(), + edge_src_chunks.end(), + size_t{0}, + std::plus(), + [](auto const& vector) { return vector.size(); }); + + rmm::device_uvector local_original_srcs(size, handle_->get_stream()); + rmm::device_uvector local_original_dsts(size, handle_->get_stream()); + auto local_original_wgts = + temporal_graph_usecase.weight_type.has_value() + ? std::make_optional>(size, handle_->get_stream()) + : std::nullopt; + auto local_original_start_times = + std::make_optional>(size, handle_->get_stream()); + auto local_original_end_times = + temporal_graph_usecase.use_end_time + ? std::make_optional>(size, handle_->get_stream()) + : std::nullopt; + + size_t last_pos = 0; + for (size_t i = 0; i < edge_src_chunks.size(); ++i) { + raft::copy(local_original_srcs.data() + last_pos, + edge_src_chunks[i].data(), + edge_src_chunks[i].size(), + handle_->get_stream()); + raft::copy(local_original_dsts.data() + last_pos, + edge_dst_chunks[i].data(), + edge_dst_chunks[i].size(), + handle_->get_stream()); + if (local_original_wgts) + raft::copy(local_original_wgts->data() + last_pos, + (*edge_weight_chunks)[i].data(), + (*edge_weight_chunks)[i].size(), + handle_->get_stream()); + if (local_original_start_times) + raft::copy(local_original_start_times->data() + last_pos, + (*edge_start_time_chunks)[i].data(), + (*edge_start_time_chunks)[i].size(), + handle_->get_stream()); + if (local_original_end_times) + raft::copy(local_original_end_times->data() + last_pos, + (*edge_end_time_chunks)[i].data(), + (*edge_end_time_chunks)[i].size(), + handle_->get_stream()); + + last_pos += edge_src_chunks[i].size(); + } + + std::tie(graph, + edge_weights, + std::ignore, + std::ignore, + edge_start_times, + edge_end_times, + renumber_map) = + cugraph::create_graph_from_edgelist(*handle_, + std::move(d_vertices_v), + std::move(edge_src_chunks), + std::move(edge_dst_chunks), + std::move(edge_weight_chunks), + std::nullopt, + std::nullopt, + std::move(edge_start_time_chunks), + std::move(edge_end_time_chunks), + cugraph::graph_properties_t{is_symmetric, true}, + renumber); + + if (cugraph::test::g_perf) { + RAFT_CUDA_TRY(cudaDeviceSynchronize()); // for consistent performance measurement + hr_timer.stop(); + hr_timer.display_and_clear(std::cout); + } + + auto graph_view = graph.view(); + + if (temporal_graph_usecase.check_correctness) { + // FIXME: decompress_to_edgelist should support all properties + // This hack only works if edge_t == edge_time_t + auto [local_result_srcs, + local_result_dsts, + local_result_wgts, + local_result_start_times, + local_result_end_times] = cugraph:: + decompress_to_edgelist( + *handle_, + graph.view(), + edge_weights ? std::make_optional(edge_weights->view()) : std::nullopt, + edge_start_times ? std::make_optional(edge_start_times->view()) : std::nullopt, + edge_end_times ? std::make_optional(edge_end_times->view()) : std::nullopt, + renumber ? std::make_optional>(renumber_map->data(), + renumber_map->size()) + : std::nullopt); + + auto result_srcs = + cugraph::test::device_gatherv(*handle_, local_result_srcs.data(), local_result_srcs.size()); + auto result_dsts = + cugraph::test::device_gatherv(*handle_, local_result_dsts.data(), local_result_dsts.size()); + + std::optional> result_wgts{std::nullopt}; + std::optional> result_start_times{std::nullopt}; + std::optional> result_end_times{std::nullopt}; + + if (local_result_wgts) + result_wgts = cugraph::test::device_gatherv( + *handle_, local_result_wgts->data(), local_result_wgts->size()); + if (local_result_start_times) + result_start_times = cugraph::test::device_gatherv( + *handle_, local_result_start_times->data(), local_result_start_times->size()); + if (local_result_end_times) + result_end_times = cugraph::test::device_gatherv( + *handle_, local_result_end_times->data(), local_result_end_times->size()); + + auto original_srcs = cugraph::test::device_gatherv( + *handle_, local_original_srcs.data(), local_original_srcs.size()); + auto original_dsts = cugraph::test::device_gatherv( + *handle_, local_original_dsts.data(), local_original_dsts.size()); + + std::optional> original_wgts{std::nullopt}; + std::optional> original_start_times{std::nullopt}; + std::optional> original_end_times{std::nullopt}; + + if (local_original_wgts) + original_wgts = cugraph::test::device_gatherv( + *handle_, local_original_wgts->data(), local_original_wgts->size()); + if (local_original_start_times) + original_start_times = cugraph::test::device_gatherv( + *handle_, local_original_start_times->data(), local_original_start_times->size()); + if (local_original_end_times) + original_end_times = cugraph::test::device_gatherv( + *handle_, local_original_end_times->data(), local_original_end_times->size()); + + if (handle_->get_comms().get_rank() == 0) { + cugraph::test::sort( + *handle_, + raft::device_span{result_srcs.data(), result_srcs.size()}, + raft::device_span{result_dsts.data(), result_dsts.size()}, + result_wgts ? std::make_optional>(result_wgts->data(), + result_wgts->size()) + : std::nullopt, + std::nullopt, + std::nullopt, + result_start_times ? std::make_optional>( + result_start_times->data(), result_start_times->size()) + : std::nullopt, + result_end_times ? std::make_optional>( + result_end_times->data(), result_end_times->size()) + : std::nullopt); + + cugraph::test::sort( + *handle_, + raft::device_span{original_srcs.data(), original_srcs.size()}, + raft::device_span{original_dsts.data(), original_dsts.size()}, + original_wgts ? std::make_optional>(original_wgts->data(), + original_wgts->size()) + : std::nullopt, + std::nullopt, + std::nullopt, + original_start_times ? std::make_optional>( + original_start_times->data(), original_start_times->size()) + : std::nullopt, + original_end_times ? std::make_optional>( + original_end_times->data(), original_end_times->size()) + : std::nullopt); + + ASSERT_TRUE(cugraph::test::device_spans_equal( + *handle_, + raft::device_span{result_srcs.data(), result_srcs.size()}, + raft::device_span{original_srcs.data(), original_srcs.size()})); + ASSERT_TRUE(cugraph::test::device_spans_equal( + *handle_, + raft::device_span{result_srcs.data(), result_srcs.size()}, + raft::device_span{original_srcs.data(), original_srcs.size()})); + if (result_wgts) + ASSERT_TRUE( + result_wgts.has_value() == original_wgts.has_value() && + cugraph::test::device_spans_equal( + *handle_, + raft::device_span{result_wgts->data(), result_wgts->size()}, + raft::device_span{original_wgts->data(), original_wgts->size()})); + if (result_start_times) + ASSERT_TRUE(result_start_times.has_value() == original_start_times.has_value() && + cugraph::test::device_spans_equal( + *handle_, + raft::device_span{result_start_times->data(), + result_start_times->size()}, + raft::device_span{original_start_times->data(), + original_start_times->size()})); + if (result_end_times) + ASSERT_TRUE(result_end_times.has_value() == original_end_times.has_value() && + cugraph::test::device_spans_equal( + *handle_, + raft::device_span{result_end_times->data(), + result_end_times->size()}, + raft::device_span{original_end_times->data(), + original_end_times->size()})); + } + } + } + + private: + static std::unique_ptr handle_; +}; + +template +std::unique_ptr Tests_MGTemporalGraph::handle_ = nullptr; + +using Tests_MGTemporalGraph_File = Tests_MGTemporalGraph; +using Tests_MGTemporalGraph_Rmat = Tests_MGTemporalGraph; + +TEST_P(Tests_MGTemporalGraph_File, CheckInt32Int32FloatTransposeFalse) +{ + run_current_test( + override_File_Usecase_with_cmd_line_arguments(GetParam())); +} + +TEST_P(Tests_MGTemporalGraph_File, CheckInt32Int32FloatTransposeTrue) +{ + run_current_test( + override_File_Usecase_with_cmd_line_arguments(GetParam())); +} + +TEST_P(Tests_MGTemporalGraph_Rmat, CheckInt32Int32FloatTransposeFalse) +{ + run_current_test( + override_Rmat_Usecase_with_cmd_line_arguments(GetParam())); +} + +TEST_P(Tests_MGTemporalGraph_Rmat, CheckInt32Int32FloatTransposeTrue) +{ + run_current_test( + override_Rmat_Usecase_with_cmd_line_arguments(GetParam())); +} + +INSTANTIATE_TEST_SUITE_P( + file_test, + Tests_MGTemporalGraph_File, + ::testing::Combine( + // enable correctness check + ::testing::Values( + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = true, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = true, .check_correctness = true}), + ::testing::Values(cugraph::test::File_Usecase("test/datasets/karate.mtx"), + cugraph::test::File_Usecase("test/datasets/dolphins.mtx")))); + +INSTANTIATE_TEST_SUITE_P( + rmat_small_test, + Tests_MGTemporalGraph_Rmat, + ::testing::Combine( + // enable correctness checks + ::testing::Values( + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = true, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = true, .check_correctness = true}), + ::testing::Values(cugraph::test::Rmat_Usecase(10, 16, 0.57, 0.19, 0.19, 0, false, false), + cugraph::test::Rmat_Usecase(10, 16, 0.57, 0.19, 0.19, 0, true, false)))); + +INSTANTIATE_TEST_SUITE_P( + file_benchmark_test, /* note that the test filename can be overridden in benchmarking (with + --gtest_filter to select only the file_benchmark_test with a specific + vertex & edge type combination) by command line arguments and do not + include more than one File_Usecase that differ only in filename + (to avoid running same benchmarks more than once) */ + Tests_MGTemporalGraph_File, + ::testing::Combine( + ::testing::Values( + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = true, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = true, .check_correctness = true}), + ::testing::Values(cugraph::test::File_Usecase("test/datasets/karate.mtx")))); + +INSTANTIATE_TEST_SUITE_P( + rmat_benchmark_test, /* note that scale & edge factor can be overridden in benchmarking (with + --gtest_filter to select only the rmat_benchmark_test with a specific + vertex & edge type combination) by command line arguments and do not + include more than one Rmat_Usecase that differ only in scale or edge + factor (to avoid running same benchmarks more than once) */ + Tests_MGTemporalGraph_Rmat, + ::testing::Combine( + // disable correctness checks for large graphs + ::testing::Values( + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = true, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = true, .check_correctness = true}), + ::testing::Values(cugraph::test::Rmat_Usecase(20, 32, 0.57, 0.19, 0.19, 0, false, false), + cugraph::test::Rmat_Usecase(20, 32, 0.57, 0.19, 0.19, 0, true, false)))); + +CUGRAPH_MG_TEST_PROGRAM_MAIN() diff --git a/cpp/tests/structure/renumbering_test.cpp b/cpp/tests/structure/renumbering_test.cpp index dcf278ab05a..7bee195b27e 100644 --- a/cpp/tests/structure/renumbering_test.cpp +++ b/cpp/tests/structure/renumbering_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -76,9 +76,17 @@ class Tests_Renumbering std::tie(src_chunks, dst_chunks, std::ignore, std::ignore, std::ignore) = input_usecase.template construct_edgelist(handle, false, false, false); - std::tie(src_v, dst_v, std::ignore) = - cugraph::test::detail::concatenate_edge_chunks( - handle, std::move(src_chunks), std::move(dst_chunks), std::nullopt); + std::tie(src_v, dst_v, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) = + cugraph::test::detail:: + concatenate_edge_chunks( + handle, + std::move(src_chunks), + std::move(dst_chunks), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt); } if (renumbering_usecase.check_correctness) { diff --git a/cpp/tests/structure/temporal_graph_test.cpp b/cpp/tests/structure/temporal_graph_test.cpp new file mode 100644 index 00000000000..0c99751eddb --- /dev/null +++ b/cpp/tests/structure/temporal_graph_test.cpp @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2024-2025, 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 governin_from_mtxg permissions and + * limitations under the License. + */ + +#include "utilities/base_fixture.hpp" +#include "utilities/conversion_utilities.hpp" +#include "utilities/property_generator_utilities.hpp" +#include "utilities/validation_utilities.hpp" + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +struct TemporalGraph_Usecase { + std::optional weight_type{std::nullopt}; + bool use_end_time{false}; + bool check_correctness{true}; +}; + +using edge_type_t = int32_t; +using edge_time_t = int32_t; + +template +class Tests_TemporalGraph + : public ::testing::TestWithParam> { + public: + Tests_TemporalGraph() {} + + static void SetUpTestCase() {} + static void TearDownTestCase() {} + + virtual void SetUp() {} + virtual void TearDown() {} + + template + void run_current_test( + std::tuple const& param) + { + constexpr bool renumber = true; + auto [temporal_graph_usecase, input_usecase] = param; + + raft::handle_t handle{}; + HighResTimer hr_timer{}; + + if (cugraph::test::g_perf) { + RAFT_CUDA_TRY(cudaDeviceSynchronize()); // for consistent performance measurement + hr_timer.start("Construct graph"); + } + + auto [edge_src_chunks, edge_dst_chunks, edge_weight_chunks, d_vertices_v, is_symmetric] = + input_usecase.template construct_edgelist( + handle, temporal_graph_usecase.weight_type.has_value(), store_transposed, false); + + size_t num_edges{0}; + for (size_t i = 0; i < edge_src_chunks.size(); ++i) { + num_edges += edge_src_chunks[i].size(); + } + + CUGRAPH_EXPECTS(num_edges <= static_cast(std::numeric_limits::max()), + "Invalid template parameter: edge_t overflow."); + + auto edge_start_time_chunks = + std::make_optional>>(); + auto edge_end_time_chunks = + temporal_graph_usecase.use_end_time + ? std::make_optional>>() + : std::nullopt; + constexpr uint64_t seed{0}; + raft::random::RngState rng_state(seed); + + for (size_t i = 0; i < edge_src_chunks.size(); ++i) { + edge_start_time_chunks->push_back( + rmm::device_uvector(edge_src_chunks[i].size(), handle.get_stream())); + cugraph::detail::uniform_random_fill(handle.get_stream(), + edge_start_time_chunks->back().data(), + edge_start_time_chunks->back().size(), + edge_time_t{0}, + edge_time_t{20000}, + rng_state); + + if (temporal_graph_usecase.use_end_time) { + edge_end_time_chunks->push_back( + rmm::device_uvector(edge_src_chunks[i].size(), handle.get_stream())); + cugraph::detail::uniform_random_fill(handle.get_stream(), + edge_start_time_chunks->back().data(), + edge_start_time_chunks->back().size(), + edge_time_t{20000}, + edge_time_t{40000}, + rng_state); + } + } + + cugraph::graph_t graph(handle); + std::optional< + cugraph::edge_property_t, + weight_t>> + edge_weights{std::nullopt}; + std::optional< + cugraph::edge_property_t, + edge_time_t>> + edge_start_times{std::nullopt}; + std::optional< + cugraph::edge_property_t, + edge_time_t>> + edge_end_times{std::nullopt}; + std::optional> renumber_map{std::nullopt}; + + size_t size = std::transform_reduce(edge_src_chunks.begin(), + edge_src_chunks.end(), + size_t{0}, + std::plus(), + [](auto const& vector) { return vector.size(); }); + + rmm::device_uvector original_srcs(size, handle.get_stream()); + rmm::device_uvector original_dsts(size, handle.get_stream()); + auto original_wgts = + temporal_graph_usecase.weight_type.has_value() + ? std::make_optional>(size, handle.get_stream()) + : std::nullopt; + auto original_start_times = + std::make_optional>(size, handle.get_stream()); + auto original_end_times = + temporal_graph_usecase.use_end_time + ? std::make_optional>(size, handle.get_stream()) + : std::nullopt; + + size_t last_pos = 0; + for (size_t i = 0; i < edge_src_chunks.size(); ++i) { + raft::copy(original_srcs.data() + last_pos, + edge_src_chunks[i].data(), + edge_src_chunks[i].size(), + handle.get_stream()); + raft::copy(original_dsts.data() + last_pos, + edge_dst_chunks[i].data(), + edge_dst_chunks[i].size(), + handle.get_stream()); + if (original_wgts) + raft::copy(original_wgts->data() + last_pos, + (*edge_weight_chunks)[i].data(), + (*edge_weight_chunks)[i].size(), + handle.get_stream()); + if (original_start_times) + raft::copy(original_start_times->data() + last_pos, + (*edge_start_time_chunks)[i].data(), + (*edge_start_time_chunks)[i].size(), + handle.get_stream()); + if (original_end_times) + raft::copy(original_end_times->data() + last_pos, + (*edge_end_time_chunks)[i].data(), + (*edge_end_time_chunks)[i].size(), + handle.get_stream()); + + last_pos += edge_src_chunks[i].size(); + } + + std::tie(graph, + edge_weights, + std::ignore, + std::ignore, + edge_start_times, + edge_end_times, + renumber_map) = + cugraph::create_graph_from_edgelist(handle, + std::move(d_vertices_v), + std::move(edge_src_chunks), + std::move(edge_dst_chunks), + std::move(edge_weight_chunks), + std::nullopt, + std::nullopt, + std::move(edge_start_time_chunks), + std::move(edge_end_time_chunks), + cugraph::graph_properties_t{is_symmetric, true}, + renumber); + + if (cugraph::test::g_perf) { + RAFT_CUDA_TRY(cudaDeviceSynchronize()); // for consistent performance measurement + hr_timer.stop(); + hr_timer.display_and_clear(std::cout); + } + + auto graph_view = graph.view(); + + if (temporal_graph_usecase.check_correctness) { + // FIXME: decompress_to_edgelist should support all properties + // This hack only works if edge_t == edge_time_t + auto [result_srcs, result_dsts, result_wgts, result_start_times, result_end_times] = cugraph:: + decompress_to_edgelist( + handle, + graph.view(), + edge_weights ? std::make_optional(edge_weights->view()) : std::nullopt, + edge_start_times ? std::make_optional(edge_start_times->view()) : std::nullopt, + edge_end_times ? std::make_optional(edge_end_times->view()) : std::nullopt, + renumber ? std::make_optional>(renumber_map->data(), + renumber_map->size()) + : std::nullopt); + + cugraph::test::sort( + handle, + raft::device_span{result_srcs.data(), result_srcs.size()}, + raft::device_span{result_dsts.data(), result_dsts.size()}, + result_wgts ? std::make_optional>(result_wgts->data(), + result_wgts->size()) + : std::nullopt, + std::nullopt, + std::nullopt, + result_start_times ? std::make_optional>( + result_start_times->data(), result_start_times->size()) + : std::nullopt, + result_end_times ? std::make_optional>( + result_end_times->data(), result_end_times->size()) + : std::nullopt); + + cugraph::test::sort( + handle, + raft::device_span{original_srcs.data(), original_srcs.size()}, + raft::device_span{original_dsts.data(), original_dsts.size()}, + original_wgts ? std::make_optional>(original_wgts->data(), + original_wgts->size()) + : std::nullopt, + std::nullopt, + std::nullopt, + original_start_times ? std::make_optional>( + original_start_times->data(), original_start_times->size()) + : std::nullopt, + original_end_times ? std::make_optional>( + original_end_times->data(), original_end_times->size()) + : std::nullopt); + + ASSERT_TRUE(cugraph::test::device_spans_equal( + handle, + raft::device_span{result_srcs.data(), result_srcs.size()}, + raft::device_span{original_srcs.data(), original_srcs.size()})); + ASSERT_TRUE(cugraph::test::device_spans_equal( + handle, + raft::device_span{result_srcs.data(), result_srcs.size()}, + raft::device_span{original_srcs.data(), original_srcs.size()})); + if (result_wgts) + ASSERT_TRUE( + result_wgts.has_value() == original_wgts.has_value() && + cugraph::test::device_spans_equal( + handle, + raft::device_span{result_wgts->data(), result_wgts->size()}, + raft::device_span{original_wgts->data(), original_wgts->size()})); + if (result_start_times) + ASSERT_TRUE(result_start_times.has_value() == original_start_times.has_value() && + cugraph::test::device_spans_equal( + handle, + raft::device_span{result_start_times->data(), + result_start_times->size()}, + raft::device_span{original_start_times->data(), + original_start_times->size()})); + if (result_end_times) + ASSERT_TRUE(result_end_times.has_value() == original_end_times.has_value() && + cugraph::test::device_spans_equal( + handle, + raft::device_span{result_end_times->data(), + result_end_times->size()}, + raft::device_span{original_end_times->data(), + original_end_times->size()})); + } + } +}; + +using Tests_TemporalGraph_File = Tests_TemporalGraph; +using Tests_TemporalGraph_Rmat = Tests_TemporalGraph; + +TEST_P(Tests_TemporalGraph_File, CheckInt32Int32FloatTransposeFalse) +{ + run_current_test( + override_File_Usecase_with_cmd_line_arguments(GetParam())); +} + +TEST_P(Tests_TemporalGraph_File, CheckInt32Int32FloatTransposeTrue) +{ + run_current_test( + override_File_Usecase_with_cmd_line_arguments(GetParam())); +} + +TEST_P(Tests_TemporalGraph_Rmat, CheckInt32Int32FloatTransposeFalse) +{ + run_current_test( + override_Rmat_Usecase_with_cmd_line_arguments(GetParam())); +} + +TEST_P(Tests_TemporalGraph_Rmat, CheckInt32Int32FloatTransposeTrue) +{ + run_current_test( + override_Rmat_Usecase_with_cmd_line_arguments(GetParam())); +} + +INSTANTIATE_TEST_SUITE_P( + file_test, + Tests_TemporalGraph_File, + ::testing::Combine( + // enable correctness check + ::testing::Values( + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = true, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = true, .check_correctness = true}), + ::testing::Values(cugraph::test::File_Usecase("test/datasets/karate.mtx"), + cugraph::test::File_Usecase("test/datasets/dolphins.mtx")))); + +INSTANTIATE_TEST_SUITE_P( + rmat_small_test, + Tests_TemporalGraph_Rmat, + ::testing::Combine( + // enable correctness checks + ::testing::Values( + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = true, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = true, .check_correctness = true}), + ::testing::Values(cugraph::test::Rmat_Usecase(10, 16, 0.57, 0.19, 0.19, 0, false, false), + cugraph::test::Rmat_Usecase(10, 16, 0.57, 0.19, 0.19, 0, true, false)))); + +INSTANTIATE_TEST_SUITE_P( + file_benchmark_test, /* note that the test filename can be overridden in benchmarking (with + --gtest_filter to select only the file_benchmark_test with a specific + vertex & edge type combination) by command line arguments and do not + include more than one File_Usecase that differ only in filename + (to avoid running same benchmarks more than once) */ + Tests_TemporalGraph_File, + ::testing::Combine( + ::testing::Values( + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = true, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = true, .check_correctness = true}), + ::testing::Values(cugraph::test::File_Usecase("test/datasets/karate.mtx")))); + +INSTANTIATE_TEST_SUITE_P( + rmat_benchmark_test, /* note that scale & edge factor can be overridden in benchmarking (with + --gtest_filter to select only the rmat_benchmark_test with a specific + vertex & edge type combination) by command line arguments and do not + include more than one Rmat_Usecase that differ only in scale or edge + factor (to avoid running same benchmarks more than once) */ + Tests_TemporalGraph_Rmat, + ::testing::Combine( + // disable correctness checks for large graphs + ::testing::Values( + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = std::nullopt, .use_end_time = true, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = false, .check_correctness = true}, + TemporalGraph_Usecase{ + .weight_type = FLOAT32, .use_end_time = true, .check_correctness = true}), + ::testing::Values(cugraph::test::Rmat_Usecase(20, 32, 0.57, 0.19, 0.19, 0, false, false), + cugraph::test::Rmat_Usecase(20, 32, 0.57, 0.19, 0.19, 0, true, false)))); + +CUGRAPH_TEST_PROGRAM_MAIN() diff --git a/cpp/tests/traversal/ms_bfs_test.cu b/cpp/tests/traversal/ms_bfs_test.cu index 6219b28e6e6..dae2d351021 100644 --- a/cpp/tests/traversal/ms_bfs_test.cu +++ b/cpp/tests/traversal/ms_bfs_test.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -158,17 +158,20 @@ class Tests_MsBfs : public ::testing::TestWithParam { thrust::sequence( rmm::exec_policy(handle.get_stream()), d_vertices.begin(), d_vertices.end(), vertex_t{0}); - std::tie(graph, std::ignore, std::ignore, std::ignore, std::ignore) = cugraph:: - create_graph_from_edgelist( - handle, - std::move(d_vertices), - std::move(d_srcs), - std::move(d_dst), - std::nullopt, - std::nullopt, - std::nullopt, - cugraph::graph_properties_t{false, true}, - false); + std::tie(graph, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) = + cugraph:: + create_graph_from_edgelist( + handle, + std::move(d_vertices), + std::move(d_srcs), + std::move(d_dst), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + cugraph::graph_properties_t{false, true}, + false); auto graph_view = graph.view(); diff --git a/cpp/tests/utilities/conversion_utilities_impl.cuh b/cpp/tests/utilities/conversion_utilities_impl.cuh index 9f8fdcf6ed9..40fe6fe8695 100644 --- a/cpp/tests/utilities/conversion_utilities_impl.cuh +++ b/cpp/tests/utilities/conversion_utilities_impl.cuh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024, NVIDIA CORPORATION. + * Copyright (c) 2022-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -333,14 +333,8 @@ mg_graph_to_sg_graph( handle.get_stream(), vertices.data(), vertices.size(), vertex_t{0}); } - std::tie(sg_graph, sg_edge_weights, sg_edge_ids, std::ignore, sg_number_map) = - cugraph::create_graph_from_edgelist( + std::tie(sg_graph, sg_edge_weights, sg_edge_ids, std::ignore, sg_number_map) = cugraph:: + create_graph_from_edgelist( handle, std::make_optional(std::move(vertices)), std::move(d_src), diff --git a/cpp/tests/utilities/csv_file_utilities.cu b/cpp/tests/utilities/csv_file_utilities.cu index e7be9ff3133..54d21eca3d1 100644 --- a/cpp/tests/utilities/csv_file_utilities.cu +++ b/cpp/tests/utilities/csv_file_utilities.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -75,12 +75,23 @@ bool check_symmetric(raft::handle_t const& handle, (*symmetrized_weights).begin()); } - std::tie(symmetrized_srcs, symmetrized_dsts, symmetrized_weights) = - symmetrize_edgelist(handle, - std::move(symmetrized_srcs), - std::move(symmetrized_dsts), - std::move(symmetrized_weights), - true); + std::tie(symmetrized_srcs, + symmetrized_dsts, + symmetrized_weights, + std::ignore, + std::ignore, + std::ignore, + std::ignore) = + symmetrize_edgelist( + handle, + std::move(symmetrized_srcs), + std::move(symmetrized_dsts), + std::move(symmetrized_weights), + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + true); if (symmetrized_srcs.size() != org_srcs.size()) { return false; } @@ -132,7 +143,7 @@ read_edgelist_from_csv_file(raft::handle_t const& handle, file.read(buffer.data(), length); CUGRAPH_EXPECTS(file, "File read failure."); - buffer.back() = '\0'; // null termination + buffer[length] = '\0'; // null termination file.close(); @@ -294,22 +305,17 @@ read_graph_from_csv_file(raft::handle_t const& handle, cugraph::edge_property_t, weight_t>> edge_weights{std::nullopt}; std::optional> renumber_map{std::nullopt}; - std::tie(graph, edge_weights, std::ignore, std::ignore, renumber_map) = - cugraph::create_graph_from_edgelist(handle, - std::nullopt, - std::move(d_edgelist_srcs), - std::move(d_edgelist_dsts), - std::move(d_edgelist_weights), - std::nullopt, - std::nullopt, - cugraph::graph_properties_t{is_symmetric, false}, - renumber); + std::tie(graph, edge_weights, std::ignore, std::ignore, renumber_map) = cugraph:: + create_graph_from_edgelist( + handle, + std::nullopt, + std::move(d_edgelist_srcs), + std::move(d_edgelist_dsts), + std::move(d_edgelist_weights), + std::nullopt, + std::nullopt, + cugraph::graph_properties_t{is_symmetric, false}, + renumber); return std::make_tuple(std::move(graph), std::move(edge_weights), std::move(renumber_map)); } diff --git a/cpp/tests/utilities/matrix_market_file_utilities.cu b/cpp/tests/utilities/matrix_market_file_utilities.cu index 1ca31a1ee6b..e935ad98a95 100644 --- a/cpp/tests/utilities/matrix_market_file_utilities.cu +++ b/cpp/tests/utilities/matrix_market_file_utilities.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -418,11 +418,11 @@ read_graph_from_matrix_market_file(raft::handle_t const& handle, cugraph::edge_property_t, weight_t>> edge_weights{std::nullopt}; std::optional> renumber_map{std::nullopt}; - std::tie(graph, edge_weights, std::ignore, std::ignore, renumber_map) = + std::tie(graph, edge_weights, std::ignore, std::ignore, std::ignore, std::ignore, renumber_map) = cugraph::create_graph_from_edgelist(handle, @@ -432,6 +432,8 @@ read_graph_from_matrix_market_file(raft::handle_t const& handle, std::move(d_edgelist_weights), std::nullopt, std::nullopt, + std::nullopt, + std::nullopt, cugraph::graph_properties_t{is_symmetric, false}, renumber); diff --git a/cpp/tests/utilities/test_graphs.hpp b/cpp/tests/utilities/test_graphs.hpp index ed96ba23917..145b3c7e676 100644 --- a/cpp/tests/utilities/test_graphs.hpp +++ b/cpp/tests/utilities/test_graphs.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, 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,7 @@ */ #pragma once +#include "cugraph/utilities/host_scalar_comm.hpp" #include "utilities/csv_file_utilities.hpp" #include "utilities/matrix_market_file_utilities.hpp" #include "utilities/misc_utilities.hpp" @@ -28,27 +29,54 @@ #include #include +#include namespace cugraph { namespace test { namespace detail { -template +template std::tuple, rmm::device_uvector, - std::optional>> -concatenate_edge_chunks(raft::handle_t const& handle, - std::vector>&& src_chunks, - std::vector>&& dst_chunks, - std::optional>> weight_chunks) + std::optional>, + std::optional>, + std::optional>, + std::optional>, + std::optional>> +concatenate_edge_chunks( + raft::handle_t const& handle, + std::vector>&& src_chunks, + std::vector>&& dst_chunks, + std::optional>>&& weight_chunks, + std::optional>>&& edge_id_chunks, + std::optional>>&& edge_type_chunks, + std::optional>>&& edge_start_time_chunks, + std::optional>>&& edge_end_time_chunks) { if (src_chunks.size() == 1) { - return std::make_tuple(std::move(src_chunks[0]), - std::move(dst_chunks[0]), - weight_chunks ? std::make_optional>( - std::move((*weight_chunks)[0])) - : std::nullopt); + return std::make_tuple( + std::move(src_chunks[0]), + std::move(dst_chunks[0]), + weight_chunks + ? std::make_optional>(std::move((*weight_chunks)[0])) + : std::nullopt, + edge_id_chunks + ? std::make_optional>(std::move((*edge_id_chunks)[0])) + : std::nullopt, + edge_type_chunks + ? std::make_optional>(std::move((*edge_type_chunks)[0])) + : std::nullopt, + edge_start_time_chunks ? std::make_optional>( + std::move((*edge_start_time_chunks)[0])) + : std::nullopt, + edge_end_time_chunks ? std::make_optional>( + std::move((*edge_end_time_chunks)[0])) + : std::nullopt); } else { size_t edge_count{0}; for (size_t i = 0; i < src_chunks.size(); ++i) { @@ -98,7 +126,83 @@ concatenate_edge_chunks(raft::handle_t const& handle, (*weight_chunks).clear(); } - return std::make_tuple(std::move(srcs), std::move(dsts), std::move(weights)); + auto edge_ids = edge_id_chunks ? std::make_optional>( + edge_count, handle.get_stream()) + : std::nullopt; + if (edge_ids) { + size_t offset{0}; + for (size_t i = 0; i < (*edge_id_chunks).size(); ++i) { + raft::copy((*edge_ids).data() + offset, + (*edge_id_chunks)[i].data(), + (*edge_id_chunks)[i].size(), + handle.get_stream()); + offset += (*edge_id_chunks)[i].size(); + (*edge_id_chunks)[i].resize(0, handle.get_stream()); + (*edge_id_chunks)[i].shrink_to_fit(handle.get_stream()); + } + (*edge_id_chunks).clear(); + } + + auto edge_types = edge_type_chunks ? std::make_optional>( + edge_count, handle.get_stream()) + : std::nullopt; + if (edge_types) { + size_t offset{0}; + for (size_t i = 0; i < (*edge_type_chunks).size(); ++i) { + raft::copy((*edge_types).data() + offset, + (*edge_type_chunks)[i].data(), + (*edge_type_chunks)[i].size(), + handle.get_stream()); + offset += (*edge_type_chunks)[i].size(); + (*edge_type_chunks)[i].resize(0, handle.get_stream()); + (*edge_type_chunks)[i].shrink_to_fit(handle.get_stream()); + } + (*edge_type_chunks).clear(); + } + + auto edge_start_times = + edge_start_time_chunks + ? std::make_optional>(edge_count, handle.get_stream()) + : std::nullopt; + if (edge_start_times) { + size_t offset{0}; + for (size_t i = 0; i < (*edge_start_time_chunks).size(); ++i) { + raft::copy((*edge_start_times).data() + offset, + (*edge_start_time_chunks)[i].data(), + (*edge_start_time_chunks)[i].size(), + handle.get_stream()); + offset += (*edge_start_time_chunks)[i].size(); + (*edge_start_time_chunks)[i].resize(0, handle.get_stream()); + (*edge_start_time_chunks)[i].shrink_to_fit(handle.get_stream()); + } + (*edge_start_time_chunks).clear(); + } + + auto edge_end_times = + edge_end_time_chunks + ? std::make_optional>(edge_count, handle.get_stream()) + : std::nullopt; + if (edge_end_times) { + size_t offset{0}; + for (size_t i = 0; i < (*edge_end_time_chunks).size(); ++i) { + raft::copy((*edge_end_times).data() + offset, + (*edge_end_time_chunks)[i].data(), + (*edge_end_time_chunks)[i].size(), + handle.get_stream()); + offset += (*edge_end_time_chunks)[i].size(); + (*edge_end_time_chunks)[i].resize(0, handle.get_stream()); + (*edge_end_time_chunks)[i].shrink_to_fit(handle.get_stream()); + } + (*edge_end_time_chunks).clear(); + } + + return std::make_tuple(std::move(srcs), + std::move(dsts), + std::move(weights), + std::move(edge_ids), + std::move(edge_types), + std::move(edge_start_times), + std::move(edge_end_times)); } } @@ -336,16 +440,21 @@ class Rmat_Usecase : public detail::TranslateGraph_Usecase { tmp_weights_v, std::ignore, std::ignore, + std::ignore, + std::ignore, std::ignore) = cugraph::detail::shuffle_ext_vertex_pairs_with_values_to_local_gpu_by_edge_partitioning< vertex_t, vertex_t, weight_t, + int32_t, int32_t>(handle, store_transposed ? std::move(tmp_dst_v) : std::move(tmp_src_v), store_transposed ? std::move(tmp_src_v) : std::move(tmp_dst_v), std::move(tmp_weights_v), std::nullopt, + std::nullopt, + std::nullopt, std::nullopt); } @@ -651,20 +760,47 @@ class CombinedGenerator_Usecase { template -std::tuple, - std::optional, - weight_t>>, - std::optional>> -construct_graph(raft::handle_t const& handle, - input_usecase_t const& input_usecase, - bool test_weighted, - bool renumber = true, - bool drop_self_loops = false, - bool drop_multi_edges = false) +std::tuple< + cugraph::graph_t, + std::optional< + cugraph::edge_property_t, + weight_t>>, + std::optional< + cugraph::edge_property_t, + edge_t>>, + std::optional< + cugraph::edge_property_t, + edge_type_t>>, + std::optional< + cugraph::edge_property_t, + edge_time_t>>, + std::optional< + cugraph::edge_property_t, + edge_time_t>>, + std::optional>> +construct_graph( + raft::handle_t const& handle, + input_usecase_t const& input_usecase, + bool test_weighted, + std::optional(raft::handle_t const&, size_t, size_t)>> + edge_ids_functor, + std::optional< + std::function(raft::handle_t const&, size_t, size_t)>> + edge_types_functor, + std::optional< + std::function(raft::handle_t const&, size_t, size_t)>> + edge_start_times_functor, + std::optional< + std::function(raft::handle_t const&, size_t, size_t)>> + edge_end_times_functor, + bool renumber = true, + bool drop_self_loops = false, + bool drop_multi_edges = false) { auto [edge_src_chunks, edge_dst_chunks, edge_weight_chunks, d_vertices_v, is_symmetric] = input_usecase.template construct_edgelist( @@ -676,36 +812,97 @@ construct_graph(raft::handle_t const& handle, } CUGRAPH_EXPECTS(num_edges <= static_cast(std::numeric_limits::max()), "Invalid template parameter: edge_t overflow."); + + size_t base_offset{0}; + if constexpr (multi_gpu) { + auto base_offsets = host_scalar_allgather(handle.get_comms(), num_edges, handle.get_stream()); + handle.sync_stream(); + std::exclusive_scan(base_offsets.begin(), base_offsets.end(), base_offsets.begin(), size_t{0}); + base_offset = base_offsets[handle.get_comms().get_rank()]; + } + + std::optional>> edge_id_chunks{std::nullopt}; + std::optional>> edge_type_chunks{std::nullopt}; + std::optional>> edge_start_time_chunks{std::nullopt}; + std::optional>> edge_end_time_chunks{std::nullopt}; + + if (edge_ids_functor) edge_id_chunks = std::vector>{}; + if (edge_types_functor) edge_type_chunks = std::vector>{}; + if (edge_start_times_functor) + edge_start_time_chunks = std::vector>{}; + if (edge_end_times_functor) + edge_end_time_chunks = std::vector>{}; + + for (size_t i = 0; i < edge_src_chunks.size(); ++i) { + if (edge_ids_functor) { + edge_id_chunks->push_back( + (*edge_ids_functor)(handle, edge_src_chunks[i].size(), base_offset)); + } + if (edge_types_functor) { + edge_type_chunks->push_back( + (*edge_types_functor)(handle, edge_src_chunks[i].size(), base_offset)); + } + if (edge_start_times_functor) { + edge_start_time_chunks->push_back( + (*edge_start_times_functor)(handle, edge_src_chunks[i].size(), base_offset)); + } + if (edge_end_times_functor) { + edge_end_time_chunks->push_back( + (*edge_end_times_functor)(handle, edge_src_chunks[i].size(), base_offset)); + } + } + if (drop_self_loops) { for (size_t i = 0; i < edge_src_chunks.size(); ++i) { std::optional> tmp_weights{std::nullopt}; - std::tie(edge_src_chunks[i], edge_dst_chunks[i], tmp_weights, std::ignore, std::ignore) = - cugraph::remove_self_loops( + std::optional> tmp_ids{std::nullopt}; + std::optional> tmp_types{std::nullopt}; + std::optional> tmp_start_times{std::nullopt}; + std::optional> tmp_end_times{std::nullopt}; + std::tie(edge_src_chunks[i], + edge_dst_chunks[i], + tmp_weights, + tmp_ids, + tmp_types, + tmp_start_times, + tmp_end_times) = + cugraph::remove_self_loops( handle, std::move(edge_src_chunks[i]), std::move(edge_dst_chunks[i]), edge_weight_chunks ? std::make_optional>(std::move((*edge_weight_chunks)[i])) : std::nullopt, - std::nullopt, - std::nullopt); + edge_id_chunks ? std::make_optional(std::move((*edge_id_chunks)[i])) : std::nullopt, + edge_type_chunks ? std::make_optional(std::move((*edge_type_chunks)[i])) : std::nullopt, + edge_start_time_chunks ? std::make_optional(std::move((*edge_start_time_chunks)[i])) + : std::nullopt, + edge_end_time_chunks ? std::make_optional(std::move((*edge_end_time_chunks)[i])) + : std::nullopt); if (tmp_weights) { (*edge_weight_chunks)[i] = std::move(*tmp_weights); } } } if (drop_multi_edges) { - auto [srcs, dsts, weights] = detail::concatenate_edge_chunks(handle, - std::move(edge_src_chunks), - std::move(edge_dst_chunks), - std::move(edge_weight_chunks)); - std::tie(srcs, dsts, weights, std::ignore, std::ignore) = + auto [srcs, dsts, weights, edge_ids, edge_types, edge_start_times, edge_end_times] = + detail::concatenate_edge_chunks(handle, + std::move(edge_src_chunks), + std::move(edge_dst_chunks), + std::move(edge_weight_chunks), + std::move(edge_id_chunks), + std::move(edge_type_chunks), + std::move(edge_start_time_chunks), + std::move(edge_end_time_chunks)); + std::tie(srcs, dsts, weights, edge_ids, edge_types, edge_start_times, edge_end_times) = cugraph::remove_multi_edges( handle, std::move(srcs), std::move(dsts), std::move(weights), - std::nullopt, - std::nullopt, + std::move(edge_ids), + std::move(edge_types), + std::move(edge_start_times), + std::move(edge_end_times), is_symmetric ? true /* keep minimum weight edges to maintain symmetry */ : false); edge_src_chunks = std::vector>{}; edge_src_chunks.push_back(std::move(srcs)); @@ -716,20 +913,49 @@ construct_graph(raft::handle_t const& handle, edge_weight_chunks = std::vector>{}; (*edge_weight_chunks).push_back(std::move(*weights)); } + if (edge_ids) { + edge_id_chunks = std::vector>{}; + (*edge_id_chunks).push_back(std::move(*edge_ids)); + } + if (edge_types) { + edge_type_chunks = std::vector>{}; + (*edge_type_chunks).push_back(std::move(*edge_types)); + } + if (edge_start_times) { + edge_start_time_chunks = std::vector>{}; + (*edge_start_time_chunks).push_back(std::move(*edge_start_times)); + } + if (edge_end_times) { + edge_end_time_chunks = std::vector>{}; + (*edge_end_time_chunks).push_back(std::move(*edge_end_times)); + } } graph_t graph(handle); std::optional< edge_property_t, weight_t>> edge_weights{std::nullopt}; + std::optional< + edge_property_t, edge_t>> + edge_ids{std::nullopt}; + std::optional< + edge_property_t, edge_type_t>> + edge_types{std::nullopt}; + std::optional< + edge_property_t, edge_time_t>> + edge_start_times{std::nullopt}; + std::optional< + edge_property_t, edge_time_t>> + edge_end_times{std::nullopt}; std::optional> renumber_map{std::nullopt}; if (edge_src_chunks.size() == 1) { - std::tie(graph, edge_weights, std::ignore, std::ignore, renumber_map) = + std::tie( + graph, edge_weights, edge_ids, edge_types, edge_start_times, edge_end_times, renumber_map) = cugraph::create_graph_from_edgelist( handle, @@ -737,17 +963,22 @@ construct_graph(raft::handle_t const& handle, std::move(edge_src_chunks[0]), std::move(edge_dst_chunks[0]), edge_weight_chunks ? std::make_optional(std::move((*edge_weight_chunks)[0])) : std::nullopt, - std::nullopt, - std::nullopt, + edge_id_chunks ? std::make_optional(std::move((*edge_id_chunks)[0])) : std::nullopt, + edge_type_chunks ? std::make_optional(std::move((*edge_type_chunks)[0])) : std::nullopt, + edge_start_time_chunks ? std::make_optional(std::move((*edge_start_time_chunks)[0])) + : std::nullopt, + edge_end_time_chunks ? std::make_optional(std::move((*edge_end_time_chunks)[0])) + : std::nullopt, cugraph::graph_properties_t{is_symmetric, drop_multi_edges ? false : true}, renumber); } else { - std::tie(graph, edge_weights, std::ignore, std::ignore, renumber_map) = + std::tie( + graph, edge_weights, edge_ids, edge_types, edge_start_times, edge_end_times, renumber_map) = cugraph::create_graph_from_edgelist( handle, @@ -755,12 +986,67 @@ construct_graph(raft::handle_t const& handle, std::move(edge_src_chunks), std::move(edge_dst_chunks), std::move(edge_weight_chunks), - std::nullopt, - std::nullopt, + std::move(edge_id_chunks), + std::move(edge_type_chunks), + std::move(edge_start_time_chunks), + std::move(edge_end_time_chunks), cugraph::graph_properties_t{is_symmetric, drop_multi_edges ? false : true}, renumber); } + return std::make_tuple(std::move(graph), + std::move(edge_weights), + std::move(edge_ids), + std::move(edge_types), + std::move(edge_start_times), + std::move(edge_end_times), + std::move(renumber_map)); +} + +template +std::tuple, + std::optional, + weight_t>>, + std::optional>> +construct_graph(raft::handle_t const& handle, + input_usecase_t const& input_usecase, + bool test_weighted, + bool renumber = true, + bool drop_self_loops = false, + bool drop_multi_edges = false) +{ + cugraph::graph_t graph(handle); + std::optional< + cugraph::edge_property_t, + weight_t>> + edge_weights{std::nullopt}; + std::optional> renumber_map{std::nullopt}; + + std::tie(graph, edge_weights, std::ignore, std::ignore, std::ignore, std::ignore, renumber_map) = + construct_graph(handle, + input_usecase, + test_weighted, + std::nullopt, + std::nullopt, + std::nullopt, + std::nullopt, + renumber, + drop_self_loops, + drop_multi_edges); + return std::make_tuple(std::move(graph), std::move(edge_weights), std::move(renumber_map)); } diff --git a/cpp/tests/utilities/thrust_wrapper.cu b/cpp/tests/utilities/thrust_wrapper.cu index 095cd15872b..c2f561f1eb6 100644 --- a/cpp/tests/utilities/thrust_wrapper.cu +++ b/cpp/tests/utilities/thrust_wrapper.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -596,5 +596,27 @@ template std::tuple, rmm::device_uvector> rmm::device_uvector&& v1, rmm::device_uvector&& v2); +template +bool device_spans_equal(raft::handle_t const& handle, + raft::device_span array_left, + raft::device_span array_right) +{ + return thrust::equal( + handle.get_thrust_policy(), array_left.begin(), array_left.end(), array_right.begin()); +} + +template bool device_spans_equal(raft::handle_t const& handle, + raft::device_span array_left, + raft::device_span array_right); +template bool device_spans_equal(raft::handle_t const& handle, + raft::device_span array_left, + raft::device_span array_right); +template bool device_spans_equal(raft::handle_t const& handle, + raft::device_span array_left, + raft::device_span array_right); +template bool device_spans_equal(raft::handle_t const& handle, + raft::device_span array_left, + raft::device_span array_right); + } // namespace test } // namespace cugraph diff --git a/cpp/tests/utilities/thrust_wrapper.hpp b/cpp/tests/utilities/thrust_wrapper.hpp index b6c8052e6b5..f60146cf0be 100644 --- a/cpp/tests/utilities/thrust_wrapper.hpp +++ b/cpp/tests/utilities/thrust_wrapper.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024, NVIDIA CORPORATION. + * Copyright (c) 2021-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -118,5 +118,10 @@ std::tuple, rmm::device_uvector> remove_ rmm::device_uvector&& v1, rmm::device_uvector&& v2); +template +bool device_spans_equal(raft::handle_t const& handle, + raft::device_span array_left, + raft::device_span array_right); + } // namespace test } // namespace cugraph diff --git a/cpp/tests/utilities/validation_utilities.cu b/cpp/tests/utilities/validation_utilities.cu index 3da998ad626..4ea9f0042c0 100644 --- a/cpp/tests/utilities/validation_utilities.cu +++ b/cpp/tests/utilities/validation_utilities.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, NVIDIA CORPORATION. + * Copyright (c) 2024-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -67,6 +67,320 @@ void sort(raft::handle_t const& handle, thrust::make_zip_iterator(srcs.end(), dsts.end())); } +template +void sort(raft::handle_t const& handle, + raft::device_span srcs, + raft::device_span dsts, + std::optional> wgts, + std::optional> ids, + std::optional> types, + std::optional> start_times, + std::optional> end_times) +{ + if (wgts) { + if (ids) { + if (types) { + if (start_times) { + if (end_times) { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), + dsts.begin(), + wgts->begin(), + ids->begin(), + types->begin(), + start_times->begin(), + end_times->begin()), + thrust::make_zip_iterator(srcs.end(), + dsts.end(), + wgts->end(), + ids->end(), + types->end(), + start_times->end(), + end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), + dsts.begin(), + wgts->begin(), + ids->begin(), + types->begin(), + start_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), wgts->end(), ids->end(), types->end(), start_times->end())); + } + } else { + if (end_times) { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), + dsts.begin(), + wgts->begin(), + ids->begin(), + types->begin(), + end_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), wgts->end(), ids->end(), types->end(), end_times->end())); + } else { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), wgts->begin(), ids->begin(), types->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), wgts->end(), ids->end(), types->end())); + } + } + } else { + if (start_times) { + if (end_times) { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), + dsts.begin(), + wgts->begin(), + ids->begin(), + start_times->begin(), + end_times->begin()), + thrust::make_zip_iterator(srcs.end(), + dsts.end(), + wgts->end(), + ids->end(), + start_times->end(), + end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), wgts->begin(), ids->begin(), start_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), wgts->end(), ids->end(), start_times->end())); + } + } else { + if (end_times) { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), wgts->begin(), ids->begin(), end_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), wgts->end(), ids->end(), end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), dsts.begin(), wgts->begin(), ids->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), wgts->end(), ids->end())); + } + } + } + } else { + if (types) { + if (start_times) { + if (end_times) { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), + dsts.begin(), + wgts->begin(), + types->begin(), + start_times->begin(), + end_times->begin()), + thrust::make_zip_iterator(srcs.end(), + dsts.end(), + wgts->end(), + types->end(), + start_times->end(), + end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), wgts->begin(), types->begin(), start_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), wgts->end(), types->end(), start_times->end())); + } + } else { + if (end_times) { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), wgts->begin(), types->begin(), end_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), wgts->end(), types->end(), end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), dsts.begin(), wgts->begin(), types->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), wgts->end(), types->end())); + } + } + } else { + if (start_times) { + if (end_times) { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), + dsts.begin(), + wgts->begin(), + start_times->begin(), + end_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), wgts->end(), start_times->end(), end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), wgts->begin(), start_times->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), wgts->end(), start_times->end())); + } + } else { + if (end_times) { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), wgts->begin(), end_times->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), wgts->end(), end_times->end())); + } else { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), dsts.begin(), wgts->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), wgts->end())); + } + } + } + } + } else { + if (ids) { + if (types) { + if (start_times) { + if (end_times) { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), + dsts.begin(), + ids->begin(), + types->begin(), + start_times->begin(), + end_times->begin()), + thrust::make_zip_iterator(srcs.end(), + dsts.end(), + ids->end(), + types->end(), + start_times->end(), + end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), ids->begin(), types->begin(), start_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), ids->end(), types->end(), start_times->end())); + } + } else { + if (end_times) { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), ids->begin(), types->begin(), end_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), ids->end(), types->end(), end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), dsts.begin(), ids->begin(), types->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), ids->end(), types->end())); + } + } + } else { + if (start_times) { + if (end_times) { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), ids->begin(), start_times->begin(), end_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), ids->end(), start_times->end(), end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), ids->begin(), start_times->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), ids->end(), start_times->end())); + } + } else { + if (end_times) { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), ids->begin(), end_times->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), ids->end(), end_times->end())); + } else { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), dsts.begin(), ids->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), ids->end())); + } + } + } + } else { + if (types) { + if (start_times) { + if (end_times) { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), + dsts.begin(), + types->begin(), + start_times->begin(), + end_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), types->end(), start_times->end(), end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), types->begin(), start_times->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), types->end(), start_times->end())); + } + } else { + if (end_times) { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), types->begin(), end_times->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), types->end(), end_times->end())); + } else { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), dsts.begin(), types->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), types->end())); + } + } + } else { + if (start_times) { + if (end_times) { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator( + srcs.begin(), dsts.begin(), start_times->begin(), end_times->begin()), + thrust::make_zip_iterator( + srcs.end(), dsts.end(), start_times->end(), end_times->end())); + } else { + thrust::sort( + handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), dsts.begin(), start_times->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), start_times->end())); + } + } else { + if (end_times) { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), dsts.begin(), end_times->begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end(), end_times->end())); + } else { + thrust::sort(handle.get_thrust_policy(), + thrust::make_zip_iterator(srcs.begin(), dsts.begin()), + thrust::make_zip_iterator(srcs.end(), dsts.end())); + } + } + } + } + } +} + template size_t count_intersection(raft::handle_t const& handle, raft::device_span srcs1, @@ -178,6 +492,78 @@ template void sort(raft::handle_t const& handle, raft::device_span srcs, raft::device_span dsts); +template void sort(raft::handle_t const& handle, + raft::device_span srcs, + raft::device_span dsts, + std::optional> wgts, + std::optional> ids, + std::optional> types, + std::optional> start_times, + std::optional> end_times); + +template void sort(raft::handle_t const& handle, + raft::device_span srcs, + raft::device_span dsts, + std::optional> wgts, + std::optional> ids, + std::optional> types, + std::optional> start_times, + std::optional> end_times); + +template void sort(raft::handle_t const& handle, + raft::device_span srcs, + raft::device_span dsts, + std::optional> wgts, + std::optional> ids, + std::optional> types, + std::optional> start_times, + std::optional> end_times); + +template void sort(raft::handle_t const& handle, + raft::device_span srcs, + raft::device_span dsts, + std::optional> wgts, + std::optional> ids, + std::optional> types, + std::optional> start_times, + std::optional> end_times); + +template void sort(raft::handle_t const& handle, + raft::device_span srcs, + raft::device_span dsts, + std::optional> wgts, + std::optional> ids, + std::optional> types, + std::optional> start_times, + std::optional> end_times); + +template void sort(raft::handle_t const& handle, + raft::device_span srcs, + raft::device_span dsts, + std::optional> wgts, + std::optional> ids, + std::optional> types, + std::optional> start_times, + std::optional> end_times); + +template void sort(raft::handle_t const& handle, + raft::device_span srcs, + raft::device_span dsts, + std::optional> wgts, + std::optional> ids, + std::optional> types, + std::optional> start_times, + std::optional> end_times); + +template void sort(raft::handle_t const& handle, + raft::device_span srcs, + raft::device_span dsts, + std::optional> wgts, + std::optional> ids, + std::optional> types, + std::optional> start_times, + std::optional> end_times); + template size_t count_intersection(raft::handle_t const& handle, raft::device_span srcs1, raft::device_span dsts1, diff --git a/cpp/tests/utilities/validation_utilities.hpp b/cpp/tests/utilities/validation_utilities.hpp index b94ceaf68be..7d72c095cd3 100644 --- a/cpp/tests/utilities/validation_utilities.hpp +++ b/cpp/tests/utilities/validation_utilities.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, NVIDIA CORPORATION. + * Copyright (c) 2024-2025, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,6 +38,20 @@ void sort(raft::handle_t const& handle, raft::device_span srcs, raft::device_span dsts); +template +void sort(raft::handle_t const& handle, + raft::device_span srcs, + raft::device_span dsts, + std::optional> wgts, + std::optional> ids, + std::optional> types, + std::optional> start_times, + std::optional> end_times); + template size_t count_intersection(raft::handle_t const& handle, raft::device_span srcs1,