diff --git a/include/osp/graph_algorithms/directed_graph_edge_view.hpp b/include/osp/graph_algorithms/directed_graph_edge_view.hpp index cf2829a5..6af4bd70 100644 --- a/include/osp/graph_algorithms/directed_graph_edge_view.hpp +++ b/include/osp/graph_algorithms/directed_graph_edge_view.hpp @@ -77,12 +77,12 @@ class edge_view { DirectedEdgeIterator &operator=(const DirectedEdgeIterator &other) = default; DirectedEdgeIterator &operator=(DirectedEdgeIterator &&other) noexcept = default; - explicit DirectedEdgeIterator(const Graph_t &graph) : graph_(&graph), currentVertex_(0), currentEdgeIdx_(0) { + explicit DirectedEdgeIterator(const Graph_t &graph1) : graph_(&graph1), currentVertex_(0), currentEdgeIdx_(0) { advanceToValid(); } - DirectedEdgeIterator(const vertex_idx_t edge_idx, const Graph_t &graph) - : graph_(&graph), currentVertex_(0), currentEdgeIdx_(edge_idx) { + DirectedEdgeIterator(const vertex_idx_t edge_idx, const Graph_t &graph1) + : graph_(&graph1), currentVertex_(0), currentEdgeIdx_(edge_idx) { if (currentEdgeIdx_ >= graph_->num_edges()) { currentEdgeIdx_ = graph_->num_edges(); diff --git a/include/osp/graph_algorithms/specialised_graph_algorithms/subgraph_algorithms.hpp b/include/osp/graph_algorithms/specialised_graph_algorithms/subgraph_algorithms.hpp new file mode 100644 index 00000000..5fc40c21 --- /dev/null +++ b/include/osp/graph_algorithms/specialised_graph_algorithms/subgraph_algorithms.hpp @@ -0,0 +1,76 @@ +/* +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 "osp/concepts/graph_traits.hpp" +#include "osp/graph_algorithms/directed_graph_top_sort.hpp" +#include "osp/graph_algorithms/subgraph_algorithms.hpp" +#include "osp/graph_implementations/adj_list_impl/compact_sparse_graph.hpp" + +namespace osp { + +template +std::unordered_map, vertex_idx_t> create_induced_subgraph_map(const Graph_t_in &dag, Compact_Sparse_Graph &dag_out, + const std::vector> &selected_nodes) { + + using Graph_t_out = Compact_Sparse_Graph; + + static_assert(std::is_same_v, vertex_idx_t>, + "Graph_t_in and out must have the same vertex_idx types"); + + const std::vector> topOrder = GetTopOrder(dag); + std::vector> topOrderPosition(topOrder.size()); + for (vertex_idx_t pos = 0; pos < dag.num_vertices(); ++pos) { + topOrderPosition[topOrder[pos]] = pos; + } + + auto topCmp = [&topOrderPosition](const vertex_idx_t &lhs, const vertex_idx_t &rhs) { return topOrderPosition[lhs] < topOrderPosition[rhs]; }; + + std::set, decltype(topCmp)> selectedVerticesOrdered(selected_nodes.begin(), selected_nodes.end(), topCmp); + + std::unordered_map, vertex_idx_t> local_idx; + local_idx.reserve(selected_nodes.size()); + + vertex_idx_t nodeCntr = 0; + for (const auto &node : selectedVerticesOrdered) { + local_idx[node] = nodeCntr++; + } + + std::vector, vertex_idx_t>> edges; + for (const auto &node : selectedVerticesOrdered) { + for (const auto &chld : dag.children(node)) { + if (selectedVerticesOrdered.find(chld) != selectedVerticesOrdered.end()) { + edges.emplace_back(local_idx.at(node), local_idx.at(chld)); + } + } + } + + dag_out = Graph_t_out(nodeCntr, edges); + + for (const auto &[oriVert, outVert] : local_idx) { + dag_out.set_vertex_work_weight(outVert, dag.vertex_work_weight(oriVert)); + dag_out.set_vertex_comm_weight(outVert, dag.vertex_comm_weight(oriVert)); + dag_out.set_vertex_mem_weight(outVert, dag.vertex_mem_weight(oriVert)); + dag_out.set_vertex_type(outVert, dag.vertex_type(oriVert)); + } + + return local_idx; +} + +} // end namespace osp diff --git a/include/osp/graph_algorithms/subgraph_algorithms.hpp b/include/osp/graph_algorithms/subgraph_algorithms.hpp index 193dcaa1..cde8cf72 100644 --- a/include/osp/graph_algorithms/subgraph_algorithms.hpp +++ b/include/osp/graph_algorithms/subgraph_algorithms.hpp @@ -22,6 +22,7 @@ limitations under the License. #include "osp/concepts/directed_graph_concept.hpp" #include #include +#include #include namespace osp { @@ -91,14 +92,12 @@ void create_induced_subgraph(const Graph_t_in &dag, Graph_t_out &dag_out, } } - template void create_induced_subgraph(const Graph_t_in &dag, Graph_t_out &dag_out, const std::vector> &selected_nodes) { return create_induced_subgraph(dag, dag_out, std::set>(selected_nodes.begin(), selected_nodes.end())); } - template bool checkOrderedIsomorphism(const Graph_t &first, const Graph_t &second) { @@ -170,8 +169,6 @@ std::vector create_induced_subgraphs(const Graph_t_in &dag_in, static_assert(is_constructable_cdag_edge_v, "Graph_t_out must satisfy the constructable_cdag_edge concept"); - - unsigned number_of_parts = 0; for (const auto id : partition_IDs) number_of_parts = std::max(number_of_parts, id + 1); @@ -202,7 +199,7 @@ std::vector create_induced_subgraphs(const Graph_t_in &dag_in, if (partition_IDs[node] == partition_IDs[succ]) split_dags[partition_IDs[node]].add_edge(local_idx[node], local_idx[succ], - dag_in.edge_comm_weight(out_edge)); + dag_in.edge_comm_weight(out_edge)); } } } else { @@ -220,7 +217,7 @@ std::vector create_induced_subgraphs(const Graph_t_in &dag_in, template std::unordered_map, vertex_idx_t> create_induced_subgraph_map(const Graph_t_in &dag, Graph_t_out &dag_out, - const std::vector> &selected_nodes) { + const std::vector> &selected_nodes) { static_assert(std::is_same_v, vertex_idx_t>, "Graph_t_in and out must have the same vertex_idx types"); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1e71d449..3579c1a0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -162,6 +162,8 @@ _add_test( maxbsp_converter_and_hc ) _add_test( cost_evaluation ) +_add_test( subgraph ) + ## pebbling ILPs if (COPT_FOUND) diff --git a/tests/subgraph.cpp b/tests/subgraph.cpp new file mode 100644 index 00000000..178c126b --- /dev/null +++ b/tests/subgraph.cpp @@ -0,0 +1,103 @@ +/* +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, Pal Andras Papp, Raphael S. Steiner, Christos Konstantinos Matzoros +*/ + +#define BOOST_TEST_MODULE SubGraphs +#include + +#include "osp/graph_algorithms/specialised_graph_algorithms/subgraph_algorithms.hpp" +#include "osp/graph_implementations/adj_list_impl/cdag_vertex_impl.hpp" +#include "osp/graph_implementations/adj_list_impl/computational_dag_vector_impl.hpp" + +using namespace osp; + +BOOST_AUTO_TEST_CASE(SubGraphCompactSparseGraph) { + const std::vector> edges({{0, 1}, {2, 3}, {6, 10}, {7, 9}, {0, 2}, {4, 6}, {1, 6}, {6, 7}, {5, 6}, {3, 7}, {1, 2}}); + Compact_Sparse_Graph graph(11, edges); + Compact_Sparse_Graph subGraph; + + unsigned cntr = 0; + for (const auto &vert : graph.vertices()) { + graph.set_vertex_work_weight(vert, cntr++); + graph.set_vertex_comm_weight(vert, cntr++); + graph.set_vertex_mem_weight(vert, cntr++); + graph.set_vertex_type(vert, cntr++); + } + + const std::vector>> selectVert({2, 3, 10, 6, 7}); + const auto vertCorrespondence = create_induced_subgraph_map(graph, subGraph, selectVert); + BOOST_CHECK_EQUAL(subGraph.num_vertices(), selectVert.size()); + BOOST_CHECK_EQUAL(subGraph.num_edges(), 4); + + for (const auto &vert : selectVert) { + BOOST_CHECK_LT(vertCorrespondence.at(vert), selectVert.size()); + + for (const auto &otherVert : selectVert) { + if (vertCorrespondence.at(vert) == vertCorrespondence.at(otherVert)) { + BOOST_CHECK_EQUAL(vert, otherVert); + } + } + } + + for (const auto &vert : selectVert) { + BOOST_CHECK_EQUAL(graph.vertex_work_weight(vert), subGraph.vertex_work_weight(vertCorrespondence.at(vert))); + BOOST_CHECK_EQUAL(graph.vertex_comm_weight(vert), subGraph.vertex_comm_weight(vertCorrespondence.at(vert))); + BOOST_CHECK_EQUAL(graph.vertex_mem_weight(vert), subGraph.vertex_mem_weight(vertCorrespondence.at(vert))); + BOOST_CHECK_EQUAL(graph.vertex_type(vert), subGraph.vertex_type(vertCorrespondence.at(vert))); + } +} + +BOOST_AUTO_TEST_CASE(SubGraphDagVectorImpl) { + using v_impl = cdag_vertex_impl; + + computational_dag_vector_impl graph; + computational_dag_vector_impl subGraph; + + const std::size_t numVert = 11; + const std::vector> edges({{0, 1}, {2, 3}, {6, 10}, {7, 9}, {0, 2}, {4, 6}, {1, 6}, {6, 7}, {5, 6}, {3, 7}, {1, 2}}); + + unsigned cntr = 0; + for (std::size_t i = 0U; i < numVert; ++i) { + graph.add_vertex(cntr, cntr + 1U, cntr + 2U, cntr + 3U); + cntr += 4U; + } + for (const auto &[src, tgt] : edges) { + graph.add_edge(src, tgt); + } + + const std::vector>> selectVert({2, 3, 10, 6, 7}); + const auto vertCorrespondence = create_induced_subgraph_map(graph, subGraph, selectVert); + BOOST_CHECK_EQUAL(subGraph.num_vertices(), selectVert.size()); + BOOST_CHECK_EQUAL(subGraph.num_edges(), 4); + + for (const auto &vert : selectVert) { + BOOST_CHECK_LT(vertCorrespondence.at(vert), selectVert.size()); + + for (const auto &otherVert : selectVert) { + if (vertCorrespondence.at(vert) == vertCorrespondence.at(otherVert)) { + BOOST_CHECK_EQUAL(vert, otherVert); + } + } + } + + for (const auto &vert : selectVert) { + BOOST_CHECK_EQUAL(graph.vertex_work_weight(vert), subGraph.vertex_work_weight(vertCorrespondence.at(vert))); + BOOST_CHECK_EQUAL(graph.vertex_comm_weight(vert), subGraph.vertex_comm_weight(vertCorrespondence.at(vert))); + BOOST_CHECK_EQUAL(graph.vertex_mem_weight(vert), subGraph.vertex_mem_weight(vertCorrespondence.at(vert))); + BOOST_CHECK_EQUAL(graph.vertex_type(vert), subGraph.vertex_type(vertCorrespondence.at(vert))); + } +} \ No newline at end of file