diff --git a/include/osp/auxiliary/io/DotFileWriter.hpp b/include/osp/auxiliary/io/DotFileWriter.hpp index f8e7c938..907fcb06 100644 --- a/include/osp/auxiliary/io/DotFileWriter.hpp +++ b/include/osp/auxiliary/io/DotFileWriter.hpp @@ -463,7 +463,7 @@ class DotFileWriter { } write_graph_structure( - os, g2, VertexWriterDuplicateRecompSchedule_DOT(g2, names, node_to_proc, node_to_superstep)); + os, g2, VertexWriterDuplicateRecompSchedule_DOT(g2, names, node_to_proc, node_to_superstep)); } template diff --git a/include/osp/bsp/model/BspInstance.hpp b/include/osp/bsp/model/BspInstance.hpp index f59a1e64..4e31d145 100644 --- a/include/osp/bsp/model/BspInstance.hpp +++ b/include/osp/bsp/model/BspInstance.hpp @@ -106,7 +106,7 @@ class BspInstance { explicit BspInstance(const BspInstance &other) : architecture(other.getArchitecture()), nodeProcessorCompatibility(other.getNodeProcessorCompatibilityMatrix()) { - construct_computational_dag(other.getComputationalDag(), cdag); + constructComputationalDag(other.getComputationalDag(), cdag); } BspInstance(const BspInstance &other) = default; diff --git a/include/osp/coarser/StepByStep/StepByStepCoarser.hpp b/include/osp/coarser/StepByStep/StepByStepCoarser.hpp index b5d77937..ba2dbdf1 100644 --- a/include/osp/coarser/StepByStep/StepByStepCoarser.hpp +++ b/include/osp/coarser/StepByStep/StepByStepCoarser.hpp @@ -156,7 +156,7 @@ std::vector> StepByStepCoarser::generate_vertex_c G_coarse.remove_vertex(node); } - construct_computational_dag(G_full, G_coarse); + constructComputationalDag(G_full, G_coarse); contractionHistory.clear(); diff --git a/include/osp/graph_algorithms/computational_dag_construction_util.hpp b/include/osp/graph_algorithms/computational_dag_construction_util.hpp index 1f7ee020..e85217e9 100644 --- a/include/osp/graph_algorithms/computational_dag_construction_util.hpp +++ b/include/osp/graph_algorithms/computational_dag_construction_util.hpp @@ -18,47 +18,52 @@ limitations under the License. #pragma once -#include - #include "osp/concepts/computational_dag_concept.hpp" #include "osp/concepts/constructable_computational_dag_concept.hpp" -#include "directed_graph_top_sort.hpp" namespace osp { +/** + * @brief Constructs a computational DAG from another graph. + * + * This function copies the structure and properties of a source graph into a target graph structure. + * Assumes that the vertices of the source graph are indexed from 0 to N-1. If the target graph is empty, indices are sequentially assigned starting from 0. + * If the target graph is not empty, new vertices will be added to the target graph and their indices will be sequentially assigned starting from the index N. + * + * @tparam Graph_from The type of the source graph. Must satisfy `is_computational_dag`. + * @tparam Graph_to The type of the target graph. Must satisfy `is_constructable_cdag_vertex`. + * @param from The source graph. + * @param to The target graph. + */ template -bool construct_computational_dag(const Graph_from &from, Graph_to &to) { - +void constructComputationalDag(const Graph_from &from, Graph_to &to) { static_assert(is_computational_dag_v, "Graph_from must satisfy the computational_dag concept"); - static_assert(is_constructable_cdag_vertex_v, - "Graph_to must satisfy the constructable_cdag_vertex concept"); + static_assert(is_constructable_cdag_vertex_v, "Graph_to must satisfy the constructable_cdag_vertex concept"); - for (const auto &v_idx : from.vertices()) { + std::vector> vertex_map; + vertex_map.reserve(from.num_vertices()); + for (const auto &v_idx : from.vertices()) { if constexpr (has_typed_vertices_v and has_typed_vertices_v) { - to.add_vertex(from.vertex_work_weight(v_idx), from.vertex_comm_weight(v_idx), - from.vertex_mem_weight(v_idx), from.vertex_type(v_idx)); + vertex_map.push_back(to.add_vertex(from.vertex_work_weight(v_idx), from.vertex_comm_weight(v_idx), + from.vertex_mem_weight(v_idx), from.vertex_type(v_idx))); } else { - to.add_vertex(from.vertex_work_weight(v_idx), from.vertex_comm_weight(v_idx), - from.vertex_mem_weight(v_idx)); + vertex_map.push_back(to.add_vertex(from.vertex_work_weight(v_idx), from.vertex_comm_weight(v_idx), + from.vertex_mem_weight(v_idx))); } } if constexpr (has_edge_weights_v and has_edge_weights_v) { - for (const auto &e : edges(from)) { - to.add_edge(source(e, from), target(e, from), from.edge_comm_weight(e)); + to.add_edge(vertex_map.at(source(e, from)), vertex_map.at(target(e, from)), from.edge_comm_weight(e)); } - } else { for (const auto &v : from.vertices()) { for (const auto &child : from.children(v)) { - to.add_edge(v, child); + to.add_edge(vertex_map.at(v), vertex_map.at(child)); } } } - - return true; } } // namespace osp diff --git a/include/osp/graph_implementations/adj_list_impl/cdag_vertex_impl.hpp b/include/osp/graph_implementations/adj_list_impl/cdag_vertex_impl.hpp new file mode 100644 index 00000000..0b67ab30 --- /dev/null +++ b/include/osp/graph_implementations/adj_list_impl/cdag_vertex_impl.hpp @@ -0,0 +1,87 @@ +/* +Copyright 2024 Huawei Technologies Co., Ltd. + +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. + +@author Toni Boehnlein, Benjamin Lozes, Pal Andras Papp, Raphael S. Steiner +*/ +#pragma once + +namespace osp { + +/** + * @brief Implementation of a computational DAG vertex. + * + * This struct holds the properties of a vertex in a computational DAG, including its ID, + * weights (work, communication, memory), and type. + * + * @tparam vertex_idx_t Type for vertex indices. + * @tparam workw_t Type for work weights. + * @tparam commw_t Type for communication weights. + * @tparam memw_t Type for memory weights. + * @tparam vertex_type_t Type for vertex types. + */ +template +struct cdag_vertex_impl { + + using vertex_idx_type = vertex_idx_t; + using work_weight_type = workw_t; + using comm_weight_type = commw_t; + using mem_weight_type = memw_t; + using cdag_vertex_type_type = vertex_type_t; + + cdag_vertex_impl() = default; + + cdag_vertex_impl(const cdag_vertex_impl &other) = default; + cdag_vertex_impl(cdag_vertex_impl &&other) noexcept = default; + cdag_vertex_impl &operator=(const cdag_vertex_impl &other) = default; + cdag_vertex_impl &operator=(cdag_vertex_impl &&other) noexcept = default; + + /** + * @brief Constructs a vertex with specified properties. + * + * @param vertex_idx_ The unique identifier for the vertex. + * @param work_w The computational work weight. + * @param comm_w The communication weight. + * @param mem_w The memory weight. + * @param vertex_t The type of the vertex. + */ + cdag_vertex_impl(vertex_idx_t vertex_idx_, workw_t work_w, commw_t comm_w, memw_t mem_w, + vertex_type_t vertex_t) + : id(vertex_idx_), work_weight(work_w), comm_weight(comm_w), mem_weight(mem_w), + vertex_type(vertex_t) {} + + vertex_idx_t id = 0; + + workw_t work_weight = 0; + commw_t comm_weight = 0; + memw_t mem_weight = 0; + + vertex_type_t vertex_type = 0; +}; + +/** + * @brief A vertex implementation with integer weights. Indexed by size_t. Node types are unsigned. + * + * This struct implements a vertex with integer weights for work, communication, and memory. + */ +using cdag_vertex_impl_int = cdag_vertex_impl; + +/** + * @brief A vertex implementation with unsigned weights. Indexed by size_t. Node types are unsigned. + * + * This struct implements a vertex with unsigned weights for work, communication, and memory. + */ +using cdag_vertex_impl_unsigned = cdag_vertex_impl; + +} // namespace osp \ No newline at end of file diff --git a/include/osp/graph_implementations/adj_list_impl/computational_dag_edge_idx_vector_impl.hpp b/include/osp/graph_implementations/adj_list_impl/computational_dag_edge_idx_vector_impl.hpp index d72bfb58..5a439664 100644 --- a/include/osp/graph_implementations/adj_list_impl/computational_dag_edge_idx_vector_impl.hpp +++ b/include/osp/graph_implementations/adj_list_impl/computational_dag_edge_idx_vector_impl.hpp @@ -18,8 +18,9 @@ limitations under the License. #pragma once #include "osp/auxiliary/hash_util.hpp" -#include "computational_dag_vector_impl.hpp" +#include "cdag_vertex_impl.hpp" #include "edge_iterator.hpp" +#include "osp/graph_implementations/integral_range.hpp" #include "osp/graph_algorithms/computational_dag_construction_util.hpp" #include @@ -123,7 +124,7 @@ class computational_dag_edge_idx_vector_impl { static_assert(is_computational_dag_v, "Graph_t must satisfy the is_computation_dag concept"); - construct_computational_dag(other, *this); + constructComputationalDag(other, *this); } computational_dag_edge_idx_vector_impl &operator=(const computational_dag_edge_idx_vector_impl &other) = default; diff --git a/include/osp/graph_implementations/adj_list_impl/computational_dag_vector_impl.hpp b/include/osp/graph_implementations/adj_list_impl/computational_dag_vector_impl.hpp index 627b0a86..74340de6 100644 --- a/include/osp/graph_implementations/adj_list_impl/computational_dag_vector_impl.hpp +++ b/include/osp/graph_implementations/adj_list_impl/computational_dag_vector_impl.hpp @@ -17,47 +17,47 @@ limitations under the License. */ #pragma once +#include "cdag_vertex_impl.hpp" #include "osp/concepts/computational_dag_concept.hpp" #include "osp/concepts/directed_graph_edge_desc_concept.hpp" #include "osp/graph_algorithms/computational_dag_construction_util.hpp" #include "osp/graph_implementations/integral_range.hpp" #include -namespace osp { - -template -struct cdag_vertex_impl { - - using vertex_idx_type = vertex_idx_t; - using work_weight_type = workw_t; - using comm_weight_type = commw_t; - using mem_weight_type = memw_t; - using cdag_vertex_type_type = vertex_type_t; - - cdag_vertex_impl() : id(0), work_weight(0), comm_weight(0), mem_weight(0), vertex_type(0) {} - - cdag_vertex_impl(const cdag_vertex_impl &other) = default; - cdag_vertex_impl(cdag_vertex_impl &&other) = default; - cdag_vertex_impl &operator=(const cdag_vertex_impl &other) = default; - cdag_vertex_impl &operator=(cdag_vertex_impl &&other) = default; - - cdag_vertex_impl(vertex_idx_t vertex_idx_, workw_t work_w, commw_t comm_w, memw_t mem_w, - vertex_type_t vertex_t) - : id(vertex_idx_), work_weight(work_w), comm_weight(comm_w), mem_weight(mem_w), - vertex_type(vertex_t) {} - - vertex_idx_t id; +#include - workw_t work_weight; - commw_t comm_weight; - memw_t mem_weight; - - vertex_type_t vertex_type; -}; - -using cdag_vertex_impl_int = cdag_vertex_impl; -using cdag_vertex_impl_unsigned = cdag_vertex_impl; +namespace osp { +/** + * @brief A vector-based implementation of a computational DAG. + * + * This class implements a computational DAG using adjacency lists stored in two std::vectors. + * It manages the storage of vertices and edges, and provides an interface to query and modify the graph. + * + * This class satisfies the following concepts: + * - `is_computational_dag_typed_vertices` + * - `is_directed_graph` + * - `has_vertex_weights` + * - `is_directed_graph_edge_desc` + * + * @tparam v_impl The vertex implementation type. This type must satisfy the following requirements: + * - It must define the following member types: + * - `vertex_idx_type`: The type used for vertex indices (e.g., `size_t`). + * - `work_weight_type`: The type used for computational work weights. + * - `comm_weight_type`: The type used for communication weights. + * - `mem_weight_type`: The type used for memory weights. + * - `cdag_vertex_type_type`: The type used for vertex types. + * - It must have the following public data members: + * - `id`: Of type `vertex_idx_type`. + * - `work_weight`: Of type `work_weight_type`. + * - `comm_weight`: Of type `comm_weight_type`. + * - `mem_weight`: Of type `mem_weight_type`. + * - `vertex_type`: Of type `cdag_vertex_type_type`. + * - It must be constructible with the signature: + * `v_impl(vertex_idx_type id, work_weight_type work_weight, comm_weight_type comm_weight, mem_weight_type mem_weight, cdag_vertex_type_type vertex_type)` + * + * @see cdag_vertex_impl for a reference implementation of the vertex type. + */ template class computational_dag_vector_impl { public: @@ -70,27 +70,41 @@ class computational_dag_vector_impl { computational_dag_vector_impl() = default; - computational_dag_vector_impl(vertex_idx num_vertices) + /** + * @brief Constructs a graph with a specified number of vertices. + * + * @param num_vertices The number of vertices to initialize. + */ + explicit computational_dag_vector_impl(const vertex_idx num_vertices) : vertices_(num_vertices), out_neigbors(num_vertices), in_neigbors(num_vertices), num_edges_(0), num_vertex_types_(0) { for (vertex_idx i = 0; i < num_vertices; ++i) { - vertices_[i].id = i; + vertices_.at(i).id = i; } } computational_dag_vector_impl(const computational_dag_vector_impl &other) = default; computational_dag_vector_impl &operator=(const computational_dag_vector_impl &other) = default; + /** + * @brief Constructs a graph from another graph type. + * + * This constructor initializes the graph by copying the structure and properties from another graph `other`. + * The source graph `Graph_t` must satisfy the `is_computational_dag` concept. + * + * @tparam Graph_t The type of the source graph. Must satisfy `is_computational_dag_v`. + * @param other The source graph to copy from. + */ template - computational_dag_vector_impl(const Graph_t &other) { + explicit computational_dag_vector_impl(const Graph_t &other) { static_assert(is_computational_dag_v, "Graph_t must satisfy the is_computation_dag concept"); - construct_computational_dag(other, *this); + constructComputationalDag(other, *this); } - computational_dag_vector_impl(computational_dag_vector_impl &&other) + computational_dag_vector_impl(computational_dag_vector_impl &&other) noexcept : vertices_(std::move(other.vertices_)), out_neigbors(std::move(other.out_neigbors)), in_neigbors(std::move(other.in_neigbors)), num_edges_(other.num_edges_), num_vertex_types_(other.num_vertex_types_) { @@ -99,7 +113,7 @@ class computational_dag_vector_impl { other.num_vertex_types_ = 0; }; - computational_dag_vector_impl &operator=(computational_dag_vector_impl &&other) { + computational_dag_vector_impl &operator=(computational_dag_vector_impl &&other) noexcept { if (this != &other) { vertices_ = std::move(other.vertices_); out_neigbors = std::move(other.out_neigbors); @@ -115,34 +129,73 @@ class computational_dag_vector_impl { virtual ~computational_dag_vector_impl() = default; - inline auto vertices() const { return integral_range(static_cast(vertices_.size())); } - - inline vertex_idx num_vertices() const { return static_cast(vertices_.size()); } - - inline vertex_idx num_edges() const { return num_edges_; } - - inline const std::vector &parents(const vertex_idx v) const { return in_neigbors[v]; } - - inline const std::vector &children(const vertex_idx v) const { return out_neigbors[v]; } - - inline vertex_idx in_degree(const vertex_idx v) const { return static_cast(in_neigbors[v].size()); } - - inline vertex_idx out_degree(const vertex_idx v) const { return static_cast(out_neigbors[v].size()); } - - inline vertex_work_weight_type vertex_work_weight(const vertex_idx v) const { return vertices_[v].work_weight; } - - inline vertex_comm_weight_type vertex_comm_weight(const vertex_idx v) const { return vertices_[v].comm_weight; } - - inline vertex_mem_weight_type vertex_mem_weight(const vertex_idx v) const { return vertices_[v].mem_weight; } - - inline vertex_type_type vertex_type(const vertex_idx v) const { return vertices_[v].vertex_type; } - - inline vertex_type_type num_vertex_types() const { return num_vertex_types_; } - - inline const v_impl &get_vertex_impl(const vertex_idx v) const { return vertices_[v]; } - - vertex_idx add_vertex(vertex_work_weight_type work_weight, vertex_comm_weight_type comm_weight, - vertex_mem_weight_type mem_weight, vertex_type_type vertex_type = 0) { + /** + * @brief Returns a range of all vertex indices. + */ + [[nodiscard]] auto vertices() const { return integral_range(static_cast(vertices_.size())); } + + /** + * @brief Returns the total number of vertices. + */ + [[nodiscard]] vertex_idx num_vertices() const { return static_cast(vertices_.size()); } + + /** + * @brief Checks if the graph is empty (no vertices). + */ + [[nodiscard]] bool empty() const { return vertices_.empty(); } + + /** + * @brief Returns the total number of edges. + */ + [[nodiscard]] vertex_idx num_edges() const { return num_edges_; } + + /** + * @brief Returns the parents (in-neighbors) of a vertex. + * @param v The vertex index. + */ + [[nodiscard]] const std::vector &parents(const vertex_idx v) const { return in_neigbors.at(v); } + + /** + * @brief Returns the children (out-neighbors) of a vertex. + * @param v The vertex index. + */ + [[nodiscard]] const std::vector &children(const vertex_idx v) const { return out_neigbors.at(v); } + + /** + * @brief Returns the in-degree of a vertex. + * @param v The vertex index. + */ + [[nodiscard]] vertex_idx in_degree(const vertex_idx v) const { return static_cast(in_neigbors.at(v).size()); } + + /** + * @brief Returns the out-degree of a vertex. + * @param v The vertex index. + */ + [[nodiscard]] vertex_idx out_degree(const vertex_idx v) const { return static_cast(out_neigbors.at(v).size()); } + + [[nodiscard]] vertex_work_weight_type vertex_work_weight(const vertex_idx v) const { return vertices_.at(v).work_weight; } + + [[nodiscard]] vertex_comm_weight_type vertex_comm_weight(const vertex_idx v) const { return vertices_.at(v).comm_weight; } + + [[nodiscard]] vertex_mem_weight_type vertex_mem_weight(const vertex_idx v) const { return vertices_.at(v).mem_weight; } + + [[nodiscard]] vertex_type_type vertex_type(const vertex_idx v) const { return vertices_.at(v).vertex_type; } + + [[nodiscard]] vertex_type_type num_vertex_types() const { return num_vertex_types_; } + + [[nodiscard]] const v_impl &get_vertex_impl(const vertex_idx v) const { return vertices_.at(v); } + + /** + * @brief Adds a new isolated vertex to the graph. + * + * @param work_weight Computational work weight. + * @param comm_weight Communication weight. + * @param mem_weight Memory weight. + * @param vertex_type Type of the vertex. + * @return The index of the newly added vertex. + */ + vertex_idx add_vertex(const vertex_work_weight_type work_weight, const vertex_comm_weight_type comm_weight, + const vertex_mem_weight_type mem_weight, const vertex_type_type vertex_type = 0) { vertices_.emplace_back(vertices_.size(), work_weight, comm_weight, mem_weight, vertex_type); out_neigbors.push_back({}); @@ -153,36 +206,42 @@ class computational_dag_vector_impl { return vertices_.back().id; } - inline void set_vertex_work_weight(vertex_idx v, vertex_work_weight_type work_weight) { - vertices_[v].work_weight = work_weight; + void set_vertex_work_weight(const vertex_idx v, const vertex_work_weight_type work_weight) { + vertices_.at(v).work_weight = work_weight; } - inline void set_vertex_comm_weight(vertex_idx v, vertex_comm_weight_type comm_weight) { - vertices_[v].comm_weight = comm_weight; + void set_vertex_comm_weight(const vertex_idx v, const vertex_comm_weight_type comm_weight) { + vertices_.at(v).comm_weight = comm_weight; } - inline void set_vertex_mem_weight(vertex_idx v, vertex_mem_weight_type mem_weight) { - vertices_[v].mem_weight = mem_weight; + void set_vertex_mem_weight(const vertex_idx v, const vertex_mem_weight_type mem_weight) { + vertices_.at(v).mem_weight = mem_weight; } - inline void set_vertex_type(vertex_idx v, vertex_type_type vertex_type) { - vertices_[v].vertex_type = vertex_type; + void set_vertex_type(const vertex_idx v, const vertex_type_type vertex_type) { + vertices_.at(v).vertex_type = vertex_type; num_vertex_types_ = std::max(num_vertex_types_, vertex_type + 1); } - bool add_edge(vertex_idx source, vertex_idx target) { + /** + * @brief Adds a directed edge between two vertices. + * + * @param source The source vertex index. + * @param target The target vertex index. + * @return True if the edge was added, false if it already exists or vertices are invalid. + */ + bool add_edge(const vertex_idx source, const vertex_idx target) { if (source >= static_cast(vertices_.size()) || target >= static_cast(vertices_.size()) || source == target) return false; - for (const vertex_idx v_idx : out_neigbors[source]) { - if (v_idx == target) { - return false; - } + const auto &out = out_neigbors.at(source); + if (std::find(out.begin(), out.end(), target) != out.end()) { + return false; } - out_neigbors[source].push_back(target); - in_neigbors[target].push_back(source); + out_neigbors.at(source).push_back(target); + in_neigbors.at(target).push_back(source); num_edges_++; return true; @@ -198,8 +257,14 @@ class computational_dag_vector_impl { unsigned num_vertex_types_ = 0; }; -// default template parameters +/** + * @brief Default implementation of a computational DAG using unsigned integer weights. + */ using computational_dag_vector_impl_def_t = computational_dag_vector_impl; + +/** + * @brief Default implementation of a computational DAG using signed integer weights. + */ using computational_dag_vector_impl_def_int_t = computational_dag_vector_impl; diff --git a/include/osp/graph_implementations/adj_list_impl/dag_vector_adapter.hpp b/include/osp/graph_implementations/adj_list_impl/dag_vector_adapter.hpp index 124c609f..1deadcee 100644 --- a/include/osp/graph_implementations/adj_list_impl/dag_vector_adapter.hpp +++ b/include/osp/graph_implementations/adj_list_impl/dag_vector_adapter.hpp @@ -17,70 +17,45 @@ limitations under the License. */ #pragma once -#include "computational_dag_vector_impl.hpp" +#include "cdag_vertex_impl.hpp" #include "osp/concepts/computational_dag_concept.hpp" -#include "osp/graph_algorithms/computational_dag_construction_util.hpp" #include "osp/graph_implementations/integral_range.hpp" +#include "vector_cast_view.hpp" #include namespace osp { -template -class vector_cast_view { - - using iter = typename std::vector::const_iterator; - const std::vector &vec; - struct cast_iterator { - iter current_edge; - - public: - using iterator_category = std::forward_iterator_tag; - using value_type = to_t; - using difference_type = std::ptrdiff_t; - using pointer = const value_type *; - using reference = const value_type &; - - cast_iterator() = default; - cast_iterator(const cast_iterator &other) : current_edge(other.current_edge) {} - - cast_iterator &operator=(const cast_iterator &other) { - if (this != &other) { - current_edge = other.current_edge; - } - return *this; - } - - cast_iterator(iter current_edge_) : current_edge(current_edge_) {} - - value_type operator*() const { return static_cast(*current_edge); } - - // Prefix increment - cast_iterator &operator++() { - current_edge++; - return *this; - } - - // Postfix increment - cast_iterator operator++(int) { - cast_iterator tmp = *this; - ++(*this); - return tmp; - } - - inline bool operator==(const cast_iterator &other) const { return current_edge == other.current_edge; } - inline bool operator!=(const cast_iterator &other) const { return current_edge != other.current_edge; } - }; - - public: - vector_cast_view(const std::vector &vec_) : vec(vec_) {} - - auto begin() const { return cast_iterator(vec.begin()); } - - auto end() const { return cast_iterator(vec.end()); } - - auto size() const { return vec.size(); } -}; - +/** + * @brief Adapter to view a pair of adjacency lists (out-neighbors and in-neighbors) as a computational DAG. + * + * This class adapts raw adjacency lists (vectors of vectors) into a graph interface compatible with + * the OSP computational DAG concepts. It stores pointers to the external adjacency lists, so the + * lifetime of these lists must exceed the lifetime of this adapter. + * + * This class satisfies the following concepts: + * - `is_computational_dag_typed_vertices` + * - `is_directed_graph` + * - `has_vertex_weights` + * - `is_directed_graph_edge_desc` + * + * @tparam v_impl The vertex implementation type. This type must satisfy the following requirements: + * - It must define the following member types: + * - `vertex_idx_type`: The type used for vertex indices (e.g., `size_t`). + * - `work_weight_type`: The type used for computational work weights. + * - `comm_weight_type`: The type used for communication weights. + * - `mem_weight_type`: The type used for memory weights. + * - `cdag_vertex_type_type`: The type used for vertex types. + * - It must have the following public data members: + * - `id`: Of type `vertex_idx_type`. + * - `work_weight`: Of type `work_weight_type`. + * - `comm_weight`: Of type `comm_weight_type`. + * - `mem_weight`: Of type `mem_weight_type`. + * - `vertex_type`: Of type `cdag_vertex_type_type`. + * - It must be constructible with the signature: + * `v_impl(vertex_idx_type id, work_weight_type work_weight, comm_weight_type comm_weight, mem_weight_type mem_weight, cdag_vertex_type_type vertex_type)` + * + * @tparam index_t The type used for vertex indices in the adjacency lists. + */ template class dag_vector_adapter { @@ -94,86 +69,124 @@ class dag_vector_adapter { dag_vector_adapter() = default; - dag_vector_adapter(std::vector> &out_neigbors_, - std::vector> &in_neigbors_) - : vertices_(out_neigbors_.size()), out_neigbors(&out_neigbors_), in_neigbors(&in_neigbors_), num_edges_(0), - num_vertex_types_(1) { - + /** + * @brief Constructs a dag_vector_adapter from adjacency lists. + * + * @param out_neigbors_ Vector of vectors representing out-neighbors for each vertex. + * @param in_neigbors_ Vector of vectors representing in-neighbors for each vertex. + * + * @warning The adapter stores pointers to these vectors. They must remain valid for the lifetime of the adapter. + */ + dag_vector_adapter(const std::vector> &out_neigbors_, + const std::vector> &in_neigbors_) : vertices_(out_neigbors_.size()), out_neigbors(&out_neigbors_), in_neigbors(&in_neigbors_), num_edges_(0), num_vertex_types_(1) { for (vertex_idx i = 0; i < static_cast(out_neigbors_.size()); ++i) { - vertices_[i].id = i; - num_edges_ += out_neigbors_[i].size(); + vertices_.at(i).id = i; + num_edges_ += out_neigbors_.at(i).size(); } } dag_vector_adapter(const dag_vector_adapter &other) = default; dag_vector_adapter &operator=(const dag_vector_adapter &other) = default; - virtual ~dag_vector_adapter() = default; + dag_vector_adapter(dag_vector_adapter &&other) noexcept = default; + dag_vector_adapter &operator=(dag_vector_adapter &&other) noexcept = default; - inline void set_in_out_neighbors(std::vector> &in_neigbors_, std::vector> &out_neigbors_) { + virtual ~dag_vector_adapter() = default; + /** + * @brief Re-initializes the adapter with new adjacency lists. + * + * @param in_neigbors_ New in-neighbors adjacency list. + * @param out_neigbors_ New out-neighbors adjacency list. + */ + void set_in_out_neighbors(const std::vector> &in_neigbors_, const std::vector> &out_neigbors_) { out_neigbors = &out_neigbors_; in_neigbors = &in_neigbors_; vertices_.resize(out_neigbors->size()); num_edges_ = 0; - for (vertex_idx i = 0; i < out_neigbors_.size(); ++i) { - vertices_[i].id = i; - num_edges_ += out_neigbors_[i].size(); + for (vertex_idx i = 0; i < static_cast(out_neigbors->size()); ++i) { + vertices_.at(i).id = i; + num_edges_ += out_neigbors->at(i).size(); } num_vertex_types_ = 1; } - inline auto vertices() const { return integral_range(static_cast(vertices_.size())); } + /** + * @brief Returns a range of all vertex indices. + */ + [[nodiscard]] auto vertices() const { return integral_range(static_cast(vertices_.size())); } - inline vertex_idx num_vertices() const { return static_cast(vertices_.size()); } + /** + * @brief Returns the total number of vertices. + */ + [[nodiscard]] vertex_idx num_vertices() const { return static_cast(vertices_.size()); } - inline vertex_idx num_edges() const { return static_cast(num_edges_); } + /** + * @brief Returns the total number of edges. + */ + [[nodiscard]] vertex_idx num_edges() const { return static_cast(num_edges_); } - inline auto parents(const vertex_idx v) const { return vector_cast_view(in_neigbors->at(v)); } + /** + * @brief Returns a view of the parents (in-neighbors) of a vertex. + * @param v The vertex index. + */ + [[nodiscard]] auto parents(const vertex_idx v) const { return vector_cast_view(in_neigbors->at(v)); } - inline auto children(const vertex_idx v) const { return vector_cast_view(out_neigbors->at(v)); } + /** + * @brief Returns a view of the children (out-neighbors) of a vertex. + * @param v The vertex index. + */ + [[nodiscard]] auto children(const vertex_idx v) const { return vector_cast_view(out_neigbors->at(v)); } - inline vertex_idx in_degree(const vertex_idx v) const { return static_cast(in_neigbors->at(v).size()); } + /** + * @brief Returns the in-degree of a vertex. + * @param v The vertex index. + */ + [[nodiscard]] vertex_idx in_degree(const vertex_idx v) const { return static_cast(in_neigbors->at(v).size()); } - inline vertex_idx out_degree(const vertex_idx v) const { return static_cast(out_neigbors->at(v).size()); } + /** + * @brief Returns the out-degree of a vertex. + * @param v The vertex index. + */ + [[nodiscard]] vertex_idx out_degree(const vertex_idx v) const { return static_cast(out_neigbors->at(v).size()); } - inline vertex_work_weight_type vertex_work_weight(const vertex_idx v) const { return vertices_[v].work_weight; } + [[nodiscard]] vertex_work_weight_type vertex_work_weight(const vertex_idx v) const { return vertices_.at(v).work_weight; } - inline vertex_comm_weight_type vertex_comm_weight(const vertex_idx v) const { return vertices_[v].comm_weight; } + [[nodiscard]] vertex_comm_weight_type vertex_comm_weight(const vertex_idx v) const { return vertices_.at(v).comm_weight; } - inline vertex_mem_weight_type vertex_mem_weight(const vertex_idx v) const { return vertices_[v].mem_weight; } + [[nodiscard]] vertex_mem_weight_type vertex_mem_weight(const vertex_idx v) const { return vertices_.at(v).mem_weight; } - inline vertex_type_type vertex_type(const vertex_idx v) const { return vertices_[v].vertex_type; } + [[nodiscard]] vertex_type_type vertex_type(const vertex_idx v) const { return vertices_.at(v).vertex_type; } - inline vertex_type_type num_vertex_types() const { return num_vertex_types_; } + [[nodiscard]] vertex_type_type num_vertex_types() const { return num_vertex_types_; } - inline const v_impl &get_vertex_impl(const vertex_idx v) const { return vertices_[v]; } + [[nodiscard]] const v_impl &get_vertex_impl(const vertex_idx v) const { return vertices_.at(v); } - inline void set_vertex_work_weight(vertex_idx v, vertex_work_weight_type work_weight) { - vertices_[v].work_weight = work_weight; + void set_vertex_work_weight(const vertex_idx v, const vertex_work_weight_type work_weight) { + vertices_.at(v).work_weight = work_weight; } - inline void set_vertex_comm_weight(vertex_idx v, vertex_comm_weight_type comm_weight) { - vertices_[v].comm_weight = comm_weight; + void set_vertex_comm_weight(const vertex_idx v, const vertex_comm_weight_type comm_weight) { + vertices_.at(v).comm_weight = comm_weight; } - inline void set_vertex_mem_weight(vertex_idx v, vertex_mem_weight_type mem_weight) { - vertices_[v].mem_weight = mem_weight; + void set_vertex_mem_weight(const vertex_idx v, const vertex_mem_weight_type mem_weight) { + vertices_.at(v).mem_weight = mem_weight; } - inline void set_vertex_type(vertex_idx v, vertex_type_type vertex_type) { - vertices_[v].vertex_type = vertex_type; + void set_vertex_type(const vertex_idx v, const vertex_type_type vertex_type) { + vertices_.at(v).vertex_type = vertex_type; num_vertex_types_ = std::max(num_vertex_types_, vertex_type + 1); } private: std::vector vertices_; - std::vector> *out_neigbors; - std::vector> *in_neigbors; + const std::vector> *out_neigbors; + const std::vector> *in_neigbors; std::size_t num_edges_ = 0; unsigned num_vertex_types_ = 0; @@ -181,15 +194,15 @@ class dag_vector_adapter { static_assert(is_directed_graph_edge_desc_v>, - "computational_dag_edge_idx_vector_impl must satisfy the directed_graph_edge_desc concept"); + "dag_vector_adapter must satisfy the directed_graph_edge_desc concept"); static_assert(has_vertex_weights_v>, - "computational_dag_vector_impl must satisfy the has_vertex_weights concept"); + "dag_vector_adapter must satisfy the has_vertex_weights concept"); static_assert(is_directed_graph_v>, - "computational_dag_vector_impl must satisfy the directed_graph concept"); + "dag_vector_adapter must satisfy the directed_graph concept"); static_assert(is_computational_dag_typed_vertices_v>, - "computational_dag_vector_impl must satisfy the is_computation_dag concept"); + "dag_vector_adapter must satisfy the is_computation_dag concept"); } // namespace osp \ No newline at end of file diff --git a/include/osp/graph_implementations/adj_list_impl/vector_cast_view.hpp b/include/osp/graph_implementations/adj_list_impl/vector_cast_view.hpp new file mode 100644 index 00000000..e8fbe586 --- /dev/null +++ b/include/osp/graph_implementations/adj_list_impl/vector_cast_view.hpp @@ -0,0 +1,147 @@ +/* +Copyright 2024 Huawei Technologies Co., Ltd. + +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. + +@author Toni Boehnlein, Benjamin Lozes, Pal Andras Papp, Raphael S. Steiner +*/ +#pragma once + +#include + +namespace osp { + +/** + * @brief A view that casts elements of a vector to a different type upon access. + * + * This class provides a lightweight view over a std::vector, exposing its elements + * as type to_t. It is useful for adapting interfaces that expect a range of a specific type + * without copying the underlying data. + * + * @tparam from_t The original type of elements in the vector. + * @tparam to_t The target type to cast elements to. + */ +template +class vector_cast_view { + + using iter = typename std::vector::const_iterator; + const std::vector &vec; + + /** + * @brief Iterator for vector_cast_view. + * + * This iterator wraps the underlying vector iterator and performs a static_cast + * on dereference. It satisfies the RandomAccessIterator concept. + */ + struct cast_iterator { + using iterator_category = std::random_access_iterator_tag; + using value_type = to_t; + using difference_type = std::ptrdiff_t; + using pointer = const value_type *; + using reference = const value_type &; + + iter current_edge; + + cast_iterator() = default; + explicit cast_iterator(iter current_edge_) : current_edge(current_edge_) {} + + value_type operator*() const { return static_cast(*current_edge); } + + cast_iterator &operator++() { + ++current_edge; + return *this; + } + + cast_iterator operator++(int) { + cast_iterator tmp = *this; + ++(*this); + return tmp; + } + + cast_iterator &operator--() { + --current_edge; + return *this; + } + + cast_iterator operator--(int) { + cast_iterator tmp = *this; + --(*this); + return tmp; + } + + cast_iterator &operator+=(difference_type n) { + current_edge += n; + return *this; + } + + cast_iterator &operator-=(difference_type n) { + current_edge -= n; + return *this; + } + + cast_iterator operator+(difference_type n) const { return cast_iterator(current_edge + n); } + + cast_iterator operator-(difference_type n) const { return cast_iterator(current_edge - n); } + + difference_type operator-(const cast_iterator &other) const { return current_edge - other.current_edge; } + + bool operator==(const cast_iterator &other) const { return current_edge == other.current_edge; } + bool operator!=(const cast_iterator &other) const { return current_edge != other.current_edge; } + bool operator<(const cast_iterator &other) const { return current_edge < other.current_edge; } + bool operator>(const cast_iterator &other) const { return current_edge > other.current_edge; } + bool operator<=(const cast_iterator &other) const { return current_edge <= other.current_edge; } + bool operator>=(const cast_iterator &other) const { return current_edge >= other.current_edge; } + }; + + public: + /** + * @brief Constructs a vector_cast_view from a vector. + * + * @param vec_ The vector to view. The view holds a reference to this vector, + * so the vector must outlive the view. + */ + explicit vector_cast_view(const std::vector &vec_) : vec(vec_) {} + + /** + * @brief Returns an iterator to the beginning of the view. + * @return An iterator to the first element. + */ + [[nodiscard]] auto begin() const { return cast_iterator(vec.begin()); } + + /** + * @brief Returns an iterator to the end of the view. + * @return An iterator to the element following the last element. + */ + [[nodiscard]] auto end() const { return cast_iterator(vec.end()); } + + /** + * @brief Returns the number of elements in the view. + * @return The number of elements. + */ + [[nodiscard]] auto size() const { return vec.size(); } + + /** + * @brief Checks if the view is empty. + * @return True if the view is empty, false otherwise. + */ + [[nodiscard]] bool empty() const { return vec.empty(); } + + /** + * @brief Accesses the element at the specified index. + * @param i The index of the element to access. + * @return The element at index i, cast to to_t. + */ + [[nodiscard]] auto operator[](std::size_t i) const { return static_cast(vec.at(i)); } +}; + +} // namespace osp \ No newline at end of file diff --git a/include/osp/graph_implementations/boost_graphs/boost_graph.hpp b/include/osp/graph_implementations/boost_graphs/boost_graph.hpp index 52557fb4..35360fdd 100644 --- a/include/osp/graph_implementations/boost_graphs/boost_graph.hpp +++ b/include/osp/graph_implementations/boost_graphs/boost_graph.hpp @@ -208,7 +208,7 @@ class boost_graph { graph.m_vertices.reserve(other.num_vertices()); - osp::construct_computational_dag(other, *this); + osp::constructComputationalDag(other, *this); } inline const boost_graph_impl_t &get_boost_graph() const { return graph; } diff --git a/tests/coarser.cpp b/tests/coarser.cpp index be189ae8..e4bd92c3 100644 --- a/tests/coarser.cpp +++ b/tests/coarser.cpp @@ -35,6 +35,7 @@ limitations under the License. #include "osp/coarser/SquashA/SquashAMul.hpp" #include "osp/coarser/top_order/top_order_coarser.hpp" #include "osp/graph_implementations/adj_list_impl/computational_dag_edge_idx_vector_impl.hpp" +#include "osp/graph_implementations/adj_list_impl/computational_dag_vector_impl.hpp" #include "osp/graph_implementations/adj_list_impl/compact_sparse_graph.hpp" #include "osp/graph_implementations/adj_list_impl/compact_sparse_graph_edge_desc.hpp" #include "osp/auxiliary/io/arch_file_reader.hpp"