From c1b17cb5c1842def1d6ec726ba5127904878d651 Mon Sep 17 00:00:00 2001 From: Tobias Heuer Date: Wed, 26 Jul 2023 15:33:53 +0200 Subject: [PATCH] construction algorithm for fixed vertex free subhypergraph --- mt-kahypar/partition/CMakeLists.txt | 3 +- .../partition/fixed_vertices/CMakeLists.txt | 6 + .../fixed_vertices/fixed_vertex_removal.cpp | 119 ++++++++++++++++ .../fixed_vertices/fixed_vertex_removal.h | 47 +++++++ tests/datastructures/CMakeLists.txt | 3 +- tests/partition/CMakeLists.txt | 1 + tests/partition/fixed_vertices/CMakeLists.txt | 3 + .../fixed_vertex_removal_test.cc | 127 ++++++++++++++++++ .../fixed_vertex_support_test.cc | 0 9 files changed, 306 insertions(+), 3 deletions(-) create mode 100644 mt-kahypar/partition/fixed_vertices/CMakeLists.txt create mode 100644 mt-kahypar/partition/fixed_vertices/fixed_vertex_removal.cpp create mode 100644 mt-kahypar/partition/fixed_vertices/fixed_vertex_removal.h create mode 100644 tests/partition/fixed_vertices/CMakeLists.txt create mode 100644 tests/partition/fixed_vertices/fixed_vertex_removal_test.cc rename tests/{datastructures => partition/fixed_vertices}/fixed_vertex_support_test.cc (100%) diff --git a/mt-kahypar/partition/CMakeLists.txt b/mt-kahypar/partition/CMakeLists.txt index 8c92b4605..4d588cfb6 100644 --- a/mt-kahypar/partition/CMakeLists.txt +++ b/mt-kahypar/partition/CMakeLists.txt @@ -1,5 +1,6 @@ -add_subdirectory(preprocessing/) +add_subdirectory(preprocessing) add_subdirectory(coarsening) +add_subdirectory(fixed_vertices) add_subdirectory(refinement) add_subdirectory(initial_partitioning) add_subdirectory(mapping) diff --git a/mt-kahypar/partition/fixed_vertices/CMakeLists.txt b/mt-kahypar/partition/fixed_vertices/CMakeLists.txt new file mode 100644 index 000000000..3b576106c --- /dev/null +++ b/mt-kahypar/partition/fixed_vertices/CMakeLists.txt @@ -0,0 +1,6 @@ +set(FixedVertexSources + fixed_vertex_removal.cpp) + +foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) + target_sources(${modtarget} PRIVATE ${FixedVertexSources}) +endforeach() \ No newline at end of file diff --git a/mt-kahypar/partition/fixed_vertices/fixed_vertex_removal.cpp b/mt-kahypar/partition/fixed_vertices/fixed_vertex_removal.cpp new file mode 100644 index 000000000..d78cf3faf --- /dev/null +++ b/mt-kahypar/partition/fixed_vertices/fixed_vertex_removal.cpp @@ -0,0 +1,119 @@ +/******************************************************************************* + * MIT License + * + * This file is part of Mt-KaHyPar. + * + * Copyright (C) 2023 Tobias Heuer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ + +#include "mt-kahypar/partition/fixed_vertices/fixed_vertex_removal.h" + +#include "tbb/parallel_invoke.h" + +#include "mt-kahypar/definitions.h" +#include "mt-kahypar/parallel/parallel_prefix_sum.h" + +namespace mt_kahypar { + +template +ExtractedHypergraph FixedVertexRemoval::remove(const Hypergraph& hypergraph) { + ExtractedHypergraph extracted_hg; + vec& hn_mapping = extracted_hg.hn_mapping; + vec he_mapping; + + parallel::TBBPrefixSum hn_mapping_prefix_sum(hn_mapping); + parallel::TBBPrefixSum he_mapping_prefix_sum(he_mapping); + tbb::parallel_invoke([&] { + hn_mapping.assign(hypergraph.initialNumNodes() + 1, 0); + hypergraph.doParallelForAllNodes([&](const HypernodeID hn) { + if ( !hypergraph.isFixed(hn) ) { + // Mark free vertices as valid + hn_mapping[hn + 1] = 1; + } + }); + // Prefix sums computes mapping of the nodes of the input hypergraph to the nodes + // of the fixed vertex free subhypergraph + tbb::parallel_scan(tbb::blocked_range(UL(0), UL(hypergraph.initialNumNodes() + 1)), hn_mapping_prefix_sum); + }, [&] { + he_mapping.assign(hypergraph.initialNumEdges() + 1, 0); + hypergraph.doParallelForAllEdges([&](const HypernodeID he) { + size_t edge_size = 0; + for ( const HypernodeID& pin : hypergraph.pins(he) ) { + if ( !hypergraph.isFixed(pin) ) { + ++edge_size; + } + } + if ( edge_size > 1 ) { + // Mark edges with more than one pin as valid + he_mapping[he + 1] = 1; + } + }); + // Prefix sums computes mapping of the edges of the input hypergraph to the edges + // of the fixed vertex free subhypergraph + tbb::parallel_scan(tbb::blocked_range(UL(0), UL(hypergraph.initialNumEdges() + 1)), he_mapping_prefix_sum); + }); + // Remove sentinel + hn_mapping.pop_back(); + + const HypernodeID num_nodes = hn_mapping_prefix_sum.total_sum(); + const HyperedgeID num_edges = he_mapping_prefix_sum.total_sum(); + HyperedgeVector edge_vector; + vec hyperedge_weights; + vec hypernode_weights; + tbb::parallel_invoke([&] { + tbb::parallel_invoke([&] { + edge_vector.resize(num_edges); + }, [&] { + hyperedge_weights.resize(num_edges); + }); + + // Construct edge vector of the fixed vertex free subhypergraph + hypergraph.doParallelForAllEdges([&](const HyperedgeID& he) { + if ( he_mapping_prefix_sum.value(he + 1) ) { + // Hyperedge contains more than one pin in fixed vertex free subhypergraph + const HyperedgeID e = he_mapping[he]; + hyperedge_weights[e] = hypergraph.edgeWeight(he); + for ( const HypernodeID& pin : hypergraph.pins(he) ) { + if ( !hypergraph.isFixed(pin) ) { + edge_vector[e].push_back(hn_mapping[pin]); + } + } + } + }); + }, [&] { + hypernode_weights.resize(num_nodes); + hypergraph.doParallelForAllNodes([&](const HypernodeID& hn) { + if ( !hypergraph.isFixed(hn) ) { + hypernode_weights[hn_mapping[hn]] = hypergraph.nodeWeight(hn); + } else { + hn_mapping[hn] = kInvalidHypernode; + } + }); + }); + + // Construct fixed vertex free subhypergraph + extracted_hg.hg = Factory::construct(num_nodes, num_edges, + edge_vector, hyperedge_weights.data(), hypernode_weights.data(), true); + return extracted_hg; +} + +INSTANTIATE_CLASS_WITH_HYPERGRAPHS(FixedVertexRemoval) +} diff --git a/mt-kahypar/partition/fixed_vertices/fixed_vertex_removal.h b/mt-kahypar/partition/fixed_vertices/fixed_vertex_removal.h new file mode 100644 index 000000000..1ec689b82 --- /dev/null +++ b/mt-kahypar/partition/fixed_vertices/fixed_vertex_removal.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * MIT License + * + * This file is part of Mt-KaHyPar. + * + * Copyright (C) 2023 Tobias Heuer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include + +#include "mt-kahypar/datastructures/hypergraph_common.h" +#include "mt-kahypar/parallel/stl/scalable_vector.h" + +namespace mt_kahypar { + +template +class FixedVertexRemoval { + + using Factory = typename Hypergraph::Factory; + using HyperedgeVector = vec>; + + public: + static ExtractedHypergraph remove(const Hypergraph& hypergraph); + +}; + +} // namespace mt_kahypar diff --git a/tests/datastructures/CMakeLists.txt b/tests/datastructures/CMakeLists.txt index 3435337fe..10d764309 100644 --- a/tests/datastructures/CMakeLists.txt +++ b/tests/datastructures/CMakeLists.txt @@ -10,8 +10,7 @@ target_sources(mt_kahypar_tests PRIVATE array_test.cc sparse_map_test.cc pin_count_in_part_test.cc - static_bitset_test.cc - fixed_vertex_support_test.cc) + static_bitset_test.cc) if ( KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES ) target_sources(mt_kahypar_tests PRIVATE diff --git a/tests/partition/CMakeLists.txt b/tests/partition/CMakeLists.txt index 28006907b..b7b39f15a 100644 --- a/tests/partition/CMakeLists.txt +++ b/tests/partition/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(preprocessing) add_subdirectory(mapping) add_subdirectory(coarsening) +add_subdirectory(fixed_vertices) add_subdirectory(initial_partitioning) add_subdirectory(refinement) add_subdirectory(determinism) \ No newline at end of file diff --git a/tests/partition/fixed_vertices/CMakeLists.txt b/tests/partition/fixed_vertices/CMakeLists.txt new file mode 100644 index 000000000..04779d850 --- /dev/null +++ b/tests/partition/fixed_vertices/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(mt_kahypar_tests PRIVATE + fixed_vertex_support_test.cc + fixed_vertex_removal_test.cc) \ No newline at end of file diff --git a/tests/partition/fixed_vertices/fixed_vertex_removal_test.cc b/tests/partition/fixed_vertices/fixed_vertex_removal_test.cc new file mode 100644 index 000000000..2e4de1784 --- /dev/null +++ b/tests/partition/fixed_vertices/fixed_vertex_removal_test.cc @@ -0,0 +1,127 @@ +/******************************************************************************* + * MIT License + * + * This file is part of Mt-KaHyPar. + * + * Copyright (C) 2023 Tobias Heuer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ + + + +#include "gmock/gmock.h" +#include "tbb/task_group.h" + +#include "mt-kahypar/datastructures/static_hypergraph.h" +#include "mt-kahypar/datastructures/static_hypergraph_factory.h" +#include "mt-kahypar/datastructures/fixed_vertex_support.h" +#include "mt-kahypar/partition/fixed_vertices/fixed_vertex_removal.h" + +using ::testing::Test; + +namespace mt_kahypar { +namespace ds { + + +class AFixedVertexRemoval : public Test { + + public: + using Hypergraph = StaticHypergraph; + using Factory = typename Hypergraph::Factory; + + AFixedVertexRemoval() : + hypergraph(Factory::construct( + 7 , 4, { {0, 2}, {0, 1, 3, 4}, {3, 4, 6}, {2, 5, 6} })) { } + + void addFixedVertices(const PartitionID k, + const vec& fixed_vertex_blocks) { + FixedVertexSupport fixed_vertices(hypergraph.initialNumNodes(), k); + fixed_vertices.setHypergraph(&hypergraph); + for ( const HypernodeID& hn : hypergraph.nodes() ) { + if ( fixed_vertex_blocks[hn] != kInvalidPartition ) { + fixed_vertices.fixToBlock(hn, fixed_vertex_blocks[hn]); + } + } + hypergraph.addFixedVertexSupport(std::move(fixed_vertices)); + } + + void verifyFixedVertexFreeSubhypergraph(const Hypergraph& hypergraph, + const vec& hn_mapping, + const HypernodeID expected_num_nodes, + const vec>& expected_pins) { + const HyperedgeID expected_num_edges = expected_pins.size(); + ASSERT_EQ(expected_num_nodes, hypergraph.initialNumNodes()); + ASSERT_EQ(expected_num_edges, hypergraph.initialNumEdges()); + + vec to_original(expected_num_nodes, 0); + for ( size_t i = 0; i < hn_mapping.size(); ++i ) { + if ( hn_mapping[i] != kInvalidHypernode ) { + to_original[hn_mapping[i]] = i; + } + } + + for ( const HyperedgeID& he : hypergraph.edges() ) { + ASSERT_EQ(UL(hypergraph.edgeSize(he)), expected_pins[he].size()); + size_t i = 0; + for ( const HypernodeID& pin : hypergraph.pins(he) ) { + ASSERT_EQ(expected_pins[he][i++], to_original[pin]); + } + } + } + + Hypergraph hypergraph; +}; + + +TEST_F(AFixedVertexRemoval, ConstructFixedVertexFreeSubhypergraph1) { + addFixedVertices(3, { kInvalidPartition, kInvalidPartition, 0, kInvalidPartition, 1, kInvalidPartition, 2 }); + ExtractedHypergraph extracted_hg = FixedVertexRemoval::remove(hypergraph); + verifyFixedVertexFreeSubhypergraph(extracted_hg.hg, extracted_hg.hn_mapping, 4, { { 0, 1, 3 } }); +} + +TEST_F(AFixedVertexRemoval, ConstructFixedVertexFreeSubhypergraph2) { + addFixedVertices(3, { 0, kInvalidPartition, kInvalidPartition, kInvalidPartition, kInvalidPartition, kInvalidPartition, 2 }); + ExtractedHypergraph extracted_hg = FixedVertexRemoval::remove(hypergraph); + verifyFixedVertexFreeSubhypergraph(extracted_hg.hg, extracted_hg.hn_mapping, + 5, { { 1, 3, 4 }, { 3, 4 }, { 2, 5 } }); +} + +TEST_F(AFixedVertexRemoval, ConstructFixedVertexFreeSubhypergraph3) { + addFixedVertices(3, { 0, 1, 2, kInvalidPartition, kInvalidPartition, 2, 2 }); + ExtractedHypergraph extracted_hg = FixedVertexRemoval::remove(hypergraph); + verifyFixedVertexFreeSubhypergraph(extracted_hg.hg, extracted_hg.hn_mapping, + 2, { { 3, 4 }, { 3, 4 } }); +} + +TEST_F(AFixedVertexRemoval, ConstructFixedVertexFreeSubhypergraph4) { + addFixedVertices(3, { kInvalidPartition, 1, kInvalidPartition, 2, 1, kInvalidPartition, 2 }); + ExtractedHypergraph extracted_hg = FixedVertexRemoval::remove(hypergraph); + verifyFixedVertexFreeSubhypergraph(extracted_hg.hg, extracted_hg.hn_mapping, + 3, { { 0, 2 }, { 2, 5 } }); +} + +TEST_F(AFixedVertexRemoval, ConstructFixedVertexFreeSubhypergraph5) { + addFixedVertices(3, { kInvalidPartition, 1, 0, 2, 1, kInvalidPartition, 2 }); + ExtractedHypergraph extracted_hg = FixedVertexRemoval::remove(hypergraph); + verifyFixedVertexFreeSubhypergraph(extracted_hg.hg, extracted_hg.hn_mapping, 2, { }); +} + +} // namespace ds +} // namespace mt_kahypar diff --git a/tests/datastructures/fixed_vertex_support_test.cc b/tests/partition/fixed_vertices/fixed_vertex_support_test.cc similarity index 100% rename from tests/datastructures/fixed_vertex_support_test.cc rename to tests/partition/fixed_vertices/fixed_vertex_support_test.cc