Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add generic edge properties object #4767

Draft
wants to merge 2 commits into
base: branch-24.12
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ set(CUGRAPH_SOURCES
src/community/detail/maximal_independent_moves_mg_v32_e32.cu
src/detail/utility_wrappers_32.cu
src/detail/utility_wrappers_64.cu
src/structure/edge_properties_v32.cpp
src/structure/edge_properties_v64.cpp
src/utilities/cugraph_data_type_id.cpp
src/structure/graph_view_mg_v64_e64.cu
src/structure/graph_view_mg_v32_e32.cu
src/structure/remove_self_loops_sg_v32_e32.cu
Expand Down
157 changes: 157 additions & 0 deletions cpp/include/cugraph/device_vector.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Copyright (c) 2024, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <cugraph_c/types.h>

#include <cugraph/utilities/cugraph_data_type_id.hpp>
#include <cugraph/utilities/error.hpp>
#include <cugraph/utilities/packed_bool_utils.hpp>

#include <raft/core/handle.hpp>

#include <rmm/cuda_stream_view.hpp>
#include <rmm/device_buffer.hpp>
#include <rmm/device_uvector.hpp>

namespace cugraph {

namespace detail {

inline rmm::device_buffer allocate_buffer(raft::handle_t const& handle,
cugraph_data_type_id_t t,
size_t size)
{
return (t == BOOL) ? rmm::device_buffer(cugraph::packed_bool_size(size) * data_type_size(t),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cugraph::packed_bool_size(size) * data_type_size(t), should data_type_size(t) here be sizeof(uint32_t)?

handle.get_stream())
: rmm::device_buffer(size * data_type_size(t), handle.get_stream());
}

} // namespace detail

/**
* Class wrapping a type-erased device vector.
* */
class device_vector_t {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure device_vector is a right name for type erased edge property vector. device_vector reminds me of thrust::device_vector or rmm::device_uvector. They are not type-erased vectors.

We may need a better name. My suggestions: edge_property_buffer or property_buffer or cugraph::device_buffer. rmm::device_buffer does not assume a specific type and may be more appropriate for type erased data types. Or we may use column (adopt column from cudf::column). In cuDF C++, they use cudf::column to store cuDF series. We may say edge_property_column or property_column or cugraph::device_column or just cugraph::column. In this case, we may rename the above allocate_buffer function to allocate_column_buffer as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we need more discussion about this naming.

public:
/**
* Constructor creating a device vector
*
* @param data_type The data type of the vector
* @param size The number of elements in the vector
*/
device_vector_t(raft::handle_t const& handle, cugraph_data_type_id_t data_type, size_t size)
: data_(detail::allocate_buffer(handle, data_type, size)), type_(data_type), size_(size)
{
}

/**
* Constructor initializing device vector from an rmm device uvector
*
* @tparam T type for the array/vector
* @param vector Vector to
*/
template <typename T>
device_vector_t(rmm::device_uvector<T>&& vector) : type_(type_to_id<T>()), size_(vector.size())
{
data_ = vector.release();
}

/**
* Return a pointer of the specified type to the beginning of the vector
*
* @tparam T type for the array vector
*
* @return pointer to the beginning of the vector
*/
template <typename T>
T* begin()
{
return reinterpret_cast<T*>(data_.data());
}

/**
* Return a const pointer of the specified type to the beginning of the vector
*
* @tparam T type for the array vector
*
* @return const pointer to the beginning of the vector
*/
template <typename T>
T const* begin() const
{
return reinterpret_cast<T const*>(data_.data());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may add cbegin() and cend() as well.


/**
* Return a pointer of the specified type to the end of the vector
*
* @tparam T type for the array vector
*
* @return pointer to the end of the vector
*/
template <typename T>
T* end()
{
return reinterpret_cast<T*>(data_.data()) + size_;
}

/**
* Return a const pointer of the specified type to the end of the vector
*
* @tparam T type for the array vector
*
* @return const pointer to the end of the vector
*/
template <typename T>
T const* end() const
{
return reinterpret_cast<T const*>(data_.data()) + size_;
}

/**
* Return the type of the vector
*
* @return type id of the type stored in the vector
*/
cugraph_data_type_id_t type() const { return type_; }

/**
* Return the number of elements in the vector
*
* @return number of elements in the vector
*/
size_t size() const { return size_; }

/**
* Release the vector and shrink the memory used
*
* @param stream_view CUDA stream
*/
void clear(rmm::cuda_stream_view stream_view)
{
data_.resize(0, stream_view);
data_.shrink_to_fit(stream_view);
}

private:
rmm::device_buffer data_{};
cugraph_data_type_id_t type_{NTYPES};
size_t size_{0};
};

} // namespace cugraph
174 changes: 174 additions & 0 deletions cpp/include/cugraph/edge_properties.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* Copyright (c) 2024, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <cugraph_c/types.h>

#include <cugraph/device_vector.hpp>
#include <cugraph/edge_property.hpp>
#include <cugraph/utilities/cugraph_data_type_id.hpp>
#include <cugraph/utilities/error.hpp>

#include <raft/core/handle.hpp>

namespace cugraph {

namespace detail {

class edge_property_impl_t {
public:
edge_property_impl_t(raft::handle_t const& handle,
cugraph_data_type_id_t data_type,
std::vector<size_t> const& edge_counts);

edge_property_impl_t(cugraph_data_type_id_t data_type,
std::vector<cugraph::device_vector_t>&& vectors);

template <typename value_type>
edge_property_impl_t(std::vector<rmm::device_uvector<value_type>>&& vectors,
std::vector<size_t> const& edge_counts);

template <typename edge_t, typename value_t>
edge_property_view_t<edge_t, value_t const*> view(std::vector<size_t> const& edge_counts) const;

template <typename edge_t, typename value_t>
edge_property_view_t<edge_t, value_t*> mutable_view(std::vector<size_t> const& edge_counts);

cugraph_data_type_id_t data_type() const { return dtype_; }

private:
cugraph_data_type_id_t dtype_{NTYPES};
std::vector<cugraph::device_vector_t> vectors_{};
};

} // namespace detail

/**
* Class for containing a collection of edge properties. Semantic interpretation of
* the properties is for the caller to interpret.
*
* Edge properties are labeled as in a vector, from 0 to n-1. It is up to the caller to
* handle proper usage of the properties.
*/
class edge_properties_t {
public:
/**
* Constructor initializing properties from a graph view
*
* @tparam GraphViewType type for the graph view
* @param graph_view Graph view object
*/
template <typename GraphViewType>
edge_properties_t(GraphViewType const& graph_view);

/**
* Adds an empty property of the specified type.
*
* Fails if the property for @p idx is already defined
*
* @param handle Handle for resources
* @param idx Index of which property to add
* @param data_type Data type of the property to add
*/
void add_property(raft::handle_t const& handle, size_t idx, cugraph_data_type_id_t data_type);

/**
* Adds a property of the specified type initialized with the provided values
*
* Fails if the property for @p idx is already defined
*
* @tparam value_type Type of the property
* @param idx Index of which property to add
* @param buffers Initial value of the property
*/
template <typename value_type>
void add_property(size_t idx, std::vector<rmm::device_uvector<value_type>>&& buffers);

/**
* Adds a property initialized with the provided values
*
* Fails if the property for @p idx is already defined
*
* @param idx Index of which property to add
* @param vectors Type erased device vectors for the initial value
*/
void add_property(size_t idx, std::vector<cugraph::device_vector_t>&& vectors);
/**
* Clears the specified property, releasing any allocated memory
*
* @param idx Index of which property to clear
*/
void clear_property(size_t idx);

/**
* clears all properties, releasing any allocate memory
*/
void clear_all_properties();

/**
* Returns true if property @p idx is defined
*/
bool is_defined(size_t idx);

/**
* Returns data type of property @p idx
*/
cugraph_data_type_id_t data_type(size_t idx);

/**
* Returns a read-only edge property view of the property using the provided types
*
* Throws exception if idx does not refer to a defined property.
* Throws exception if value_t does not match the property type
*
* @tparam edge_t Typename for the edge
* @tparam value_t Typename for the property
* @param idx Index of the property
*
* @return a read-only view for accessing the property
*/
template <typename edge_t, typename value_t>
edge_property_view_t<edge_t, value_t const*> view(size_t idx) const;

/**
* Returns a read-write edge property view of the property using the provided types
*
* Throws exception if idx does not refer to a defined property.
* Throws exception if value_t does not match the property type
*
* @tparam edge_t Typename for the edge
* @tparam value_t Typename for the property
* @param idx Index of the property
*
* @return a read-write view for accessing the property
*/
template <typename edge_t, typename value_t>
edge_property_view_t<edge_t, value_t*> mutable_view(size_t idx);

/**
* Return list of defined properties
*
* @return vector of defined property indexes
*/
std::vector<size_t> defined() const;

private:
std::vector<std::optional<detail::edge_property_impl_t>> properties_{};
std::vector<size_t> edge_counts_{};
};

} // namespace cugraph
Loading
Loading