From 7986bfe651c9f30fba1a119f94a8dc82de133df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Thu, 3 Jun 2021 22:06:11 +0200 Subject: [PATCH 01/66] unfinished draft implementation of parallel merge style block pair prefix finding --- .../deterministic_label_propagation.cpp | 170 +++++++++++------- .../deterministic_label_propagation.h | 9 + 2 files changed, 110 insertions(+), 69 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 78ae20717..0b9240ad0 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -312,81 +312,58 @@ namespace mt_kahypar { // swap_prefix[index(p1,p2)] stores the first position of moves to revert out of the sequence of moves from p1 to p2 vec swap_prefix(max_key, 0); - vec part_weight_deltas(k, 0); + vec part_weight_deltas(k, 0); tbb::parallel_for(0UL, relevant_block_pairs.size(), [&](size_t bp_index) { // sort both directions by gain (alternative: gain / weight?) - auto[p1, p2] = relevant_block_pairs[bp_index]; - auto comp = [&](const Move& m1, const Move& m2) { - return m1.gain > m2.gain || (m1.gain == m2.gain && m1.node < m2.node); + auto sort_by_gain_and_prefix_sum_node_weights = [&](PartitionID p1, PartitionID p2) { + size_t begin = positions[index(p1, p2)], end = positions[index(p1, p2) + 1]; + auto comp = [&](const Move& m1, const Move& m2) { + return m1.gain > m2.gain || (m1.gain == m2.gain && m1.node < m2.node); + }; + tbb::parallel_sort(sorted_moves.begin() + begin, sorted_moves.begin() + end, comp); + tbb::parallel_for(begin, end, [&](size_t pos) { + cumulative_node_weights[pos] = phg.nodeWeight(sorted_moves[pos].node); + }); + parallel_prefix_sum(cumulative_node_weights.begin() + begin, cumulative_node_weights.begin() + end, + cumulative_node_weights.begin() + begin, std::plus<>(), 0); }; - const auto b = sorted_moves.begin(); - size_t i = positions[index(p1, p2)], i_last = positions[index(p1, p2) + 1], - j = positions[index(p2, p1)], j_last = positions[index(p2, p1) + 1]; - std::sort(b + i, b + i_last, comp); - std::sort(b + j, b + j_last, comp); - - - // get balanced swap prefix - HypernodeWeight budget_p1 = context.partition.max_part_weights[p1] - phg.partWeight(p1), - budget_p2 = context.partition.max_part_weights[p2] - phg.partWeight(p2); - HypernodeWeight slack_p1 = budget_p1 / std::max(1UL, involvements[p1]), - slack_p2 = budget_p2 / std::max(1UL, involvements[p2]); - - int64_t balance = 0; - std::tuple best{0, 0, 0}; - - /* - * this can be parallelized as follows. - * 1. prefix sums of node weights over both move sequences - * 2. pick middle of larger sequence, binary search for its prefix sum in the smaller sequence - * 3. search for prefixes independently in both halves, and pick the better one - * - * in most cases we're expecting to take roughly as many moves as the size of the shorter sequence, from each of the sequences. - * can we bias the search towards that? - */ - - // gain > 0 first. alternate depending on balance - while (i < i_last && sorted_moves[i].gain > 0 && j < j_last && sorted_moves[j].gain > 0) { - if (balance < 0 || (balance == 0 && sorted_moves[i].gain > sorted_moves[j].gain)) { - // perform next move from p1 to p2 - balance += phg.nodeWeight(sorted_moves[i++].node); - } else { - // perform next move from p2 to p1 - balance -= phg.nodeWeight(sorted_moves[j++].node); - } - if (-balance <= slack_p1 && balance <= slack_p2) { - best = {i, j, balance}; - } - } + const auto& bp = relevant_block_pairs[bp_index]; + tbb::parallel_invoke([&] { + sort_by_gain_and_prefix_sum_node_weights(bp.first, bp.second); + }, [&] { + sort_by_gain_and_prefix_sum_node_weights(bp.second, bp.first); + }); + }); - // if one sequence is depleted or gain == 0. only do rebalancing in the other direction - if (j == j_last || sorted_moves[j].gain == 0) { - while (i < i_last && balance <= slack_p2 && (balance < 0 || sorted_moves[i].gain > 0)) { - balance += phg.nodeWeight(sorted_moves[i++].node); - if (-balance <= slack_p1 && balance <= slack_p2) { - best = {i, j, balance}; - } - } - } - if (i == i_last || sorted_moves[i].gain == 0) { - while (j < j_last && -balance <= slack_p1 && (balance > 0 || sorted_moves[j].gain > 0)) { - balance -= phg.nodeWeight(sorted_moves[j++].node); - if (-balance <= slack_p1 && balance <= slack_p2) { - best = {i, j, balance}; - } - } - } + for (const auto& [p1,p2] : relevant_block_pairs) { + HypernodeWeight lb_p1 = (phg.partWeight(p1) + part_weight_deltas[p1]) - context.partition.max_part_weights[p1], + ub_p2 = context.partition.max_part_weights[p2] - (phg.partWeight(p2) + part_weight_deltas[p2]); + + size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], + p2_begin = positions[index(p2, p1)], p2_end = positions[index(p2, p1) + 1]; + + auto balance = [&](size_t p1_ind, size_t p2_ind) { + const auto a = (p1_ind == p1_begin - 1) ? 0 : cumulative_node_weights[p1_ind]; + const auto b = (p2_ind == p2_begin - 1) ? 0 : cumulative_node_weights[p2_ind]; + return a - b; + }; - swap_prefix[index(p1, p2)] = std::get<0>(best); - swap_prefix[index(p2, p1)] = std::get<1>(best); - int64_t best_balance = std::get<2>(best); + LOG << V(p1) << V(p2) << V(p1_begin) << V(p1_end) << V(p2_begin) << V(p2_begin) << (lb_p1) << V(ub_p2); - // balance < 0 --> p1 got more weight, balance > 0 --> p2 got more weight + auto best_prefix = findBestPrefixesRecursive(p1_begin, p1_end, p2_begin, p2_end, + p1_begin - 1, p2_begin - 1, lb_p1, ub_p2); + + + swap_prefix[index(p1, p2)] = best_prefix.first; + swap_prefix[index(p2, p1)] = best_prefix.second; + HypernodeWeight best_balance = balance(best_prefix.first - 1, best_prefix.second - 1); + LOG << V(best_prefix.first) << V(best_prefix.second) << V(best_balance); __atomic_fetch_add(&part_weight_deltas[p1], best_balance, __ATOMIC_RELAXED); __atomic_fetch_sub(&part_weight_deltas[p2], best_balance, __ATOMIC_RELAXED); - }); + } + LOG << "block-pair handling done"; moves.clear(); Gain actual_gain = applyMovesIf(phg, sorted_moves, num_moves, [&](size_t pos) { @@ -418,13 +395,68 @@ namespace mt_kahypar { return actual_gain; } + std::pair DeterministicLabelPropagationRefiner::findBestPrefixesRecursive( + size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, + size_t p1_invalid, size_t p2_invalid, + HypernodeWeight lb_p1, HypernodeWeight ub_p2) + { + auto balance = [&](size_t p1_ind, size_t p2_ind) { + const auto a = (p1_ind == p1_invalid) ? 0 : cumulative_node_weights[p1_ind]; + const auto b = (p2_ind == p2_invalid) ? 0 : cumulative_node_weights[p2_ind]; + return a - b; + }; + + auto is_feasible = [&](size_t p1_ind, size_t p2_ind) { + const HypernodeWeight bal = balance(p1_ind, p2_ind); + return lb_p1 <= bal && bal <= ub_p2; + }; + + const size_t n_p1 = p1_end - p1_begin, n_p2 = p2_end - p2_begin; + + static constexpr size_t sequential_cutoff = 5000; + if (n_p1 < sequential_cutoff && n_p2 < sequential_cutoff) { + while (true) { + if (is_feasible(p1_end - 1, p2_end - 1)) { return std::make_pair(p1_end, p2_end); } + if (balance(p1_end - 1, p2_end - 1) < 0) { + if (p2_end == p2_begin) { break; } + p2_end--; + } else { + if (p1_end == p1_begin) { break; } + p1_end--; + } + } + return std::make_pair(invalid_pos, invalid_pos); + } + + const auto c = cumulative_node_weights.begin(); + if (n_p1 > n_p2) { + size_t p1_mid = p1_begin + n_p1 / 2; + auto p2_match_it = std::lower_bound(c + p2_begin, c + p2_end, cumulative_node_weights[p1_mid]); + size_t p2_match = std::distance(cumulative_node_weights.begin(), p2_match_it); + + // TODO apply pruning + // i.e. if p1_mid cannot be compensated, don't recurse on the tail range + // could also binary search for the end of a range + slack and discard everything behind that + + tbb::parallel_invoke([&] { + findBestPrefixesRecursive(p1_begin, p1_mid, p2_begin, p2_match, p1_invalid, p2_invalid, lb_p1, ub_p2); + }, [&] { + findBestPrefixesRecursive(p1_mid, p1_end, p2_match, p2_end, p1_invalid, p2_invalid, lb_p1, ub_p2); + }); + + } else { + + } + + } + Gain DeterministicLabelPropagationRefiner::applyMovesSortedByGainWithRecalculation(PartitionedHypergraph& phg) { if (last_recalc_round.empty() || ++recalc_round == std::numeric_limits::max()) { last_recalc_round.assign(max_num_edges, CAtomic(0)); } - constexpr MoveID invalid_pos = std::numeric_limits::max(); + constexpr MoveID invalid_move_id = std::numeric_limits::max(); if (move_pos_of_node.empty()) { - move_pos_of_node.resize(max_num_nodes, invalid_pos); + move_pos_of_node.resize(max_num_nodes, invalid_move_id); } const size_t num_moves = moves.size(); @@ -437,7 +469,7 @@ namespace mt_kahypar { moves[pos].gain = 0; }); - auto was_node_moved_in_this_round = [&](HypernodeID u) { return move_pos_of_node[u] != invalid_pos; }; + auto was_node_moved_in_this_round = [&](HypernodeID u) { return move_pos_of_node[u] != invalid_move_id; }; // recalculate gains tbb::parallel_for(0UL, num_moves, [&](size_t pos) { @@ -509,7 +541,7 @@ namespace mt_kahypar { #endif // remove markers again - tbb::parallel_for(0UL, num_moves, [&](size_t pos) { move_pos_of_node[moves[pos].node] = invalid_pos; }); + tbb::parallel_for(0UL, num_moves, [&](size_t pos) { move_pos_of_node[moves[pos].node] = invalid_move_id; }); // calculate number of overloaded blocks size_t num_overloaded_blocks_before_pass = 0, num_overloaded_blocks = 0; diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index ca49eee50..0f5868427 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -36,6 +36,7 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { context(context), compute_gains(context.partition.k), moves(hypergraph.initialNumNodes()), // TODO make smaller --> max round size + cumulative_node_weights(hypergraph.initialNumNodes()), sorted_moves(hypergraph.initialNumNodes()), prng(context.partition.seed), active_nodes(0), @@ -52,6 +53,7 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { private: static constexpr bool debug = false; + static constexpr size_t invalid_pos = std::numeric_limits::max(); bool refineImpl(PartitionedHypergraph& hypergraph, const vec& refinement_nodes, kahypar::Metrics& best_metrics, double) final ; @@ -66,6 +68,12 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { template Gain applyMovesIf(PartitionedHypergraph& phg, const vec& moves, size_t end, Predicate&& predicate); + + std::pair findBestPrefixesRecursive( + size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, + size_t p1_inv, size_t p2_inv, + HypernodeWeight lb_p1, HypernodeWeight ub_p2); + MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE void calculateAndSaveBestMove(PartitionedHypergraph& phg, HypernodeID u) { assert(u < phg.initialNumNodes()); @@ -89,6 +97,7 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { const Context& context; tbb::enumerable_thread_specific compute_gains; ds::BufferedVector moves; + vec cumulative_node_weights; vec sorted_moves; std::mt19937 prng; From 134de4a407704160a563cee5f766fe3af6f7d8be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 7 Jun 2021 12:05:13 +0200 Subject: [PATCH 02/66] fix part weight aggregation (wasn't used before) --- external_tools/googletest | 2 +- .../deterministic/deterministic_label_propagation.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/external_tools/googletest b/external_tools/googletest index d5707695c..53495a2a7 160000 --- a/external_tools/googletest +++ b/external_tools/googletest @@ -1 +1 @@ -Subproject commit d5707695cb020ace53dc35f30dd1c3f463daf98e +Subproject commit 53495a2a7d6ba7e0691a7f3602e9a5324bba6e45 diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 0b9240ad0..f8b4f4ec6 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -312,7 +312,8 @@ namespace mt_kahypar { // swap_prefix[index(p1,p2)] stores the first position of moves to revert out of the sequence of moves from p1 to p2 vec swap_prefix(max_key, 0); - vec part_weight_deltas(k, 0); + vec part_weights(k, 0); + for (PartitionID i = 0; i < phg.k(); ++i) { part_weights[i] = phg.partWeight(i); } tbb::parallel_for(0UL, relevant_block_pairs.size(), [&](size_t bp_index) { // sort both directions by gain (alternative: gain / weight?) @@ -338,8 +339,8 @@ namespace mt_kahypar { }); for (const auto& [p1,p2] : relevant_block_pairs) { - HypernodeWeight lb_p1 = (phg.partWeight(p1) + part_weight_deltas[p1]) - context.partition.max_part_weights[p1], - ub_p2 = context.partition.max_part_weights[p2] - (phg.partWeight(p2) + part_weight_deltas[p2]); + HypernodeWeight lb_p1 = (part_weights[p1]) - context.partition.max_part_weights[p1], + ub_p2 = context.partition.max_part_weights[p2] - (part_weights[p2]); size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], p2_begin = positions[index(p2, p1)], p2_end = positions[index(p2, p1) + 1]; @@ -360,8 +361,8 @@ namespace mt_kahypar { swap_prefix[index(p2, p1)] = best_prefix.second; HypernodeWeight best_balance = balance(best_prefix.first - 1, best_prefix.second - 1); LOG << V(best_prefix.first) << V(best_prefix.second) << V(best_balance); - __atomic_fetch_add(&part_weight_deltas[p1], best_balance, __ATOMIC_RELAXED); - __atomic_fetch_sub(&part_weight_deltas[p2], best_balance, __ATOMIC_RELAXED); + __atomic_fetch_sub(&part_weights[p1], best_balance, __ATOMIC_RELAXED); + __atomic_fetch_add(&part_weights[p2], best_balance, __ATOMIC_RELAXED); } LOG << "block-pair handling done"; From ddfb66ec2b2a7aeac9a79b23a9b690a885710abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 7 Jun 2021 12:55:47 +0200 Subject: [PATCH 03/66] don't search left range if mid is feasible --- .../deterministic/deterministic_label_propagation.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index f8b4f4ec6..c71a580bb 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -435,16 +435,23 @@ namespace mt_kahypar { auto p2_match_it = std::lower_bound(c + p2_begin, c + p2_end, cumulative_node_weights[p1_mid]); size_t p2_match = std::distance(cumulative_node_weights.begin(), p2_match_it); + if (p2_match != p2_end && p1_mid != p1_end && is_feasible(p1_mid, p2_match)) { + // no need to search left range + return findBestPrefixesRecursive(p1_mid + 1, p1_end, p2_match + 1, p2_end, p1_invalid, p2_invalid, lb_p1, ub_p2); + } + // TODO apply pruning // i.e. if p1_mid cannot be compensated, don't recurse on the tail range // could also binary search for the end of a range + slack and discard everything behind that + std::pair left, right; tbb::parallel_invoke([&] { - findBestPrefixesRecursive(p1_begin, p1_mid, p2_begin, p2_match, p1_invalid, p2_invalid, lb_p1, ub_p2); + left = findBestPrefixesRecursive(p1_begin, p1_mid, p2_begin, p2_match, p1_invalid, p2_invalid, lb_p1, ub_p2); }, [&] { - findBestPrefixesRecursive(p1_mid, p1_end, p2_match, p2_end, p1_invalid, p2_invalid, lb_p1, ub_p2); + right = findBestPrefixesRecursive(p1_mid, p1_end, p2_match, p2_end, p1_invalid, p2_invalid, lb_p1, ub_p2); }); + return right.first != invalid_pos ? right : left; } else { } From a53f549dbf9354d480641e63281e1dafc3796eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 7 Jun 2021 13:05:34 +0200 Subject: [PATCH 04/66] finish up pruning. still to go: symmetric case --- .../deterministic_label_propagation.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index c71a580bb..f7d73ef30 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -402,6 +402,12 @@ namespace mt_kahypar { HypernodeWeight lb_p1, HypernodeWeight ub_p2) { auto balance = [&](size_t p1_ind, size_t p2_ind) { + assert(p1_ind < p1_end); + assert(p2_ind < p2_end); + assert(p1_ind >= p1_invalid); + assert(p2_ind >= p2_invalid); + assert(p1_ind < cumulative_node_weights.size()); + assert(p2_ind < cumulative_node_weights.size()); const auto a = (p1_ind == p1_invalid) ? 0 : cumulative_node_weights[p1_ind]; const auto b = (p2_ind == p2_invalid) ? 0 : cumulative_node_weights[p2_ind]; return a - b; @@ -439,10 +445,10 @@ namespace mt_kahypar { // no need to search left range return findBestPrefixesRecursive(p1_mid + 1, p1_end, p2_match + 1, p2_end, p1_invalid, p2_invalid, lb_p1, ub_p2); } - - // TODO apply pruning - // i.e. if p1_mid cannot be compensated, don't recurse on the tail range - // could also binary search for the end of a range + slack and discard everything behind that + if (p2_match == p2_end && balance(p1_mid, p2_end - 1) > ub_p2) { + // p1_mid cannot be compensated --> no need to search right range + return findBestPrefixesRecursive(p1_begin, p1_mid, p2_begin, p2_match, p1_invalid, p2_invalid, lb_p1, ub_p2); + } std::pair left, right; tbb::parallel_invoke([&] { From 62baad4f7acd44eae5931daec452e5c5d19e9c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 7 Jun 2021 13:09:51 +0200 Subject: [PATCH 05/66] implement symmetric case --- .../deterministic_label_propagation.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index f7d73ef30..b24fac553 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -456,12 +456,29 @@ namespace mt_kahypar { }, [&] { right = findBestPrefixesRecursive(p1_mid, p1_end, p2_match, p2_end, p1_invalid, p2_invalid, lb_p1, ub_p2); }); - return right.first != invalid_pos ? right : left; } else { + size_t p2_mid = p2_begin + n_p2 / 2; + auto p1_match_it = std::lower_bound(c + p1_begin, c + p1_end, cumulative_node_weights[p2_mid]); + size_t p1_match = std::distance(cumulative_node_weights.begin(), p1_match_it); - } + if (p1_match != p1_end && p2_mid != p2_end && is_feasible(p1_match, p2_mid)) { + // no need to search left range + return findBestPrefixesRecursive(p1_match + 1, p1_end, p2_mid + 1, p2_end, p1_invalid, p2_invalid, lb_p1, ub_p2); + } + if (p1_match == p1_end && balance(p1_end - 1, p2_mid) < lb_p1) { + // p2_mid cannot be compensated --> no need to search right range + return findBestPrefixesRecursive(p1_begin, p1_match, p2_begin, p2_mid, p1_invalid, p2_invalid, lb_p1, ub_p2); + } + std::pair left, right; + tbb::parallel_invoke([&] { + left = findBestPrefixesRecursive(p1_begin, p1_match, p2_begin, p2_mid, p1_invalid, p2_invalid, lb_p1, ub_p2); + }, [&] { + right = findBestPrefixesRecursive(p1_match, p1_end, p2_mid, p2_end, p1_invalid, p2_invalid, lb_p1, ub_p2); + }); + return right.first != invalid_pos ? right : left; + } } Gain DeterministicLabelPropagationRefiner::applyMovesSortedByGainWithRecalculation(PartitionedHypergraph& phg) { From 5c86a96dfb205080b76cdf2d8ab54022e131bab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 7 Jun 2021 13:47:45 +0200 Subject: [PATCH 06/66] implementation seems to be working :) remove debug output --- .../deterministic_label_propagation.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index b24fac553..8fd063caa 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -351,8 +351,6 @@ namespace mt_kahypar { return a - b; }; - LOG << V(p1) << V(p2) << V(p1_begin) << V(p1_end) << V(p2_begin) << V(p2_begin) << (lb_p1) << V(ub_p2); - auto best_prefix = findBestPrefixesRecursive(p1_begin, p1_end, p2_begin, p2_end, p1_begin - 1, p2_begin - 1, lb_p1, ub_p2); @@ -360,11 +358,10 @@ namespace mt_kahypar { swap_prefix[index(p1, p2)] = best_prefix.first; swap_prefix[index(p2, p1)] = best_prefix.second; HypernodeWeight best_balance = balance(best_prefix.first - 1, best_prefix.second - 1); - LOG << V(best_prefix.first) << V(best_prefix.second) << V(best_balance); + assert(best_balance <= ub_p2 && best_balance >= lb_p1); __atomic_fetch_sub(&part_weights[p1], best_balance, __ATOMIC_RELAXED); __atomic_fetch_add(&part_weights[p2], best_balance, __ATOMIC_RELAXED); } - LOG << "block-pair handling done"; moves.clear(); Gain actual_gain = applyMovesIf(phg, sorted_moves, num_moves, [&](size_t pos) { @@ -402,12 +399,12 @@ namespace mt_kahypar { HypernodeWeight lb_p1, HypernodeWeight ub_p2) { auto balance = [&](size_t p1_ind, size_t p2_ind) { - assert(p1_ind < p1_end); - assert(p2_ind < p2_end); - assert(p1_ind >= p1_invalid); - assert(p2_ind >= p2_invalid); - assert(p1_ind < cumulative_node_weights.size()); - assert(p2_ind < cumulative_node_weights.size()); + assert(p1_ind == p1_invalid || p1_ind < p1_end); + assert(p1_ind >= p1_invalid || p1_invalid == (0UL - 1)); + assert(p2_ind == p2_invalid || p2_ind < p2_end); + assert(p2_ind >= p2_invalid || p2_invalid == (0UL - 1)); + assert(p1_ind == p1_invalid || p1_ind < cumulative_node_weights.size()); + assert(p2_ind == p2_invalid || p2_ind < cumulative_node_weights.size()); const auto a = (p1_ind == p1_invalid) ? 0 : cumulative_node_weights[p1_ind]; const auto b = (p2_ind == p2_invalid) ? 0 : cumulative_node_weights[p2_ind]; return a - b; @@ -420,7 +417,7 @@ namespace mt_kahypar { const size_t n_p1 = p1_end - p1_begin, n_p2 = p2_end - p2_begin; - static constexpr size_t sequential_cutoff = 5000; + static constexpr size_t sequential_cutoff = 2000; if (n_p1 < sequential_cutoff && n_p2 < sequential_cutoff) { while (true) { if (is_feasible(p1_end - 1, p2_end - 1)) { return std::make_pair(p1_end, p2_end); } From 0a1371a7fb4c7eb395126dbfa8ff7331c9fdf92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 7 Jun 2021 14:02:03 +0200 Subject: [PATCH 07/66] add stub for sequential best prefix implementation. used for checking correctness of the parallel implementation --- .../deterministic/deterministic_label_propagation.cpp | 8 +++++++- .../deterministic/deterministic_label_propagation.h | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 8fd063caa..09e4aaebc 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -353,7 +353,7 @@ namespace mt_kahypar { auto best_prefix = findBestPrefixesRecursive(p1_begin, p1_end, p2_begin, p2_end, p1_begin - 1, p2_begin - 1, lb_p1, ub_p2); - + assert(best_prefix == findBestPrefixesSequentially(p1_begin, p1_end, p2_begin, p2_end, lb_p1, ub_p2)); swap_prefix[index(p1, p2)] = best_prefix.first; swap_prefix[index(p2, p1)] = best_prefix.second; @@ -478,6 +478,12 @@ namespace mt_kahypar { } } + std::pair DeterministicLabelPropagationRefiner::findBestPrefixesSequentially( + size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, HypernodeWeight lb_p1, HypernodeWeight ub_p2) + { + + } + Gain DeterministicLabelPropagationRefiner::applyMovesSortedByGainWithRecalculation(PartitionedHypergraph& phg) { if (last_recalc_round.empty() || ++recalc_round == std::numeric_limits::max()) { last_recalc_round.assign(max_num_edges, CAtomic(0)); diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index 0f5868427..71ea9d302 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -74,6 +74,10 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { size_t p1_inv, size_t p2_inv, HypernodeWeight lb_p1, HypernodeWeight ub_p2); + // used for verification + std::pair findBestPrefixesSequentially(size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, + HypernodeWeight lb_p1, HypernodeWeight ub_p2); + MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE void calculateAndSaveBestMove(PartitionedHypergraph& phg, HypernodeID u) { assert(u < phg.initialNumNodes()); From 69e7a8db29a0ebee8b9b82bef50f5ecf92891b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 7 Jun 2021 14:11:13 +0200 Subject: [PATCH 08/66] add implementation of sequential prefix --- .../deterministic_label_propagation.cpp | 41 ++++++++++++++++++- .../deterministic_label_propagation.h | 8 ++-- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 09e4aaebc..cc1dfeab0 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -353,7 +353,7 @@ namespace mt_kahypar { auto best_prefix = findBestPrefixesRecursive(p1_begin, p1_end, p2_begin, p2_end, p1_begin - 1, p2_begin - 1, lb_p1, ub_p2); - assert(best_prefix == findBestPrefixesSequentially(p1_begin, p1_end, p2_begin, p2_end, lb_p1, ub_p2)); + assert(best_prefix == findBestPrefixesSequentially(phg, p1_begin, p1_end, p2_begin, p2_end, lb_p1, ub_p2)); swap_prefix[index(p1, p2)] = best_prefix.first; swap_prefix[index(p2, p1)] = best_prefix.second; @@ -479,9 +479,46 @@ namespace mt_kahypar { } std::pair DeterministicLabelPropagationRefiner::findBestPrefixesSequentially( - size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, HypernodeWeight lb_p1, HypernodeWeight ub_p2) + const PartitionedHypergraph& phg, size_t p1_begin, size_t p1_end, + size_t p2_begin, size_t p2_end, HypernodeWeight lb_p1, HypernodeWeight ub_p2) { + int64_t balance = 0; + std::pair best{0, 0}; + + // gain > 0 first. alternate depending on balance + while (p1_begin < p1_end && p2_begin < p2_end) { + if (balance < 0) { + // perform next move from p1 to p2 + balance += phg.nodeWeight(sorted_moves[p1_begin++].node); + } else { + // perform next move from p2 to p1 + balance -= phg.nodeWeight(sorted_moves[p2_begin++].node); + } + + if (balance <= ub_p2 && balance >= lb_p1) { + best = {p1_begin, p2_end}; + } + } + + // if one sequence is depleted or gain == 0. only do rebalancing in the other direction + if (p2_begin == p2_end) { + while (p1_begin < p1_end && balance <= ub_p2) { + balance += phg.nodeWeight(sorted_moves[p1_begin++].node); + if (balance <= ub_p2 && balance >= lb_p1) { + best = {p1_begin, p2_end}; + } + } + } + if (p1_begin == p1_end) { + while (p2_begin < p2_end && balance >= lb_p1) { + balance -= phg.nodeWeight(sorted_moves[p2_begin++].node); + if (balance <= ub_p2 && balance >= lb_p1) { + best = {p1_begin, p2_end}; + } + } + } + return best; } Gain DeterministicLabelPropagationRefiner::applyMovesSortedByGainWithRecalculation(PartitionedHypergraph& phg) { diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index 71ea9d302..be4c5da03 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -70,13 +70,13 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { std::pair findBestPrefixesRecursive( - size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, - size_t p1_inv, size_t p2_inv, + size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, size_t p1_inv, size_t p2_inv, HypernodeWeight lb_p1, HypernodeWeight ub_p2); // used for verification - std::pair findBestPrefixesSequentially(size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, - HypernodeWeight lb_p1, HypernodeWeight ub_p2); + std::pair findBestPrefixesSequentially( + const PartitionedHypergraph& phg, size_t p1_begin, size_t p1_end, + size_t p2_begin, size_t p2_end, HypernodeWeight lb_p1, HypernodeWeight ub_p2); MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE void calculateAndSaveBestMove(PartitionedHypergraph& phg, HypernodeID u) { From 6d6955fa706bd1c4f08a7bbbaf328fe8ce4859b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 7 Jun 2021 16:42:10 +0200 Subject: [PATCH 09/66] previous sequential best prefix implementation had other preferences if balance == 0 --> also use the revert from back approach --- .../deterministic_label_propagation.cpp | 73 +++++++------------ .../deterministic_label_propagation.h | 6 +- 2 files changed, 30 insertions(+), 49 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index cc1dfeab0..3089def21 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -353,8 +353,14 @@ namespace mt_kahypar { auto best_prefix = findBestPrefixesRecursive(p1_begin, p1_end, p2_begin, p2_end, p1_begin - 1, p2_begin - 1, lb_p1, ub_p2); - assert(best_prefix == findBestPrefixesSequentially(phg, p1_begin, p1_end, p2_begin, p2_end, lb_p1, ub_p2)); + assert(best_prefix == findBestPrefixesSequentially(p1_begin, p1_end, p2_begin, p2_end, + p1_begin - 1, p2_begin - 1, lb_p1, ub_p2)); + if (best_prefix.first == invalid_pos) { + // represents no solution found (and recursive version didn't move all the way to the start of the range) + // --> replace with starts of ranges (represents no moves applied) + best_prefix = std::make_pair(p1_begin, p2_begin); + } swap_prefix[index(p1, p2)] = best_prefix.first; swap_prefix[index(p2, p1)] = best_prefix.second; HypernodeWeight best_balance = balance(best_prefix.first - 1, best_prefix.second - 1); @@ -419,17 +425,7 @@ namespace mt_kahypar { static constexpr size_t sequential_cutoff = 2000; if (n_p1 < sequential_cutoff && n_p2 < sequential_cutoff) { - while (true) { - if (is_feasible(p1_end - 1, p2_end - 1)) { return std::make_pair(p1_end, p2_end); } - if (balance(p1_end - 1, p2_end - 1) < 0) { - if (p2_end == p2_begin) { break; } - p2_end--; - } else { - if (p1_end == p1_begin) { break; } - p1_end--; - } - } - return std::make_pair(invalid_pos, invalid_pos); + return findBestPrefixesSequentially(p1_begin, p1_end, p2_begin, p2_end, p1_invalid, p2_invalid, lb_p1, ub_p2); } const auto c = cumulative_node_weights.begin(); @@ -479,46 +475,31 @@ namespace mt_kahypar { } std::pair DeterministicLabelPropagationRefiner::findBestPrefixesSequentially( - const PartitionedHypergraph& phg, size_t p1_begin, size_t p1_end, - size_t p2_begin, size_t p2_end, HypernodeWeight lb_p1, HypernodeWeight ub_p2) + size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, size_t p1_inv, size_t p2_inv, + HypernodeWeight lb_p1, HypernodeWeight ub_p2) { + auto balance = [&](size_t p1_ind, size_t p2_ind) { + const auto a = (p1_ind == p1_inv) ? 0 : cumulative_node_weights[p1_ind]; + const auto b = (p2_ind == p2_inv) ? 0 : cumulative_node_weights[p2_ind]; + return a - b; + }; - int64_t balance = 0; - std::pair best{0, 0}; + auto is_feasible = [&](size_t p1_ind, size_t p2_ind) { + const HypernodeWeight bal = balance(p1_ind, p2_ind); + return lb_p1 <= bal && bal <= ub_p2; + }; - // gain > 0 first. alternate depending on balance - while (p1_begin < p1_end && p2_begin < p2_end) { - if (balance < 0) { - // perform next move from p1 to p2 - balance += phg.nodeWeight(sorted_moves[p1_begin++].node); + while (true) { + if (is_feasible(p1_end - 1, p2_end - 1)) { return std::make_pair(p1_end, p2_end); } + if (balance(p1_end - 1, p2_end - 1) < 0) { + if (p2_end == p2_begin) { break; } + p2_end--; } else { - // perform next move from p2 to p1 - balance -= phg.nodeWeight(sorted_moves[p2_begin++].node); - } - - if (balance <= ub_p2 && balance >= lb_p1) { - best = {p1_begin, p2_end}; - } - } - - // if one sequence is depleted or gain == 0. only do rebalancing in the other direction - if (p2_begin == p2_end) { - while (p1_begin < p1_end && balance <= ub_p2) { - balance += phg.nodeWeight(sorted_moves[p1_begin++].node); - if (balance <= ub_p2 && balance >= lb_p1) { - best = {p1_begin, p2_end}; - } - } - } - if (p1_begin == p1_end) { - while (p2_begin < p2_end && balance >= lb_p1) { - balance -= phg.nodeWeight(sorted_moves[p2_begin++].node); - if (balance <= ub_p2 && balance >= lb_p1) { - best = {p1_begin, p2_end}; - } + if (p1_end == p1_begin) { break; } + p1_end--; } } - return best; + return std::make_pair(invalid_pos, invalid_pos); } Gain DeterministicLabelPropagationRefiner::applyMovesSortedByGainWithRecalculation(PartitionedHypergraph& phg) { diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index be4c5da03..2748e4cbc 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -53,7 +53,7 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { private: static constexpr bool debug = false; - static constexpr size_t invalid_pos = std::numeric_limits::max(); + static constexpr size_t invalid_pos = std::numeric_limits::max() / 2; bool refineImpl(PartitionedHypergraph& hypergraph, const vec& refinement_nodes, kahypar::Metrics& best_metrics, double) final ; @@ -75,8 +75,8 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { // used for verification std::pair findBestPrefixesSequentially( - const PartitionedHypergraph& phg, size_t p1_begin, size_t p1_end, - size_t p2_begin, size_t p2_end, HypernodeWeight lb_p1, HypernodeWeight ub_p2); + size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, size_t p1_inv, size_t p2_inv, + HypernodeWeight lb_p1, HypernodeWeight ub_p2); MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE void calculateAndSaveBestMove(PartitionedHypergraph& phg, HypernodeID u) { From 4e74dc3d023c6a705416125c57638b539883c8b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 7 Jun 2021 17:04:19 +0200 Subject: [PATCH 10/66] extract approve per block-pair into lambda and provide both a parallelization over block-pairs in combination with parallelization per block-pair as well as sequential over block-pairs with parallel per block-pair (for larger balancing ranges) --- .../deterministic_label_propagation.cpp | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 3089def21..14353ce16 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -338,12 +338,9 @@ namespace mt_kahypar { }); }); - for (const auto& [p1,p2] : relevant_block_pairs) { - HypernodeWeight lb_p1 = (part_weights[p1]) - context.partition.max_part_weights[p1], - ub_p2 = context.partition.max_part_weights[p2] - (part_weights[p2]); - - size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], - p2_begin = positions[index(p2, p1)], p2_end = positions[index(p2, p1) + 1]; + auto approve_block_pair = [&](PartitionID p1, PartitionID p2, HypernodeWeight lb_p1, HypernodeWeight ub_p2) { + size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], + p2_begin = positions[index(p2, p1)], p2_end = positions[index(p2, p1) + 1]; auto balance = [&](size_t p1_ind, size_t p2_ind) { const auto a = (p1_ind == p1_begin - 1) ? 0 : cumulative_node_weights[p1_ind]; @@ -367,8 +364,25 @@ namespace mt_kahypar { assert(best_balance <= ub_p2 && best_balance >= lb_p1); __atomic_fetch_sub(&part_weights[p1], best_balance, __ATOMIC_RELAXED); __atomic_fetch_add(&part_weights[p2], best_balance, __ATOMIC_RELAXED); + }; + + for (const auto& [p1, p2] : relevant_block_pairs) { + HypernodeWeight lb_p1 = (part_weights[p1]) - context.partition.max_part_weights[p1], + ub_p2 = context.partition.max_part_weights[p2] - (part_weights[p2]); + approve_block_pair(p1, p2, lb_p1, ub_p2); } + /* + tbb::parallel_for(0UL, relevant_block_pairs.size(), [&](size_t bp_index) { + const auto [p1, p2] = relevant_block_pairs[bp_index]; + HypernodeWeight budget_p1 = context.partition.max_part_weights[p1] - phg.partWeight(p1), + budget_p2 = context.partition.max_part_weights[p2] - phg.partWeight(p2); + HypernodeWeight slack_p1 = budget_p1 / std::max(1UL, involvements[p1]), + slack_p2 = budget_p2 / std::max(1UL, involvements[p2]); + approve_block_pair(p1, p2, -slack_p1, slack_p2); + }); + */ + moves.clear(); Gain actual_gain = applyMovesIf(phg, sorted_moves, num_moves, [&](size_t pos) { if (pos < swap_prefix[index(sorted_moves[pos].from, sorted_moves[pos].to)]) { From db28c1122b04420ef3c1adc426ff06012701a10c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Tue, 8 Jun 2021 08:15:20 +0200 Subject: [PATCH 11/66] shuffle block pairs randomly if handled sequentially --- .../deterministic/deterministic_label_propagation.cpp | 1 + .../deterministic/deterministic_label_propagation.h | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 4d30f782d..4f4afaa01 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -358,6 +358,7 @@ namespace mt_kahypar { __atomic_fetch_add(&part_weights[p2], best_balance, __ATOMIC_RELAXED); }; + std::shuffle(relevant_block_pairs.begin(), relevant_block_pairs.end(), prng); for (const auto& [p1, p2] : relevant_block_pairs) { HypernodeWeight lb_p1 = (part_weights[p1]) - context.partition.max_part_weights[p1], ub_p2 = context.partition.max_part_weights[p2] - (part_weights[p2]); diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index e965261cc..44bb18b93 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -43,7 +43,8 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { active_nodes(0), ets_recalc_data( vec(context.partition.k) ), max_num_nodes(hypergraph.initialNumNodes()), - max_num_edges(hypergraph.initialNumEdges()) + max_num_edges(hypergraph.initialNumEdges()), + prng(context.partition.seed + hypergraph.initialNumNodes()) { if (context.refinement.deterministic_refinement.use_active_node_set) { active_nodes.adapt_capacity(hypergraph.initialNumNodes()); @@ -121,12 +122,13 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { vec> last_moved_in_round; uint32_t round = 0; - tbb::enumerable_thread_specific< vec > ets_recalc_data; vec> last_recalc_round; vec move_pos_of_node; uint32_t recalc_round = 1; size_t max_num_nodes = 0, max_num_edges = 0; + + std::mt19937 prng; }; } From 6d0921fac95ac61632ab3faff2b50cf16dbf054d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Tue, 8 Jun 2021 19:01:39 +0200 Subject: [PATCH 12/66] fix --- .../refinement/deterministic/deterministic_label_propagation.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index 44bb18b93..0afad43ca 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -44,7 +44,6 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { ets_recalc_data( vec(context.partition.k) ), max_num_nodes(hypergraph.initialNumNodes()), max_num_edges(hypergraph.initialNumEdges()), - prng(context.partition.seed + hypergraph.initialNumNodes()) { if (context.refinement.deterministic_refinement.use_active_node_set) { active_nodes.adapt_capacity(hypergraph.initialNumNodes()); @@ -128,7 +127,6 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { uint32_t recalc_round = 1; size_t max_num_nodes = 0, max_num_edges = 0; - std::mt19937 prng; }; } From 03582bc2a85d5412cb3d44081fa0e6ab4413a81a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Tue, 8 Jun 2021 19:04:30 +0200 Subject: [PATCH 13/66] fix --- .../refinement/deterministic/deterministic_label_propagation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index 0afad43ca..a7c7bc3dc 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -43,7 +43,7 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { active_nodes(0), ets_recalc_data( vec(context.partition.k) ), max_num_nodes(hypergraph.initialNumNodes()), - max_num_edges(hypergraph.initialNumEdges()), + max_num_edges(hypergraph.initialNumEdges()) { if (context.refinement.deterministic_refinement.use_active_node_set) { active_nodes.adapt_capacity(hypergraph.initialNumNodes()); From 70aee80ef90e890e1d45ec2ebe8f6cbe233fe558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Wed, 9 Jun 2021 08:07:31 +0200 Subject: [PATCH 14/66] remove shortcut switch --- mt-kahypar/io/command_line_options.cpp | 4 ++-- mt-kahypar/partition/context.cpp | 24 ------------------- .../deterministic_label_propagation.cpp | 2 -- 3 files changed, 2 insertions(+), 28 deletions(-) diff --git a/mt-kahypar/io/command_line_options.cpp b/mt-kahypar/io/command_line_options.cpp index 3dc42efa6..28732c3b0 100644 --- a/mt-kahypar/io/command_line_options.cpp +++ b/mt-kahypar/io/command_line_options.cpp @@ -52,8 +52,8 @@ namespace mt_kahypar { options.add_options() ("help", "show help message") ("deterministic", po::value(&context.partition.deterministic)->value_name("")->default_value(false), - "Shortcut to enables deterministic partitioning mode, where results are reproducible across runs. " - "If set, the specific deterministic subroutines don't need to be set manually.") + "Enables determinism in preprocessing in initial partitioning. " + "Coarsening and refinement routines must still be set to the deterministic versions.") ("verbose,v", po::value(&context.partition.verbose_output)->value_name("")->default_value(true), "Verbose main partitioning output") ("write-partition-file", diff --git a/mt-kahypar/partition/context.cpp b/mt-kahypar/partition/context.cpp index ce4b17781..2f98abeba 100644 --- a/mt-kahypar/partition/context.cpp +++ b/mt-kahypar/partition/context.cpp @@ -405,31 +405,7 @@ namespace mt_kahypar { partition.max_part_weights.size()); } - shared_memory.static_balancing_work_packages = std::clamp(shared_memory.static_balancing_work_packages, 4UL, 256UL); - - if ( partition.deterministic ) { - coarsening.algorithm = CoarseningAlgorithm::deterministic_multilevel_coarsener; - - // disable FM until we have a deterministic version - refinement.fm.algorithm = FMAlgorithm::do_nothing; - initial_partitioning.refinement.fm.algorithm = FMAlgorithm::do_nothing; - - // disable adaptive IP - initial_partitioning.use_adaptive_ip_runs = false; - - - // switch silently - auto lp_algo = refinement.label_propagation.algorithm; - if ( lp_algo != LabelPropagationAlgorithm::do_nothing && lp_algo != LabelPropagationAlgorithm::deterministic ) { - refinement.label_propagation.algorithm = LabelPropagationAlgorithm::deterministic; - } - - lp_algo = initial_partitioning.refinement.label_propagation.algorithm; - if ( lp_algo != LabelPropagationAlgorithm::do_nothing && lp_algo != LabelPropagationAlgorithm::deterministic ) { - initial_partitioning.refinement.label_propagation.algorithm = LabelPropagationAlgorithm::deterministic; - } - } } std::ostream & operator<< (std::ostream& str, const Context& context) { diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 4f4afaa01..c3e835ac4 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -253,7 +253,6 @@ namespace mt_kahypar { // if that decreased solution quality, revert it all if (gain < 0) { - DBG << "Kommando zurück" << V(gain) << V(num_moves) << V(num_reverted_moves); gain += applyMovesIf(phg, moves.getData(), num_moves, [&](size_t pos) { if (moves[pos].isValid()) { std::swap(moves[pos].from, moves[pos].to); @@ -389,7 +388,6 @@ namespace mt_kahypar { // revert everything if that decreased solution quality if (actual_gain < 0) { - DBG << "Kommando zurück" << V(actual_gain); actual_gain += applyMovesIf(phg, sorted_moves, num_moves, [&](size_t pos) { if (pos < swap_prefix[index(sorted_moves[pos].from, sorted_moves[pos].to)]) { std::swap(sorted_moves[pos].from, sorted_moves[pos].to); From 19ba1b584e32a0b4267c07634fa1aeb5c9e1edb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Wed, 9 Jun 2021 17:45:49 +0200 Subject: [PATCH 15/66] use parallelism over block pairs --- .../deterministic/deterministic_label_propagation.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index c3e835ac4..93fba7a5b 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -357,14 +357,15 @@ namespace mt_kahypar { __atomic_fetch_add(&part_weights[p2], best_balance, __ATOMIC_RELAXED); }; + /* std::shuffle(relevant_block_pairs.begin(), relevant_block_pairs.end(), prng); for (const auto& [p1, p2] : relevant_block_pairs) { HypernodeWeight lb_p1 = (part_weights[p1]) - context.partition.max_part_weights[p1], ub_p2 = context.partition.max_part_weights[p2] - (part_weights[p2]); approve_block_pair(p1, p2, lb_p1, ub_p2); } + */ - /* tbb::parallel_for(0UL, relevant_block_pairs.size(), [&](size_t bp_index) { const auto [p1, p2] = relevant_block_pairs[bp_index]; HypernodeWeight budget_p1 = context.partition.max_part_weights[p1] - phg.partWeight(p1), @@ -373,7 +374,7 @@ namespace mt_kahypar { slack_p2 = budget_p2 / std::max(1UL, involvements[p2]); approve_block_pair(p1, p2, -slack_p1, slack_p2); }); - */ + moves.clear(); Gain actual_gain = applyMovesIf(phg, sorted_moves, num_moves, [&](size_t pos) { From 94b790370b911dc3a0021825f39755c2ee73e2bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Thu, 10 Jun 2021 18:18:29 +0200 Subject: [PATCH 16/66] parse recalc gains parameter --- config/speed_deterministic_preset.ini | 2 ++ mt-kahypar/io/command_line_options.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/config/speed_deterministic_preset.ini b/config/speed_deterministic_preset.ini index a22d37cea..1bced1072 100644 --- a/config/speed_deterministic_preset.ini +++ b/config/speed_deterministic_preset.ini @@ -44,6 +44,7 @@ i-r-lp-maximum-iterations=5 i-r-sync-lp-sub-rounds=1 i-r-lp-he-size-activation-threshold=100 i-r-sync-lp-active-nodeset=true +i-r-sync-lp-recalculate-gains-on-second-apply=false # main -> initial_partitioning -> refinement -> fm i-r-fm-type=do_nothing i-population-size=64 @@ -55,5 +56,6 @@ r-lp-maximum-iterations=5 r-sync-lp-sub-rounds=1 r-lp-he-size-activation-threshold=100 r-sync-lp-active-nodeset=true +r-sync-lp-recalculate-gains-on-second-apply=false # main -> refinement -> fm r-fm-type=do_nothing \ No newline at end of file diff --git a/mt-kahypar/io/command_line_options.cpp b/mt-kahypar/io/command_line_options.cpp index 28732c3b0..8fcca0c98 100644 --- a/mt-kahypar/io/command_line_options.cpp +++ b/mt-kahypar/io/command_line_options.cpp @@ -296,7 +296,12 @@ namespace mt_kahypar { po::value((!initial_partitioning ? &context.refinement.deterministic_refinement.use_active_node_set : &context.initial_partitioning.refinement.deterministic_refinement.use_active_node_set))->value_name( "")->default_value(true), - "Number of sub-rounds for deterministic synchronous label propagation") + "Use active nodeset in synchronous label propagation") + ((initial_partitioning ? "i-r-sync-lp-recalculate-gains-on-second-apply" : "r-sync-lp-recalculate-gains-on-second-apply"), + po::value((!initial_partitioning ? &context.refinement.deterministic_refinement.recalculate_gains_on_second_apply : + &context.initial_partitioning.refinement.deterministic_refinement.recalculate_gains_on_second_apply))->value_name( + "")->default_value(false), + "Recalculate gains for second attempt at applying moves in synchronous label propagation") ((initial_partitioning ? "i-r-lp-rebalancing" : "r-lp-rebalancing"), po::value((!initial_partitioning ? &context.refinement.label_propagation.rebalancing : &context.initial_partitioning.refinement.label_propagation.rebalancing))->value_name( From e304b6975300160114dab6f0d329ea9bd7dee5a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 11 Jun 2021 11:28:39 +0200 Subject: [PATCH 17/66] clean up block pair apply code a little more --- .../deterministic_label_propagation.cpp | 47 +++++-------------- 1 file changed, 11 insertions(+), 36 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 93fba7a5b..901679225 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -303,8 +303,6 @@ namespace mt_kahypar { // swap_prefix[index(p1,p2)] stores the first position of moves to revert out of the sequence of moves from p1 to p2 vec swap_prefix(max_key, 0); - vec part_weights(k, 0); - for (PartitionID i = 0; i < phg.k(); ++i) { part_weights[i] = phg.partWeight(i); } tbb::parallel_for(0UL, relevant_block_pairs.size(), [&](size_t bp_index) { // sort both directions by gain (alternative: gain / weight?) @@ -321,24 +319,23 @@ namespace mt_kahypar { cumulative_node_weights.begin() + begin, std::plus<>(), 0); }; - const auto& bp = relevant_block_pairs[bp_index]; + const auto [p1, p2] = relevant_block_pairs[bp_index]; tbb::parallel_invoke([&] { - sort_by_gain_and_prefix_sum_node_weights(bp.first, bp.second); + sort_by_gain_and_prefix_sum_node_weights(p1, p2); }, [&] { - sort_by_gain_and_prefix_sum_node_weights(bp.second, bp.first); + sort_by_gain_and_prefix_sum_node_weights(p2, p1); }); - }); - auto approve_block_pair = [&](PartitionID p1, PartitionID p2, HypernodeWeight lb_p1, HypernodeWeight ub_p2) { + + HypernodeWeight budget_p1 = context.partition.max_part_weights[p1] - phg.partWeight(p1), + budget_p2 = context.partition.max_part_weights[p2] - phg.partWeight(p2); + HypernodeWeight lb_p1 = budget_p1 / std::max(1UL, involvements[p1]), + ub_p2 = budget_p2 / std::max(1UL, involvements[p2]); + + size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], p2_begin = positions[index(p2, p1)], p2_end = positions[index(p2, p1) + 1]; - auto balance = [&](size_t p1_ind, size_t p2_ind) { - const auto a = (p1_ind == p1_begin - 1) ? 0 : cumulative_node_weights[p1_ind]; - const auto b = (p2_ind == p2_begin - 1) ? 0 : cumulative_node_weights[p2_ind]; - return a - b; - }; - auto best_prefix = findBestPrefixesRecursive(p1_begin, p1_end, p2_begin, p2_end, p1_begin - 1, p2_begin - 1, lb_p1, ub_p2); @@ -351,31 +348,9 @@ namespace mt_kahypar { } swap_prefix[index(p1, p2)] = best_prefix.first; swap_prefix[index(p2, p1)] = best_prefix.second; - HypernodeWeight best_balance = balance(best_prefix.first - 1, best_prefix.second - 1); - assert(best_balance <= ub_p2 && best_balance >= lb_p1); - __atomic_fetch_sub(&part_weights[p1], best_balance, __ATOMIC_RELAXED); - __atomic_fetch_add(&part_weights[p2], best_balance, __ATOMIC_RELAXED); - }; - - /* - std::shuffle(relevant_block_pairs.begin(), relevant_block_pairs.end(), prng); - for (const auto& [p1, p2] : relevant_block_pairs) { - HypernodeWeight lb_p1 = (part_weights[p1]) - context.partition.max_part_weights[p1], - ub_p2 = context.partition.max_part_weights[p2] - (part_weights[p2]); - approve_block_pair(p1, p2, lb_p1, ub_p2); - } - */ - - tbb::parallel_for(0UL, relevant_block_pairs.size(), [&](size_t bp_index) { - const auto [p1, p2] = relevant_block_pairs[bp_index]; - HypernodeWeight budget_p1 = context.partition.max_part_weights[p1] - phg.partWeight(p1), - budget_p2 = context.partition.max_part_weights[p2] - phg.partWeight(p2); - HypernodeWeight slack_p1 = budget_p1 / std::max(1UL, involvements[p1]), - slack_p2 = budget_p2 / std::max(1UL, involvements[p2]); - approve_block_pair(p1, p2, -slack_p1, slack_p2); + }); - moves.clear(); Gain actual_gain = applyMovesIf(phg, sorted_moves, num_moves, [&](size_t pos) { if (pos < swap_prefix[index(sorted_moves[pos].from, sorted_moves[pos].to)]) { From cb186491c176422820e8f0b413197e817f8674b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Wed, 16 Jun 2021 22:01:36 +0200 Subject: [PATCH 18/66] fix warning --- .../deterministic/deterministic_label_propagation.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 901679225..7e96d01c3 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -319,20 +319,19 @@ namespace mt_kahypar { cumulative_node_weights.begin() + begin, std::plus<>(), 0); }; - const auto [p1, p2] = relevant_block_pairs[bp_index]; + PartitionID p1, p2; + std::tie(p1, p2) = relevant_block_pairs[bp_index]; tbb::parallel_invoke([&] { sort_by_gain_and_prefix_sum_node_weights(p1, p2); }, [&] { sort_by_gain_and_prefix_sum_node_weights(p2, p1); }); - HypernodeWeight budget_p1 = context.partition.max_part_weights[p1] - phg.partWeight(p1), budget_p2 = context.partition.max_part_weights[p2] - phg.partWeight(p2); HypernodeWeight lb_p1 = budget_p1 / std::max(1UL, involvements[p1]), ub_p2 = budget_p2 / std::max(1UL, involvements[p2]); - size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], p2_begin = positions[index(p2, p1)], p2_end = positions[index(p2, p1) + 1]; @@ -348,7 +347,7 @@ namespace mt_kahypar { } swap_prefix[index(p1, p2)] = best_prefix.first; swap_prefix[index(p2, p1)] = best_prefix.second; - + }); moves.clear(); @@ -613,4 +612,4 @@ namespace mt_kahypar { return best_gain; } -} // namespace mt_kahypar \ No newline at end of file +} // namespace mt_kahypar From d67912e75f98df95aaea3b6b19bbe3dc3858b105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Wed, 16 Jun 2021 22:37:33 +0200 Subject: [PATCH 19/66] fix sign bug that was introduced while cleaning up --- .../deterministic/deterministic_label_propagation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 7e96d01c3..76dd212db 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -329,7 +329,7 @@ namespace mt_kahypar { HypernodeWeight budget_p1 = context.partition.max_part_weights[p1] - phg.partWeight(p1), budget_p2 = context.partition.max_part_weights[p2] - phg.partWeight(p2); - HypernodeWeight lb_p1 = budget_p1 / std::max(1UL, involvements[p1]), + HypernodeWeight lb_p1 = -budget_p1 / std::max(1UL, involvements[p1]), ub_p2 = budget_p2 / std::max(1UL, involvements[p2]); size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], From 56617f3a98c20561044b346ac951ff3f740f5dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Wed, 16 Jun 2021 23:04:02 +0200 Subject: [PATCH 20/66] fix division by unsigned int bug --- .../deterministic/deterministic_label_propagation.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 76dd212db..cb32892c1 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -303,7 +303,6 @@ namespace mt_kahypar { // swap_prefix[index(p1,p2)] stores the first position of moves to revert out of the sequence of moves from p1 to p2 vec swap_prefix(max_key, 0); - tbb::parallel_for(0UL, relevant_block_pairs.size(), [&](size_t bp_index) { // sort both directions by gain (alternative: gain / weight?) auto sort_by_gain_and_prefix_sum_node_weights = [&](PartitionID p1, PartitionID p2) { @@ -329,7 +328,7 @@ namespace mt_kahypar { HypernodeWeight budget_p1 = context.partition.max_part_weights[p1] - phg.partWeight(p1), budget_p2 = context.partition.max_part_weights[p2] - phg.partWeight(p2); - HypernodeWeight lb_p1 = -budget_p1 / std::max(1UL, involvements[p1]), + HypernodeWeight lb_p1 = (-budget_p1) / int(std::max(1UL, involvements[p1])), ub_p2 = budget_p2 / std::max(1UL, involvements[p2]); size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], @@ -347,7 +346,6 @@ namespace mt_kahypar { } swap_prefix[index(p1, p2)] = best_prefix.first; swap_prefix[index(p2, p1)] = best_prefix.second; - }); moves.clear(); From 0af81cac42ad52ee7172e06e98a26b3d5397394e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Wed, 16 Jun 2021 23:08:09 +0200 Subject: [PATCH 21/66] prettier fix --- .../deterministic/deterministic_label_propagation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index cb32892c1..a5f90afa8 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -328,7 +328,7 @@ namespace mt_kahypar { HypernodeWeight budget_p1 = context.partition.max_part_weights[p1] - phg.partWeight(p1), budget_p2 = context.partition.max_part_weights[p2] - phg.partWeight(p2); - HypernodeWeight lb_p1 = (-budget_p1) / int(std::max(1UL, involvements[p1])), + HypernodeWeight lb_p1 = -(budget_p1 /std::max(1UL, involvements[p1])), ub_p2 = budget_p2 / std::max(1UL, involvements[p2]); size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], From 959af2cd4070c7a9798d523efe3bf53b4b920c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 11 Jun 2021 16:15:08 +0200 Subject: [PATCH 22/66] fix assertion that does not consider disabled nodes in IP --- .../flat/initial_partitioning_data_container.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mt-kahypar/partition/initial_partitioning/flat/initial_partitioning_data_container.h b/mt-kahypar/partition/initial_partitioning/flat/initial_partitioning_data_container.h index 2a097b0ed..41fc60eb8 100644 --- a/mt-kahypar/partition/initial_partitioning/flat/initial_partitioning_data_container.h +++ b/mt-kahypar/partition/initial_partitioning/flat/initial_partitioning_data_container.h @@ -291,6 +291,7 @@ class InitialPartitioningDataContainer { void copyPartition(vec& partition_store) const { for (HypernodeID node : _partitioned_hypergraph.nodes()) { + ASSERT(_partitioned_hypergraph.partID(node) != kInvalidPartition); partition_store[node] = _partitioned_hypergraph.partID(node); } } @@ -484,7 +485,6 @@ class InitialPartitioningDataContainer { _best_partitions[0].first = my_result; std::pop_heap(_best_partitions.begin(), _best_partitions.end(), comp); std::push_heap(_best_partitions.begin(), _best_partitions.end(), comp); - assert(std::is_heap(_best_partitions.begin(), _best_partitions.end(), comp)); } _pop_lock.unlock(); } @@ -492,7 +492,6 @@ class InitialPartitioningDataContainer { if (my_ip_data._result.is_other_better(my_result, eps)) { my_ip_data._result = my_result; my_ip_data.copyPartition(my_ip_data._partition); - assert(std::all_of(my_ip_data._partition.begin(), my_ip_data._partition.end(), [&](PartitionID p) { return p != kInvalidPartition; })); } } my_ip_data._partitioned_hypergraph.resetPartition(); From 045801df5c85683df6727cd04aaef8bcbf489bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Sun, 20 Jun 2021 15:57:38 +0200 Subject: [PATCH 23/66] add assertion --- .../coarsening/deterministic_multilevel_coarsener.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp b/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp index 1aa41bc8c..1ea28e465 100644 --- a/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp +++ b/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp @@ -62,7 +62,7 @@ void DeterministicMultilevelCoarsener::coarsenImpl() { // each vertex finds a cluster it wants to join tbb::parallel_for(first, last, [&](size_t pos) { const HypernodeID u = permutation.at(pos); - if (cluster_weight[u] == hg.nodeWeight(u) && hg.nodeIsEnabled(u)) { + if (hg.nodeIsEnabled(u) && cluster_weight[u] == hg.nodeWeight(u)) { calculatePreferredTargetCluster(u, clusters); } }); @@ -102,9 +102,10 @@ void DeterministicMultilevelCoarsener::coarsenImpl() { break; } performMultilevelContraction(std::move(clusters), pass_start_time); + ASSERT(currentNumNodes() == num_nodes - hg.numRemovedHypernodes()); } - progress_bar += (initial_num_nodes - progress_bar.count()); // fill to 100% + progress_bar += (initial_num_nodes - progress_bar.count()); // fill to 100% progress_bar.disable(); finalize(); } From 508893cc6cfc6734d09a411d7fe90970c9fe3939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Sun, 20 Jun 2021 18:12:37 +0200 Subject: [PATCH 24/66] enabled check --- .../deterministic/deterministic_label_propagation.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index a7c7bc3dc..4e447497b 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -82,7 +82,7 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE void calculateAndSaveBestMove(PartitionedHypergraph& phg, HypernodeID u) { assert(u < phg.initialNumNodes()); - if (!phg.isBorderNode(u)) return; + if (!phg.nodeIsEnabled(u) || !phg.isBorderNode(u)) return; //auto [to, gain] = compute_gains.local().computeBestTargetBlock(phg, u, context.partition.max_part_weights); auto [to, gain] = compute_gains.local().computeBestTargetBlockIgnoringBalance(phg, u); if (gain > 0 && to != kInvalidPartition) { // depending on apply moves function we might do gain >= 0 @@ -92,7 +92,7 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE void calculateAndSaveBestMoveTwoWay(PartitionedHypergraph& phg, HypernodeID u) { - if (!phg.isBorderNode(u)) return; + if (!phg.nodeIsEnabled(u) || !phg.isBorderNode(u)) return; const Gain gain = TwoWayGainComputer::gainToOtherBlock(phg, u); if (gain > 0) { moves.push_back_buffered({ phg.partID(u), 1 - phg.partID(u), u, gain }); @@ -130,4 +130,3 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { }; } - From 5fd1d70f9bf1e8fbe53b845b16c62a05bed42545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Sun, 20 Jun 2021 19:29:55 +0200 Subject: [PATCH 25/66] dont waste tls keys on code thats not performance critical --- mt-kahypar/datastructures/partitioned_hypergraph.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/datastructures/partitioned_hypergraph.h b/mt-kahypar/datastructures/partitioned_hypergraph.h index 2f3d0dd23..e3ce66101 100644 --- a/mt-kahypar/datastructures/partitioned_hypergraph.h +++ b/mt-kahypar/datastructures/partitioned_hypergraph.h @@ -426,7 +426,7 @@ class PartitionedHypergraph { // Recalculate pin count in parts const size_t incidence_array_start = _hg->hyperedge(he).firstEntry(); const size_t incidence_array_end = _hg->hyperedge(he).firstInvalidEntry(); - tls_enumerable_thread_specific< vec > ets_pin_count_in_part(_k, 0); + tbb::enumerable_thread_specific< vec > ets_pin_count_in_part(_k, 0); tbb::parallel_for(incidence_array_start, incidence_array_end, [&](const size_t pos) { const HypernodeID pin = _hg->_incidence_array[pos]; const PartitionID block = partID(pin); @@ -1203,4 +1203,4 @@ class PartitionedHypergraph { }; } // namespace ds -} // namespace mt_kahypar \ No newline at end of file +} // namespace mt_kahypar From 87a271e542133eb9e16b590128ec21988cabb62d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Sun, 20 Jun 2021 19:30:17 +0200 Subject: [PATCH 26/66] add TODO (large he remover breaks in case of multi-pins) --- mt-kahypar/datastructures/static_hypergraph.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mt-kahypar/datastructures/static_hypergraph.h b/mt-kahypar/datastructures/static_hypergraph.h index fa3f63ee3..076846937 100644 --- a/mt-kahypar/datastructures/static_hypergraph.h +++ b/mt-kahypar/datastructures/static_hypergraph.h @@ -746,6 +746,7 @@ class StaticHypergraph { ASSERT(edgeIsEnabled(he), "Hyperedge" << he << "is disabled"); const size_t incidence_array_start = hyperedge(he).firstEntry(); const size_t incidence_array_end = hyperedge(he).firstInvalidEntry(); + // TODO this breaks if we have multi-pins. same for restore. we don't have a check for multi-pins in the input tbb::parallel_for(incidence_array_start, incidence_array_end, [&](const size_t pos) { const HypernodeID pin = _incidence_array[pos]; removeIncidentEdgeFromHypernode(he, pin); @@ -954,4 +955,4 @@ class StaticHypergraph { }; } // namespace ds -} // namespace mt_kahypar \ No newline at end of file +} // namespace mt_kahypar From 9acaabfecc699cf175d6892eee9e245c907fe492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 21 Jun 2021 10:06:08 +0200 Subject: [PATCH 27/66] fix non-determinism source from high degree special handling in hypergraph contraction --- .../datastructures/static_hypergraph.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/mt-kahypar/datastructures/static_hypergraph.cpp b/mt-kahypar/datastructures/static_hypergraph.cpp index 390802b15..25492c799 100644 --- a/mt-kahypar/datastructures/static_hypergraph.cpp +++ b/mt-kahypar/datastructures/static_hypergraph.cpp @@ -127,9 +127,6 @@ namespace mt_kahypar::ds { ASSERT(coarse_hn < num_hypernodes, V(coarse_hn) << V(num_hypernodes)); // Weight vector is atomic => thread-safe hn_weights[coarse_hn] += nodeWeight(hn); - // In case community detection is enabled all vertices matched to one vertex - // in the contracted hypergraph belong to same community. Otherwise, all communities - // are default assigned to community 0 // Aggregate upper bound for number of incident nets of the contracted vertex tmp_num_incident_nets[coarse_hn] += nodeDegree(hn); }); @@ -382,8 +379,7 @@ namespace mt_kahypar::ds { // Compute number of hyperedges in coarse graph (those flagged as valid) parallel::TBBPrefixSum he_mapping(valid_hyperedges); tbb::parallel_invoke([&] { - tbb::parallel_scan(tbb::blocked_range( - 0UL, UI64(_num_hyperedges)), he_mapping); + tbb::parallel_scan(tbb::blocked_range(0UL, UI64(_num_hyperedges)), he_mapping); }, [&] { hypergraph._hypernodes.resize(num_hypernodes); }); @@ -427,11 +423,11 @@ namespace mt_kahypar::ds { // Write hyperedges from temporary buffers to incidence array tbb::enumerable_thread_specific local_max_edge_size(0UL); tbb::parallel_for(ID(0), _num_hyperedges, [&](const HyperedgeID& id) { - if ( he_mapping.value(id) /* hyperedge is valid */ ) { + if ( he_mapping.value(id) > 0 /* hyperedge is valid */ ) { const size_t he_pos = he_mapping[id]; const size_t incidence_array_start = num_pins_prefix_sum[id]; Hyperedge& he = hypergraph._hyperedges[he_pos]; - he = std::move(tmp_hyperedges[id]); + he = tmp_hyperedges[id]; const size_t tmp_incidence_array_start = he.firstEntry(); const size_t edge_size = he.size(); local_max_edge_size.local() = std::max(local_max_edge_size.local(), edge_size); @@ -459,7 +455,7 @@ namespace mt_kahypar::ds { size_t incident_nets_end = tmp_hypernodes[id].firstInvalidEntry(); for ( size_t pos = incident_nets_start; pos < incident_nets_end; ++pos ) { const HyperedgeID he = tmp_incident_nets[pos]; - if ( he_mapping.value(he) ) { + if ( he_mapping.value(he) > 0 /* hyperedge is valid */ ) { tmp_incident_nets[pos] = he_mapping[he]; } else { std::swap(tmp_incident_nets[pos--], tmp_incident_nets[--incident_nets_end]); @@ -486,18 +482,22 @@ namespace mt_kahypar::ds { tbb::parallel_for(ID(0), num_hypernodes, [&](const HypernodeID& id) { const size_t incident_nets_start = num_incident_nets_prefix_sum[id]; Hypernode& hn = hypergraph._hypernodes[id]; - hn = std::move(tmp_hypernodes[id]); + hn = tmp_hypernodes[id]; const size_t tmp_incident_nets_start = hn.firstEntry(); std::memcpy(hypergraph._incident_nets.data() + incident_nets_start, tmp_incident_nets.data() + tmp_incident_nets_start, sizeof(HyperedgeID) * hn.size()); hn.setFirstEntry(incident_nets_start); + + // still need to sort here because high degree vertex handling does not insert in deterministic order + std::sort(hypergraph._incident_nets.begin() + hn.firstEntry(), + hypergraph._incident_nets.begin() + hn.firstInvalidEntry()); }); utils::Timer::instance().stop_timer("setup_incident_nets"); utils::Timer::instance().stop_timer("setup_hypernodes"); }; - tbb::parallel_invoke( assign_communities, setup_hyperedges, setup_hypernodes); + tbb::parallel_invoke(assign_communities, setup_hyperedges, setup_hypernodes); utils::Timer::instance().stop_timer("contract_hypergraph"); hypergraph._total_weight = _total_weight; // didn't lose any vertices @@ -600,4 +600,4 @@ namespace mt_kahypar::ds { }, std::plus<>()); } -} // namespace \ No newline at end of file +} // namespace From b95555e4dc65be4dc6ae8def84c23ce0a8bdce1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 21 Jun 2021 19:56:25 +0200 Subject: [PATCH 28/66] only sort for high degree vertices --- mt-kahypar/datastructures/concurrent_bucket_map.h | 6 ++---- mt-kahypar/datastructures/static_hypergraph.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/mt-kahypar/datastructures/concurrent_bucket_map.h b/mt-kahypar/datastructures/concurrent_bucket_map.h index bdda30a19..7c4480b6a 100644 --- a/mt-kahypar/datastructures/concurrent_bucket_map.h +++ b/mt-kahypar/datastructures/concurrent_bucket_map.h @@ -61,8 +61,7 @@ class ConcurrentBucketMap { public: ConcurrentBucketMap() : - _num_buckets(align_to_next_power_of_two( - BUCKET_FACTOR * std::thread::hardware_concurrency())), + _num_buckets(align_to_next_power_of_two(BUCKET_FACTOR * std::thread::hardware_concurrency())), _mod_mask(_num_buckets - 1), _spin_locks(_num_buckets), _buckets(_num_buckets) { } @@ -71,8 +70,7 @@ class ConcurrentBucketMap { ConcurrentBucketMap & operator= (const ConcurrentBucketMap &) = delete; ConcurrentBucketMap(ConcurrentBucketMap&& other) : - _num_buckets(align_to_next_power_of_two( - BUCKET_FACTOR * std::thread::hardware_concurrency())), + _num_buckets(align_to_next_power_of_two(BUCKET_FACTOR * BUCKET_FACTOR)), _mod_mask(_num_buckets - 1), _spin_locks(_num_buckets), _buckets(std::move(other._buffer)) { } diff --git a/mt-kahypar/datastructures/static_hypergraph.cpp b/mt-kahypar/datastructures/static_hypergraph.cpp index 25492c799..8f8476f44 100644 --- a/mt-kahypar/datastructures/static_hypergraph.cpp +++ b/mt-kahypar/datastructures/static_hypergraph.cpp @@ -27,6 +27,7 @@ #include "mt-kahypar/utils/memory_tree.h" #include +#include namespace mt_kahypar::ds { @@ -287,6 +288,10 @@ namespace mt_kahypar::ds { // Update number of incident nets of high degree vertex const size_t contracted_size = incident_nets_pos.load() - incident_nets_start; tmp_hypernodes[coarse_hn].setSize(contracted_size); + + // sort for determinism + tbb::parallel_sort(tmp_incident_nets.begin() + incident_nets_start, + tmp_incident_nets.begin() + incident_nets_start + contracted_size); } duplicate_incident_nets_map.free(); } @@ -488,10 +493,6 @@ namespace mt_kahypar::ds { tmp_incident_nets.data() + tmp_incident_nets_start, sizeof(HyperedgeID) * hn.size()); hn.setFirstEntry(incident_nets_start); - - // still need to sort here because high degree vertex handling does not insert in deterministic order - std::sort(hypergraph._incident_nets.begin() + hn.firstEntry(), - hypergraph._incident_nets.begin() + hn.firstInvalidEntry()); }); utils::Timer::instance().stop_timer("setup_incident_nets"); utils::Timer::instance().stop_timer("setup_hypernodes"); From c01a0ad249a79d385d67e067a7f92c55ac031e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 21 Jun 2021 20:00:34 +0200 Subject: [PATCH 29/66] make concurrent bucket map size independent of machine used --- mt-kahypar/datastructures/concurrent_bucket_map.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/datastructures/concurrent_bucket_map.h b/mt-kahypar/datastructures/concurrent_bucket_map.h index 7c4480b6a..f8192f458 100644 --- a/mt-kahypar/datastructures/concurrent_bucket_map.h +++ b/mt-kahypar/datastructures/concurrent_bucket_map.h @@ -61,7 +61,7 @@ class ConcurrentBucketMap { public: ConcurrentBucketMap() : - _num_buckets(align_to_next_power_of_two(BUCKET_FACTOR * std::thread::hardware_concurrency())), + _num_buckets(align_to_next_power_of_two(BUCKET_FACTOR * BUCKET_FACTOR)), _mod_mask(_num_buckets - 1), _spin_locks(_num_buckets), _buckets(_num_buckets) { } From 18df03cd3ad82e79d5e60b19d9d469469bf6ff98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 21 Jun 2021 20:02:13 +0200 Subject: [PATCH 30/66] fix random access operator for array iterator --- mt-kahypar/datastructures/array.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/datastructures/array.h b/mt-kahypar/datastructures/array.h index 96c2f4a7c..2d98d9e94 100644 --- a/mt-kahypar/datastructures/array.h +++ b/mt-kahypar/datastructures/array.h @@ -99,7 +99,7 @@ class Array { } reference operator[](const difference_type& n) const { - return *_ptr[n]; + return _ptr[n]; } bool operator==(const ArrayIterator& other) const { @@ -474,4 +474,4 @@ namespace parallel { } -} // namespace mt_kahypar \ No newline at end of file +} // namespace mt_kahypar From 64d172afa6f042f73e5c50ed6f95a5ede778791c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 5 Jul 2021 11:48:04 +0200 Subject: [PATCH 31/66] increase sub-rounds if move sequence was reverted due to negative gain --- .../deterministic_label_propagation.cpp | 22 +++++++++++-------- .../deterministic_label_propagation.h | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index a5f90afa8..cbd4fde17 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -35,8 +35,7 @@ namespace mt_kahypar { const double) { Gain overall_improvement = 0; constexpr size_t num_buckets = utils::ParallelPermutation::num_buckets; - const size_t num_sub_rounds = context.refinement.deterministic_refinement.num_sub_rounds_sync_lp; - const size_t num_buckets_per_sub_round = parallel::chunking::idiv_ceil(num_buckets, num_sub_rounds); + size_t num_sub_rounds = context.refinement.deterministic_refinement.num_sub_rounds_sync_lp; for (size_t iter = 0; iter < context.refinement.label_propagation.maximum_iterations; ++iter) { if (context.refinement.deterministic_refinement.use_active_node_set && ++round == 0) { @@ -53,8 +52,10 @@ namespace mt_kahypar { } active_nodes.clear(); + const size_t num_buckets_per_sub_round = parallel::chunking::idiv_ceil(num_buckets, num_sub_rounds); size_t num_moves = 0; Gain round_improvement = 0; + bool increase_sub_rounds = false; for (size_t sub_round = 0; sub_round < num_sub_rounds; ++sub_round) { auto[first_bucket, last_bucket] = parallel::chunking::bounds(sub_round, num_buckets, num_buckets_per_sub_round); assert(first_bucket < last_bucket && last_bucket < permutation.bucket_bounds.size()); @@ -78,7 +79,9 @@ namespace mt_kahypar { Gain sub_round_improvement = 0; size_t num_moves_in_sub_round = moves.size(); if (num_moves_in_sub_round > 0) { - sub_round_improvement = applyMovesByMaximalPrefixesInBlockPairs(phg); + bool reverted = false; + std::tie(sub_round_improvement, reverted) = applyMovesByMaximalPrefixesInBlockPairs(phg); + increase_sub_rounds |= reverted; if (sub_round_improvement > 0 && moves.size() > 0) { if (!context.refinement.deterministic_refinement.recalculate_gains_on_second_apply) { sub_round_improvement += applyMovesSortedByGainAndRevertUnbalanced(phg); @@ -93,6 +96,9 @@ namespace mt_kahypar { overall_improvement += round_improvement; active_nodes.finalize(); + if (increase_sub_rounds) { + num_sub_rounds = std::min(num_buckets, num_sub_rounds * 2); + } if (num_moves == 0) { break; // no vertices with positive gain --> stop } @@ -266,7 +272,7 @@ namespace mt_kahypar { return gain; } - Gain DeterministicLabelPropagationRefiner::applyMovesByMaximalPrefixesInBlockPairs(PartitionedHypergraph& phg) { + std::pair DeterministicLabelPropagationRefiner::applyMovesByMaximalPrefixesInBlockPairs(PartitionedHypergraph& phg) { PartitionID k = phg.k(); PartitionID max_key = k * k; auto index = [&](PartitionID b1, PartitionID b2) { return b1 * k + b2; }; @@ -360,7 +366,8 @@ namespace mt_kahypar { moves.finalize(); // revert everything if that decreased solution quality - if (actual_gain < 0) { + bool revert_all = actual_gain < 0; + if (revert_all) { actual_gain += applyMovesIf(phg, sorted_moves, num_moves, [&](size_t pos) { if (pos < swap_prefix[index(sorted_moves[pos].from, sorted_moves[pos].to)]) { std::swap(sorted_moves[pos].from, sorted_moves[pos].to); @@ -369,12 +376,9 @@ namespace mt_kahypar { return false; } }); - - assert(actual_gain == 0); } - DBG << V(num_moves) << V(actual_gain) << V(metrics::imbalance(phg, context)); - return actual_gain; + return std::make_pair(actual_gain, revert_all); } std::pair DeterministicLabelPropagationRefiner::findBestPrefixesRecursive( diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index 4e447497b..3b67c5264 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -63,7 +63,7 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { // functions to apply moves from a sub-round Gain applyMovesSortedByGainAndRevertUnbalanced(PartitionedHypergraph& phg); - Gain applyMovesByMaximalPrefixesInBlockPairs(PartitionedHypergraph& phg); + std::pair applyMovesByMaximalPrefixesInBlockPairs(PartitionedHypergraph& phg); Gain applyMovesSortedByGainWithRecalculation(PartitionedHypergraph& phg); Gain performMoveWithAttributedGain(PartitionedHypergraph& phg, const Move& m, bool activate_neighbors); template From e06ee02c46c4f2158fb01d1fa769cf837ea1dcac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Thu, 28 Sep 2023 15:05:48 +0200 Subject: [PATCH 32/66] reorder members to fix compiler warnings (artifact of master merge) --- .../deterministic/deterministic_label_propagation.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index f0731de69..eb7585671 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -55,8 +55,8 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { const HyperedgeID num_hyperedges, const Context& context) : context(context), - cumulative_node_weights(num_hypernodes), compute_gains(context), + cumulative_node_weights(num_hypernodes), moves(num_hypernodes), sorted_moves(num_hypernodes), prng(context.partition.seed), @@ -130,8 +130,8 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { const Context& context; tbb::enumerable_thread_specific compute_gains; - ds::BufferedVector moves; vec cumulative_node_weights; + ds::BufferedVector moves; vec sorted_moves; std::mt19937 prng; From ee3f07e9b10a84cc863beab9845be2481b5a3d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Thu, 28 Sep 2023 15:17:21 +0200 Subject: [PATCH 33/66] fix double contract (merge conflict) --- .../partition/coarsening/deterministic_multilevel_coarsener.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp b/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp index b3add0c8e..7084e8811 100644 --- a/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp +++ b/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp @@ -91,8 +91,6 @@ bool DeterministicMultilevelCoarsener::coarseningPassImpl() { num_nodes -= approveVerticesInTooHeavyClusters(clusters); } - _uncoarseningData.performMultilevelContraction(std::move(clusters), pass_start_time); - ASSERT(currentNumberOfNodes() == num_nodes - hg.numRemovedHypernodes()); nodes_in_too_heavy_clusters.clear(); } From a88f063dd95921b0cea4223474cabfa5dcbc5755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Thu, 28 Sep 2023 19:00:39 +0200 Subject: [PATCH 34/66] use size_t instead of UL to appease windows --- .../deterministic/deterministic_label_propagation.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 6da608600..408d888b7 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -350,11 +350,11 @@ namespace mt_kahypar { HypernodeWeight budget_p1 = context.partition.max_part_weights[p1] - phg.partWeight(p1), budget_p2 = context.partition.max_part_weights[p2] - phg.partWeight(p2); - HypernodeWeight lb_p1 = -(budget_p1 /std::max(1UL, involvements[p1])), - ub_p2 = budget_p2 / std::max(1UL, involvements[p2]); + HypernodeWeight lb_p1 = -(budget_p1 /std::max(size_t(1), involvements[p1])), + ub_p2 = budget_p2 / std::max(size_t(1), involvements[p2]); - size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], - p2_begin = positions[index(p2, p1)], p2_end = positions[index(p2, p1) + 1]; + size_t p1_begin = positions[index(p1, p2)], p1_end = positions[index(p1, p2) + 1], + p2_begin = positions[index(p2, p1)], p2_end = positions[index(p2, p1) + 1]; auto best_prefix = findBestPrefixesRecursive(p1_begin, p1_end, p2_begin, p2_end, p1_begin - 1, p2_begin - 1, lb_p1, ub_p2); From df555e30de21846b425093a3485fcf6500afb7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Thu, 28 Sep 2023 19:32:18 +0200 Subject: [PATCH 35/66] more casts --- mt-kahypar/datastructures/static_hypergraph.cpp | 4 ++-- .../deterministic/deterministic_label_propagation.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mt-kahypar/datastructures/static_hypergraph.cpp b/mt-kahypar/datastructures/static_hypergraph.cpp index 3c7e8491d..92d87d190 100644 --- a/mt-kahypar/datastructures/static_hypergraph.cpp +++ b/mt-kahypar/datastructures/static_hypergraph.cpp @@ -375,7 +375,7 @@ namespace mt_kahypar::ds { // Compute number of hyperedges in coarse graph (those flagged as valid) parallel::TBBPrefixSum he_mapping(valid_hyperedges); tbb::parallel_invoke([&] { - tbb::parallel_scan(tbb::blocked_range(0UL, UI64(_num_hyperedges)), he_mapping); + tbb::parallel_scan(tbb::blocked_range(size_t(0), size_t(_num_hyperedges)), he_mapping); }, [&] { hypergraph._hypernodes.resize(num_hypernodes); }); @@ -395,7 +395,7 @@ namespace mt_kahypar::ds { // Compute start position of each hyperedge in incidence array parallel::TBBPrefixSum num_pins_prefix_sum(he_sizes); tbb::parallel_invoke([&] { - tbb::parallel_for(ID(0), _num_hyperedges, [&](const HyperedgeID& id) { + tbb::parallel_for(size_t(0), size_t(_num_hyperedges), [&](const HyperedgeID& id) { if ( he_mapping.value(id) ) { he_sizes[id] = tmp_hyperedges[id].size(); } else { diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 408d888b7..5dd73763f 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -325,7 +325,7 @@ namespace mt_kahypar { // swap_prefix[index(p1,p2)] stores the first position of moves to revert out of the sequence of moves from p1 to p2 vec swap_prefix(max_key, 0); - tbb::parallel_for(0UL, relevant_block_pairs.size(), [&](size_t bp_index) { + tbb::parallel_for(size_t(0), relevant_block_pairs.size(), [&](size_t bp_index) { // sort both directions by gain (alternative: gain / weight?) auto sort_by_gain_and_prefix_sum_node_weights = [&](PartitionID p1, PartitionID p2) { size_t begin = positions[index(p1, p2)], end = positions[index(p1, p2) + 1]; @@ -405,9 +405,9 @@ namespace mt_kahypar { { auto balance = [&](size_t p1_ind, size_t p2_ind) { assert(p1_ind == p1_invalid || p1_ind < p1_end); - assert(p1_ind >= p1_invalid || p1_invalid == (0UL - 1)); + assert(p1_ind >= p1_invalid || p1_invalid == (size_t(0) - 1)); assert(p2_ind == p2_invalid || p2_ind < p2_end); - assert(p2_ind >= p2_invalid || p2_invalid == (0UL - 1)); + assert(p2_ind >= p2_invalid || p2_invalid == (size_t(0) - 1)); assert(p1_ind == p1_invalid || p1_ind < cumulative_node_weights.size()); assert(p2_ind == p2_invalid || p2_ind < cumulative_node_weights.size()); const auto a = (p1_ind == p1_invalid) ? 0 : cumulative_node_weights[p1_ind]; @@ -596,7 +596,7 @@ namespace mt_kahypar { #endif // remove markers again - tbb::parallel_for(0UL, num_moves, [&](size_t pos) { move_pos_of_node[moves[pos].node] = invalid_move_id; }); + tbb::parallel_for(size_t(0), num_moves, [&](size_t pos) { move_pos_of_node[moves[pos].node] = invalid_move_id; }); // calculate number of overloaded blocks size_t num_overloaded_blocks_before_pass = 0, num_overloaded_blocks = 0; From ca9b386d9f399d5206de06ee2b4ca4bc1a45b746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Thu, 28 Sep 2023 19:59:51 +0200 Subject: [PATCH 36/66] even more casts --- mt-kahypar/datastructures/dynamic_hypergraph.cpp | 4 ++-- mt-kahypar/datastructures/pin_count_snapshot.h | 2 +- mt-kahypar/partition/context.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mt-kahypar/datastructures/dynamic_hypergraph.cpp b/mt-kahypar/datastructures/dynamic_hypergraph.cpp index 99425ce05..99afceec6 100644 --- a/mt-kahypar/datastructures/dynamic_hypergraph.cpp +++ b/mt-kahypar/datastructures/dynamic_hypergraph.cpp @@ -498,7 +498,7 @@ void DynamicHypergraph::memoryConsumption(utils::MemoryTreeNode* parent) const { parent->addChild("Incidence Array", sizeof(HypernodeID) * _incidence_array.size()); parent->addChild("Hyperedge Ownership Vector", sizeof(bool) * _acquired_hes.size()); parent->addChild("Bitsets", - ( _num_hyperedges * _he_bitset.size() ) / 8UL + sizeof(uint16_t) * _num_hyperedges); + ( _num_hyperedges * _he_bitset.size() ) / size_t(8) + sizeof(uint16_t) * _num_hyperedges); utils::MemoryTreeNode* contraction_tree_node = parent->addChild("Contraction Tree"); _contraction_tree.memoryConsumption(contraction_tree_node); @@ -763,4 +763,4 @@ BatchVector DynamicHypergraph::createBatchUncontractionHierarchyForVersion(Batch } } // namespace ds -} // namespace mt_kahypar \ No newline at end of file +} // namespace mt_kahypar diff --git a/mt-kahypar/datastructures/pin_count_snapshot.h b/mt-kahypar/datastructures/pin_count_snapshot.h index f1fd911e1..ce16c19f0 100644 --- a/mt-kahypar/datastructures/pin_count_snapshot.h +++ b/mt-kahypar/datastructures/pin_count_snapshot.h @@ -151,7 +151,7 @@ class PinCountSnapshot { static size_t num_entries_per_value(const PartitionID k, const HypernodeID max_value) { const size_t bits_per_element = num_bits_per_element(max_value); - const size_t bits_per_value = sizeof(Value) * 8UL; + const size_t bits_per_value = sizeof(Value) * size_t(8); ASSERT(bits_per_element <= bits_per_value); return std::min(bits_per_value / bits_per_element, static_cast(k)); } diff --git a/mt-kahypar/partition/context.cpp b/mt-kahypar/partition/context.cpp index 63874ae56..0ed6eef6e 100644 --- a/mt-kahypar/partition/context.cpp +++ b/mt-kahypar/partition/context.cpp @@ -352,7 +352,7 @@ namespace mt_kahypar { partition.max_part_weights.size()); } - shared_memory.static_balancing_work_packages = std::clamp(shared_memory.static_balancing_work_packages, 4UL, 256UL); + shared_memory.static_balancing_work_packages = std::clamp(shared_memory.static_balancing_work_packages, size_t(4), size_t(256)); if ( partition.objective == Objective::steiner_tree ) { if ( !target_graph ) { From 96a5a2d004946223a4ab45e847383996f3736fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 10:15:32 +0200 Subject: [PATCH 37/66] [Gain computation] Fix check whether we should look at non-adjacent blocks --- mt-kahypar/partition/refinement/gains/gain_computation_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/partition/refinement/gains/gain_computation_base.h b/mt-kahypar/partition/refinement/gains/gain_computation_base.h index 6f8856854..dc2dea4ec 100644 --- a/mt-kahypar/partition/refinement/gains/gain_computation_base.h +++ b/mt-kahypar/partition/refinement/gains/gain_computation_base.h @@ -99,7 +99,7 @@ class GainComputationBase { } } - if ( consider_non_adjacent_blocks && best_move.from == from ) { + if ( consider_non_adjacent_blocks && best_move.to == from ) { // This is important for our rebalancer as the last fallback strategy vec non_adjacent_block; for ( PartitionID to = 0; to < _context.partition.k; ++to ) { From 406f52a21a1b827423b07c9cdc52435b1d2b957f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 10:20:06 +0200 Subject: [PATCH 38/66] [Gain computation] Remove thread_local member _isolated_block_gain that can just be a stack-local variable --- .../partition/refinement/gains/gain_computation_base.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/mt-kahypar/partition/refinement/gains/gain_computation_base.h b/mt-kahypar/partition/refinement/gains/gain_computation_base.h index dc2dea4ec..dd7833630 100644 --- a/mt-kahypar/partition/refinement/gains/gain_computation_base.h +++ b/mt-kahypar/partition/refinement/gains/gain_computation_base.h @@ -46,7 +46,6 @@ class GainComputationBase { public: using RatingMap = ds::SparseMap; using TmpScores = tbb::enumerable_thread_specific; - using Penalty = tbb::enumerable_thread_specific; GainComputationBase(const Context& context, const bool disable_randomization) : @@ -55,8 +54,7 @@ class GainComputationBase { _deltas(0), _tmp_scores([&] { return constructLocalTmpScores(); - }), - _isolated_block_gain(0) { } + }) { } template Move computeMaxGainMove(const PartitionedHypergraph& phg, @@ -66,7 +64,7 @@ class GainComputationBase { const bool allow_imbalance = false) { Derived* derived = static_cast(this); RatingMap& tmp_scores = _tmp_scores.local(); - Gain& isolated_block_gain = _isolated_block_gain.local(); + Gain isolated_block_gain = 0; derived->precomputeGains(phg, hn, tmp_scores, isolated_block_gain, consider_non_adjacent_blocks); PartitionID from = phg.partID(hn); @@ -120,7 +118,6 @@ class GainComputationBase { } } - isolated_block_gain = 0; tmp_scores.clear(); return best_move; } @@ -172,7 +169,6 @@ class GainComputationBase { const bool _disable_randomization; DeltaGain _deltas; TmpScores _tmp_scores; - Penalty _isolated_block_gain; }; } // namespace mt_kahypar From fa538920648b48376db1f9b946b8000cf4e0e06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:08:20 +0200 Subject: [PATCH 39/66] implement other gain types for deterministic label prop refiner --- mt-kahypar/partition/factories.h | 2 +- .../deterministic_label_propagation.cpp | 72 +++++++++++-------- .../deterministic_label_propagation.h | 26 +------ .../register_refinement_algorithms.cpp | 4 +- 4 files changed, 48 insertions(+), 56 deletions(-) diff --git a/mt-kahypar/partition/factories.h b/mt-kahypar/partition/factories.h index a39026dad..feb0f1323 100644 --- a/mt-kahypar/partition/factories.h +++ b/mt-kahypar/partition/factories.h @@ -93,7 +93,7 @@ using LabelPropagationDispatcher = kahypar::meta::StaticMultiDispatchFactory< using DeterministicLabelPropagationDispatcher = kahypar::meta::StaticMultiDispatchFactory< DeterministicLabelPropagationRefiner, IRefiner, - kahypar::meta::Typelist>; + kahypar::meta::Typelist>; using FMFactory = kahypar::meta::Factory; diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 5dd73763f..02b57f83b 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -32,14 +32,16 @@ #include "mt-kahypar/parallel/chunking.h" #include "mt-kahypar/parallel/parallel_counting_sort.h" #include "mt-kahypar/utils/cast.h" +#include "mt-kahypar/partition/refinement/gains/gain_definitions.h" #include #include namespace mt_kahypar { - template - bool DeterministicLabelPropagationRefiner::refineImpl( + + template + bool DeterministicLabelPropagationRefiner::refineImpl( mt_kahypar_partitioned_hypergraph_t& hypergraph, const vec&, Metrics& best_metrics, @@ -49,6 +51,9 @@ namespace mt_kahypar { constexpr size_t num_buckets = utils::ParallelPermutation::num_buckets; size_t num_sub_rounds = context.refinement.deterministic_refinement.num_sub_rounds_sync_lp; + using GainComputation = typename GainTypes::GainComputation; + GainComputation gain_computation(context); + for (size_t iter = 0; iter < context.refinement.label_propagation.maximum_iterations; ++iter) { if (context.refinement.deterministic_refinement.use_active_node_set && ++round == 0) { std::fill(last_moved_in_round.begin(), last_moved_in_round.end(), CAtomic(0)); @@ -70,22 +75,23 @@ namespace mt_kahypar { bool increase_sub_rounds = false; for (size_t sub_round = 0; sub_round < num_sub_rounds; ++sub_round) { auto[first_bucket, last_bucket] = parallel::chunking::bounds(sub_round, num_buckets, num_buckets_per_sub_round); - assert(first_bucket < last_bucket && last_bucket < permutation.bucket_bounds.size()); + ASSERT(first_bucket < last_bucket && last_bucket < permutation.bucket_bounds.size()); size_t first = permutation.bucket_bounds[first_bucket], last = permutation.bucket_bounds[last_bucket]; moves.clear(); // calculate moves - if (phg.k() == 2) { - tbb::parallel_for(HypernodeID(first), HypernodeID(last), [&](const HypernodeID position) { - assert(position < permutation.permutation.size()); - calculateAndSaveBestMoveTwoWay(phg, permutation.at(position)); - }); - } else { - tbb::parallel_for(HypernodeID(first), HypernodeID(last), [&](const HypernodeID position) { - assert(position < permutation.permutation.size()); - calculateAndSaveBestMove(phg, permutation.at(position)); - }); - } + tbb::parallel_for(HypernodeID(first), HypernodeID(last), [&](const HypernodeID position) { + ASSERT(position < permutation.permutation.size()); + const HypernodeID u = permutation.at(position); + ASSERT(u < phg.initialNumNodes()); + if (!phg.nodeIsEnabled(u) || !phg.isBorderNode(u)) return; + Move move = gain_computation.computeMaxGainMove(phg, u, /*rebalance=*/false, /*consider_non_adjacent_blocks=*/false, /*allow_imbalance=*/true); + move.gain = -move.gain; + if (move.gain > 0 && move.to != phg.partID(u)) { + moves.push_back_buffered(move); + } + }); + moves.finalize(); Gain sub_round_improvement = 0; @@ -127,12 +133,13 @@ namespace mt_kahypar { /* * for configs where we don't know exact gains --> have to trace the overall improvement with attributed gains */ - template - Gain DeterministicLabelPropagationRefiner::performMoveWithAttributedGain( + template + Gain DeterministicLabelPropagationRefiner::performMoveWithAttributedGain( PartitionedHypergraph& phg, const Move& m, bool activate_neighbors) { Gain attributed_gain = 0; auto objective_delta = [&](const SynchronizedEdgeUpdate& sync_update) { - attributed_gain -= Km1AttributedGains::gain(sync_update); + using AttributedGains = typename GainTypes::AttributedGains; + attributed_gain -= AttributedGains::gain(sync_update); }; const bool was_moved = phg.changeNodePart(m.node, m.from, m.to, objective_delta); if (context.refinement.deterministic_refinement.use_active_node_set && activate_neighbors && was_moved) { @@ -156,9 +163,9 @@ namespace mt_kahypar { return attributed_gain; } - template + template template - Gain DeterministicLabelPropagationRefiner::applyMovesIf( + Gain DeterministicLabelPropagationRefiner::applyMovesIf( PartitionedHypergraph& phg, const vec& my_moves, size_t end, Predicate&& predicate) { auto range = tbb::blocked_range(UL(0), end); auto accum = [&](const tbb::blocked_range& r, const Gain& init) -> Gain { @@ -196,8 +203,8 @@ namespace mt_kahypar { return res; } - template - Gain DeterministicLabelPropagationRefiner::applyMovesSortedByGainAndRevertUnbalanced(PartitionedHypergraph& phg) { + template + Gain DeterministicLabelPropagationRefiner::applyMovesSortedByGainAndRevertUnbalanced(PartitionedHypergraph& phg) { const size_t num_moves = moves.size(); tbb::parallel_sort(moves.begin(), moves.begin() + num_moves, [](const Move& m1, const Move& m2) { return m1.gain > m2.gain || (m1.gain == m2.gain && m1.node < m2.node); @@ -287,8 +294,8 @@ namespace mt_kahypar { return gain; } - template - std::pair DeterministicLabelPropagationRefiner::applyMovesByMaximalPrefixesInBlockPairs(PartitionedHypergraph& phg) { + template + std::pair DeterministicLabelPropagationRefiner::applyMovesByMaximalPrefixesInBlockPairs(PartitionedHypergraph& phg) { PartitionID k = phg.k(); PartitionID max_key = k * k; auto index = [&](PartitionID b1, PartitionID b2) { return b1 * k + b2; }; @@ -397,8 +404,8 @@ namespace mt_kahypar { return std::make_pair(actual_gain, revert_all); } - template - std::pair DeterministicLabelPropagationRefiner::findBestPrefixesRecursive( + template + std::pair DeterministicLabelPropagationRefiner::findBestPrefixesRecursive( size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, size_t p1_invalid, size_t p2_invalid, HypernodeWeight lb_p1, HypernodeWeight ub_p2) @@ -473,8 +480,8 @@ namespace mt_kahypar { } } - template - std::pair DeterministicLabelPropagationRefiner::findBestPrefixesSequentially( + template + std::pair DeterministicLabelPropagationRefiner::findBestPrefixesSequentially( size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, size_t p1_inv, size_t p2_inv, HypernodeWeight lb_p1, HypernodeWeight ub_p2) { @@ -502,8 +509,8 @@ namespace mt_kahypar { return std::make_pair(invalid_pos, invalid_pos); } - template - Gain DeterministicLabelPropagationRefiner::applyMovesSortedByGainWithRecalculation(PartitionedHypergraph& phg) { + template + Gain DeterministicLabelPropagationRefiner::applyMovesSortedByGainWithRecalculation(PartitionedHypergraph& phg) { if (last_recalc_round.empty() || ++recalc_round == std::numeric_limits::max()) { last_recalc_round.assign(max_num_edges, CAtomic(0)); } @@ -635,5 +642,10 @@ namespace mt_kahypar { return best_gain; } - INSTANTIATE_CLASS_WITH_TYPE_TRAITS(DeterministicLabelPropagationRefiner) + namespace { + #define DETERMINISTIC_LABEL_PROPAGATION_REFINER(X, Y) DeterministicLabelPropagationRefiner + } + + + INSTANTIATE_CLASS_WITH_TYPE_TRAITS_AND_GAIN_TYPES(DETERMINISTIC_LABEL_PROPAGATION_REFINER) } // namespace mt_kahypar diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index eb7585671..3c462c453 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -38,7 +38,7 @@ namespace mt_kahypar { -template +template class DeterministicLabelPropagationRefiner final : public IRefiner { using PartitionedHypergraph = typename TypeTraits::PartitionedHypergraph; @@ -55,7 +55,6 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { const HyperedgeID num_hyperedges, const Context& context) : context(context), - compute_gains(context), cumulative_node_weights(num_hypernodes), moves(num_hypernodes), sorted_moves(num_hypernodes), @@ -98,26 +97,6 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, size_t p1_inv, size_t p2_inv, HypernodeWeight lb_p1, HypernodeWeight ub_p2); - MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE - void calculateAndSaveBestMove(PartitionedHypergraph& phg, HypernodeID u) { - assert(u < phg.initialNumNodes()); - if (!phg.nodeIsEnabled(u) || !phg.isBorderNode(u)) return; - //auto [to, gain] = compute_gains.local().computeBestTargetBlock(phg, u, context.partition.max_part_weights); - auto [to, gain] = compute_gains.local().computeBestTargetBlockIgnoringBalance(phg, u); - if (gain > 0 && to != kInvalidPartition) { // depending on apply moves function we might do gain >= 0 - moves.push_back_buffered( { phg.partID(u), to, u, gain } ); - } - } - - MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE - void calculateAndSaveBestMoveTwoWay(PartitionedHypergraph& phg, HypernodeID u) { - if (!phg.nodeIsEnabled(u) || !phg.isBorderNode(u)) return; - const Gain gain = TwoWayGainComputer::gainToOtherBlock(phg, u); - if (gain > 0) { - moves.push_back_buffered({ phg.partID(u), 1 - phg.partID(u), u, gain }); - } - } - struct RecalculationData { MoveID first_in, last_out; HypernodeID remaining_pins; @@ -129,13 +108,12 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { }; const Context& context; - tbb::enumerable_thread_specific compute_gains; vec cumulative_node_weights; ds::BufferedVector moves; vec sorted_moves; std::mt19937 prng; - utils::ParallelPermutation permutation; // gets memory only once used + utils::ParallelPermutation permutation; ds::BufferedVector active_nodes; vec> last_moved_in_round; uint32_t round = 0; diff --git a/mt-kahypar/partition/registries/register_refinement_algorithms.cpp b/mt-kahypar/partition/registries/register_refinement_algorithms.cpp index 9a3684030..6c727591f 100644 --- a/mt-kahypar/partition/registries/register_refinement_algorithms.cpp +++ b/mt-kahypar/partition/registries/register_refinement_algorithms.cpp @@ -143,7 +143,9 @@ REGISTER_DISPATCHED_LP_REFINER(LabelPropagationAlgorithm::label_propagation, REGISTER_DISPATCHED_LP_REFINER(LabelPropagationAlgorithm::deterministic, DeterministicLabelPropagationDispatcher, kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); + context.partition.partition_type), + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.gain_policy)); REGISTER_LP_REFINER(LabelPropagationAlgorithm::do_nothing, DoNothingRefiner, 1); REGISTER_DISPATCHED_FM_REFINER(FMAlgorithm::kway_fm, From 4ec9df9a04cd47f82f370f1f8858dec5ffca48ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:14:34 +0200 Subject: [PATCH 40/66] remove old hand-rolled gain computation --- .../deterministic_label_propagation.cpp | 1 - .../deterministic_label_propagation.h | 1 - .../refinement/fm/strategies/km1_gains.h | 143 ---------------- tests/partition/refinement/CMakeLists.txt | 2 - tests/partition/refinement/gain_test.cc | 158 ------------------ 5 files changed, 305 deletions(-) delete mode 100644 mt-kahypar/partition/refinement/fm/strategies/km1_gains.h delete mode 100644 tests/partition/refinement/gain_test.cc diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 02b57f83b..d0db4551e 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -28,7 +28,6 @@ #include "mt-kahypar/definitions.h" #include "mt-kahypar/partition/metrics.h" -#include "mt-kahypar/partition/refinement/gains/km1/km1_attributed_gains.h" #include "mt-kahypar/parallel/chunking.h" #include "mt-kahypar/parallel/parallel_counting_sort.h" #include "mt-kahypar/utils/cast.h" diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index 3c462c453..07c7dbe94 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -32,7 +32,6 @@ #include "mt-kahypar/partition/refinement/i_refiner.h" #include "mt-kahypar/partition/refinement/i_rebalancer.h" -#include "mt-kahypar/partition/refinement/fm/strategies/km1_gains.h" #include "mt-kahypar/partition/refinement/gains/gain_cache_ptr.h" #include "mt-kahypar/utils/reproducible_random.h" diff --git a/mt-kahypar/partition/refinement/fm/strategies/km1_gains.h b/mt-kahypar/partition/refinement/fm/strategies/km1_gains.h deleted file mode 100644 index efb5f0bac..000000000 --- a/mt-kahypar/partition/refinement/fm/strategies/km1_gains.h +++ /dev/null @@ -1,143 +0,0 @@ -/******************************************************************************* - * MIT License - * - * This file is part of Mt-KaHyPar. - * - * Copyright (C) 2020 Lars Gottesbüren - * - * 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 "mt-kahypar/datastructures/hypergraph_common.h" - -namespace mt_kahypar { -struct Km1GainComputer { - Km1GainComputer(const Context& context) : - context(context), - gains(context.partition.k, 0) { } - - template - MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE - void computeGains(const PHG& phg, const HypernodeID u) { - clear(); - Gain internal_weight = computeGainsPlusInternalWeight(phg, u); - for (Gain& x : gains) { x -= internal_weight; } - } - - template - MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE - Gain computeGainsPlusInternalWeight(const PHG& phg, const HypernodeID u) { - assert(std::all_of(gains.begin(), gains.end(), [](const Gain& g) { return g == 0; })); - const PartitionID from = phg.partID(u); - Gain internal_weight = 0; // weight that will not be removed from the objective - for (HyperedgeID e : phg.incidentEdges(u)) { - HyperedgeWeight edge_weight = phg.edgeWeight(e); - if (phg.pinCountInPart(e, from) > 1) { - internal_weight += edge_weight; - } - - if constexpr (PHG::supports_connectivity_set) { - for (PartitionID i : phg.connectivitySet(e)) { - gains[i] += edge_weight; - } - } else { - // case for deltaPhg since maintaining connectivity sets is too slow - for (PartitionID i = 0; i < context.partition.k; ++i) { - if (phg.pinCountInPart(e, i) > 0) { - gains[i] += edge_weight; - } - } - } - } - return internal_weight; - } - - void clear() { - std::fill(gains.begin(), gains.end(), 0); - } - - template - MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE - std::pair computeBestTargetBlock(const PHG& phg, - const HypernodeID u, - const std::vector& max_part_weights) { - const HypernodeWeight weight_of_u = phg.nodeWeight(u); - const PartitionID from = phg.partID(u); - const Gain internal_weight = computeGainsPlusInternalWeight(phg, u); - PartitionID best_target = kInvalidPartition; - HypernodeWeight best_target_weight = std::numeric_limits::max(); - Gain best_gain = std::numeric_limits::min(); - for (PartitionID target = 0; target < context.partition.k; ++target) { - if (target != from) { - const HypernodeWeight target_weight = phg.partWeight(target); - const Gain gain = gains[target]; - if ( (gain > best_gain || (gain == best_gain && target_weight < best_target_weight)) - && target_weight + weight_of_u <= max_part_weights[target]) { - best_target = target; - best_gain = gain; - best_target_weight = target_weight; - } - } - gains[target] = 0; - } - - best_gain -= internal_weight; - return std::make_pair(best_target, best_gain); - } - - template - std::pair computeBestTargetBlockIgnoringBalance(const PHG& phg, - const HypernodeID u) { - const PartitionID from = phg.partID(u); - const Gain internal_weight = computeGainsPlusInternalWeight(phg, u); - PartitionID best_target = kInvalidPartition; - Gain best_gain = std::numeric_limits::min(); - for (PartitionID target = 0; target < context.partition.k; ++target) { - if (target != from && gains[target] > best_gain) { - best_gain = gains[target]; - best_target = target; - } - gains[target] = 0; - } - best_gain -= internal_weight; - return std::make_pair(best_target, best_gain); - } - - const Context& context; - vec gains; -}; - -struct TwoWayGainComputer { - template - static Gain gainToOtherBlock(const PHG& phg, const HypernodeID u) { - Gain gain = 0; - const PartitionID from = phg.partID(u); - for (HyperedgeID e : phg.incidentEdges(u)) { - const auto pcip = phg.pinCountInPart(e, from); - const auto weight = phg.edgeWeight(e); - if (pcip == 1) { gain += weight; } - else if (pcip == phg.edgeSize(e)) { gain -= weight; } - } - return gain; - } -}; - -} \ No newline at end of file diff --git a/tests/partition/refinement/CMakeLists.txt b/tests/partition/refinement/CMakeLists.txt index e8377c144..fd4b6aa1f 100644 --- a/tests/partition/refinement/CMakeLists.txt +++ b/tests/partition/refinement/CMakeLists.txt @@ -10,10 +10,8 @@ target_sources(mt_kahypar_tests PRIVATE rebalance_test.cc advanced_rebalancer_test.cc twoway_fm_refiner_test.cc - gain_test.cc gain_cache_test.cc multitry_fm_test.cc fm_strategy_test.cc flow_construction_test.cc ) - diff --git a/tests/partition/refinement/gain_test.cc b/tests/partition/refinement/gain_test.cc deleted file mode 100644 index f6919a88b..000000000 --- a/tests/partition/refinement/gain_test.cc +++ /dev/null @@ -1,158 +0,0 @@ -/******************************************************************************* - * MIT License - * - * This file is part of Mt-KaHyPar. - * - * Copyright (C) 2020 Lars Gottesbüren - * - * 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 "tests/datastructures/hypergraph_fixtures.h" -#include "mt-kahypar/definitions.h" -#include "mt-kahypar/partition/context.h" - -#include "mt-kahypar/partition/refinement/fm/strategies/km1_gains.h" - -using ::testing::Test; - -namespace mt_kahypar { - -namespace { - using Hypergraph = typename StaticHypergraphTypeTraits::Hypergraph; - using PartitionedHypergraph = typename StaticHypergraphTypeTraits::PartitionedHypergraph; -} - -template -class GainComputerTest : public Test { - - using HypergraphFactory = typename Hypergraph::Factory; - -public: - GainComputerTest() : - hg(HypergraphFactory::construct(7, 4, - {{0, 2}, - {0, 1, 3, 4}, - {3, 4, 6}, - {2, 5, 6}})), - context(), - gain(nullptr) { - context.partition.k = K; - context.partition.max_part_weights.assign(K, std::numeric_limits::max()); - phg = PartitionedHypergraph(K, hg, parallel_tag_t()); - gain = std::make_unique(context); - } - - void assignPartitionIDs(const std::vector& part_ids) { - HypernodeID hn = 0; - for (const PartitionID& part : part_ids) { - ASSERT(part < K); - phg.setNodePart(hn++, part); - } - } - - Hypergraph hg; - PartitionedHypergraph phg; - Context context; - std::unique_ptr gain; -}; - -using Km1GainsK2 = GainComputerTest<2>; - -TEST_F(Km1GainsK2, ComputesCorrectMoveGainForVertex1) { - assignPartitionIDs({1, 0, 0, 0, 0, 1, 1}); - auto [to, g] = gain->computeBestTargetBlock(phg, 0, context.partition.max_part_weights); - ASSERT_EQ(0, to); - ASSERT_EQ(2, g); -} - - -TEST_F(Km1GainsK2, ComputesCorrectMoveGainForVertex2) { - assignPartitionIDs({0, 0, 0, 1, 0, 1, 1}); - auto [to, g] = gain->computeBestTargetBlock(phg, 3, context.partition.max_part_weights); - ASSERT_EQ(0, to); - ASSERT_EQ(1, g); -} - - -TEST_F(Km1GainsK2, ComputesCorrectMoveGainForVertex3) { - assignPartitionIDs({0, 0, 0, 0, 0, 1, 1}); - auto [to, g] = gain->computeBestTargetBlock(phg, 4, context.partition.max_part_weights); - ASSERT_EQ(1, to); - ASSERT_EQ(-1, g); // computeBestTarget block will select negative gain moves! -} - - - -using Km1GainsK4 = GainComputerTest<4>; - -TEST_F(Km1GainsK4, ComputesCorrectMoveGainForVertex1) { - assignPartitionIDs({0, 1, 2, 3, 3, 1, 2}); - auto [to, g] = gain->computeBestTargetBlock(phg, 0, context.partition.max_part_weights); - - gain->computeGains(phg, 0); - ASSERT_EQ(gain->gains[1], 1); - ASSERT_EQ(gain->gains[2], 1); - ASSERT_EQ(gain->gains[3], 1); - - ASSERT_EQ(1, to); // all target blocks have equal weight --> take the first - ASSERT_EQ(1, g); -} - - -TEST_F(Km1GainsK4, ComputesCorrectMoveGainForVertex2) { - assignPartitionIDs({0, 3, 1, 2, 2, 0, 3}); - auto [to, g] = gain->computeBestTargetBlock(phg, 6, context.partition.max_part_weights); - - gain->computeGains(phg, 6); - ASSERT_EQ(gain->gains[0], 1); - ASSERT_EQ(gain->gains[1], 1); - ASSERT_EQ(gain->gains[2], 1); - ASSERT_EQ(1, to); // block 1 is lighter than block 0 - ASSERT_EQ(1, g); - - gain->clear(); - std::tie(to, g) = gain->computeBestTargetBlock(phg, 2, context.partition.max_part_weights); - - gain->computeGains(phg, 2); - ASSERT_EQ(gain->gains[0], 2); - ASSERT_EQ(gain->gains[2], 0); - ASSERT_EQ(gain->gains[3], 1); - - ASSERT_EQ(to, 0); - ASSERT_EQ(g, 2); -} - - -TEST_F(Km1GainsK4, ComputesCorrectMoveGainForVertex3) { - assignPartitionIDs({0, 3, 1, 2, 2, 0, 3}); - auto [to, g] = gain->computeBestTargetBlock(phg, 3, context.partition.max_part_weights); - - gain->computeGains(phg, 3); - ASSERT_EQ(gain->gains[0], -1); - ASSERT_EQ(gain->gains[1], -2); - ASSERT_EQ(gain->gains[3], 0); - - ASSERT_EQ(3, to); - ASSERT_EQ(0, g); -} - -} // namespace \ No newline at end of file From 96642addaa3fce93b2ee051b69fdc93d7102d16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:15:27 +0200 Subject: [PATCH 41/66] add fixed vertex support --- .../deterministic/deterministic_label_propagation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index d0db4551e..3817f7c83 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -83,7 +83,7 @@ namespace mt_kahypar { ASSERT(position < permutation.permutation.size()); const HypernodeID u = permutation.at(position); ASSERT(u < phg.initialNumNodes()); - if (!phg.nodeIsEnabled(u) || !phg.isBorderNode(u)) return; + if (phg.isFixedVertex(u) || !phg.nodeIsEnabled(u) || !phg.isBorderNode(u)) return; Move move = gain_computation.computeMaxGainMove(phg, u, /*rebalance=*/false, /*consider_non_adjacent_blocks=*/false, /*allow_imbalance=*/true); move.gain = -move.gain; if (move.gain > 0 && move.to != phg.partID(u)) { From e1a9d648ec58c5ca82adaaa5eaba3cf3da59e2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:17:24 +0200 Subject: [PATCH 42/66] call correct fixed vertex function... --- .../deterministic/deterministic_label_propagation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 3817f7c83..f5b60e10d 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -83,7 +83,7 @@ namespace mt_kahypar { ASSERT(position < permutation.permutation.size()); const HypernodeID u = permutation.at(position); ASSERT(u < phg.initialNumNodes()); - if (phg.isFixedVertex(u) || !phg.nodeIsEnabled(u) || !phg.isBorderNode(u)) return; + if (phg.isFixed(u) || !phg.nodeIsEnabled(u) || !phg.isBorderNode(u)) return; Move move = gain_computation.computeMaxGainMove(phg, u, /*rebalance=*/false, /*consider_non_adjacent_blocks=*/false, /*allow_imbalance=*/true); move.gain = -move.gain; if (move.gain > 0 && move.to != phg.partID(u)) { From d491f82cb80e843b8242847755e0e486f9d590ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:20:38 +0200 Subject: [PATCH 43/66] remove deterministic applyMoves with fancy gain recalculation --- mt-kahypar/io/command_line_options.cpp | 5 - mt-kahypar/partition/context.cpp | 2 - mt-kahypar/partition/context.h | 1 - .../deterministic_label_propagation.cpp | 139 +----------------- .../deterministic_label_propagation.h | 14 -- 5 files changed, 1 insertion(+), 160 deletions(-) diff --git a/mt-kahypar/io/command_line_options.cpp b/mt-kahypar/io/command_line_options.cpp index df8feb289..1ce9f1d71 100644 --- a/mt-kahypar/io/command_line_options.cpp +++ b/mt-kahypar/io/command_line_options.cpp @@ -368,11 +368,6 @@ namespace mt_kahypar { &context.initial_partitioning.refinement.deterministic_refinement.use_active_node_set))->value_name( "")->default_value(true), "Use active nodeset in synchronous label propagation") - ((initial_partitioning ? "i-r-sync-lp-recalculate-gains-on-second-apply" : "r-sync-lp-recalculate-gains-on-second-apply"), - po::value((!initial_partitioning ? &context.refinement.deterministic_refinement.recalculate_gains_on_second_apply : - &context.initial_partitioning.refinement.deterministic_refinement.recalculate_gains_on_second_apply))->value_name( - "")->default_value(false), - "Recalculate gains for second attempt at applying moves in synchronous label propagation") ((initial_partitioning ? "i-r-lp-rebalancing" : "r-lp-rebalancing"), po::value((!initial_partitioning ? &context.refinement.label_propagation.rebalancing : &context.initial_partitioning.refinement.label_propagation.rebalancing))->value_name( diff --git a/mt-kahypar/partition/context.cpp b/mt-kahypar/partition/context.cpp index 0ed6eef6e..9099047f3 100644 --- a/mt-kahypar/partition/context.cpp +++ b/mt-kahypar/partition/context.cpp @@ -183,8 +183,6 @@ namespace mt_kahypar { std::ostream& operator<<(std::ostream& out, const DeterministicRefinementParameters& params) { out << " Number of sub-rounds for Sync LP: " << params.num_sub_rounds_sync_lp << std::endl; out << " Use active node set: " << std::boolalpha << params.use_active_node_set << std::endl; - out << " recalculate gains on second apply: " << std::boolalpha - << params.recalculate_gains_on_second_apply << std::endl; return out; } diff --git a/mt-kahypar/partition/context.h b/mt-kahypar/partition/context.h index c6b59f98a..35d2ea97d 100644 --- a/mt-kahypar/partition/context.h +++ b/mt-kahypar/partition/context.h @@ -206,7 +206,6 @@ std::ostream& operator<<(std::ostream& out, const FlowParameters& params); struct DeterministicRefinementParameters { size_t num_sub_rounds_sync_lp = 5; bool use_active_node_set = false; - bool recalculate_gains_on_second_apply = false; }; std::ostream& operator<<(std::ostream& out, const DeterministicRefinementParameters& params); diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index f5b60e10d..db748038d 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -100,11 +100,7 @@ namespace mt_kahypar { std::tie(sub_round_improvement, reverted) = applyMovesByMaximalPrefixesInBlockPairs(phg); increase_sub_rounds |= reverted; if (sub_round_improvement > 0 && moves.size() > 0) { - if (!context.refinement.deterministic_refinement.recalculate_gains_on_second_apply) { - sub_round_improvement += applyMovesSortedByGainAndRevertUnbalanced(phg); - } else { - sub_round_improvement += applyMovesSortedByGainWithRecalculation(phg); - } + sub_round_improvement += applyMovesSortedByGainAndRevertUnbalanced(phg); } } round_improvement += sub_round_improvement; @@ -508,139 +504,6 @@ namespace mt_kahypar { return std::make_pair(invalid_pos, invalid_pos); } - template - Gain DeterministicLabelPropagationRefiner::applyMovesSortedByGainWithRecalculation(PartitionedHypergraph& phg) { - if (last_recalc_round.empty() || ++recalc_round == std::numeric_limits::max()) { - last_recalc_round.assign(max_num_edges, CAtomic(0)); - } - constexpr MoveID invalid_move_id = std::numeric_limits::max(); - if (move_pos_of_node.empty()) { - move_pos_of_node.resize(max_num_nodes, invalid_move_id); - } - - const size_t num_moves = moves.size(); - tbb::parallel_sort(moves.begin(), moves.begin() + num_moves, [](const Move& m1, const Move& m2) { - return m1.gain > m2.gain || (m1.gain == m2.gain && m1.node < m2.node); - }); - - tbb::parallel_for(UL(0), num_moves, [&](size_t pos) { - move_pos_of_node[moves[pos].node] = pos + 1; // pos + 1 to handle zero init of last_out - moves[pos].gain = 0; - }); - - auto was_node_moved_in_this_round = [&](HypernodeID u) { return move_pos_of_node[u] != invalid_move_id; }; - - // recalculate gains - tbb::parallel_for(UL(0), num_moves, [&](size_t pos) { - auto& r = ets_recalc_data.local(); - - HypernodeID u = moves[pos].node; - for (HyperedgeID e : phg.incidentEdges(u)) { - uint32_t expected = last_recalc_round[e].load(std::memory_order_relaxed); - if (expected < recalc_round && last_recalc_round[e].exchange(recalc_round, std::memory_order_acq_rel) == expected) { - for (HypernodeID v : phg.pins(e)) { - if (was_node_moved_in_this_round(v)) { - const MoveID m_id = move_pos_of_node[v]; - const Move& m = moves[m_id - 1]; - r[m.to].first_in = std::min(r[m.to].first_in, m_id); - r[m.from].last_out = std::max(r[m.from].last_out, m_id); - } else { - r[phg.partID(v)].remaining_pins++; - } - } - - const HyperedgeWeight we = phg.edgeWeight(e); - for (HypernodeID v : phg.pins(e)) { - if (was_node_moved_in_this_round(v)) { - const MoveID m_id = move_pos_of_node[v]; - Move& m = moves[m_id - 1]; - const bool benefit = r[m.from].last_out == m_id && r[m.from].first_in > m_id && r[m.from].remaining_pins == 0; - const bool penalty = r[m.to].first_in == m_id && r[m.to].last_out < m_id && r[m.to].remaining_pins == 0; - if (benefit && !penalty) { - __atomic_fetch_add(&m.gain, we, __ATOMIC_RELAXED); - } - if (!benefit && penalty) { - __atomic_fetch_sub(&m.gain, we, __ATOMIC_RELAXED); - } - } - } - - if (phg.k() <= static_cast(2 * phg.edgeSize(e))) { - for (PartitionID i = 0; i < phg.k(); ++i) { - r[i] = RecalculationData(); - } - } else { - for (HypernodeID v : phg.pins(e)) { - if (was_node_moved_in_this_round(v)) { - const Move& m = moves[move_pos_of_node[v] - 1]; - r[m.from] = RecalculationData(); - r[m.to] = RecalculationData(); - } else { - r[phg.partID(v)] = RecalculationData(); - } - } - } - } - } - }); - -#ifndef NDEBUG - for (size_t pos = 0; pos < num_moves; ++pos) { - const Move& m = moves[pos]; - Gain move_gain = performMoveWithAttributedGain(phg, m, false); - unused(move_gain); - ASSERT(move_gain == m.gain); - } - - for (int64_t pos = num_moves - 1; pos >= 0; --pos) { - Move reverse_move = moves[pos]; - std::swap(reverse_move.from, reverse_move.to); - Gain move_gain = performMoveWithAttributedGain(phg, reverse_move, false); - unused(move_gain); - ASSERT(move_gain == -moves[pos].gain); - } -#endif - - // remove markers again - tbb::parallel_for(size_t(0), num_moves, [&](size_t pos) { move_pos_of_node[moves[pos].node] = invalid_move_id; }); - - // calculate number of overloaded blocks - size_t num_overloaded_blocks_before_pass = 0, num_overloaded_blocks = 0; - const auto& max_part_weights = context.partition.max_part_weights; - vec part_weights(phg.k()); - for (PartitionID i = 0; i < phg.k(); ++i) { - part_weights[i] = phg.partWeight(i); - if (part_weights[i] > max_part_weights[i]) { - num_overloaded_blocks_before_pass++; - } - } - num_overloaded_blocks = num_overloaded_blocks_before_pass; - - // prefix sum part weights and gains. (might incorporate parallel version if this takes too long) - Gain best_gain = 0, gain_sum = 0; - size_t best_index = 0; - for (size_t pos = 0; pos < num_moves; ++pos) { - const Move& m = moves[pos]; - num_overloaded_blocks -= (part_weights[m.from] > max_part_weights[m.from] && - part_weights[m.from] - phg.nodeWeight(m.node) <= max_part_weights[m.from]); - num_overloaded_blocks += (part_weights[m.to] <= max_part_weights[m.to] && - part_weights[m.to] + phg.nodeWeight(m.node) > max_part_weights[m.to]); - - part_weights[m.from] -= phg.nodeWeight(m.node); - part_weights[m.to] += phg.nodeWeight(m.node); - gain_sum += m.gain; - if (num_overloaded_blocks <= num_overloaded_blocks_before_pass && gain_sum >= best_gain) { - best_index = pos + 1; - best_gain = gain_sum; - } - } - - Gain attributed_gain = applyMovesIf(phg, moves.getData(), best_index, [&](size_t) { return true; }); - ASSERT(attributed_gain == best_gain); unused(attributed_gain); - - return best_gain; - } - namespace { #define DETERMINISTIC_LABEL_PROPAGATION_REFINER(X, Y) DeterministicLabelPropagationRefiner } diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index 07c7dbe94..d0ee553b3 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -59,7 +59,6 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { sorted_moves(num_hypernodes), prng(context.partition.seed), active_nodes(0), - ets_recalc_data( vec(context.partition.k) ), max_num_nodes(num_hypernodes), max_num_edges(num_hyperedges) { if (context.refinement.deterministic_refinement.use_active_node_set) { @@ -81,7 +80,6 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { // functions to apply moves from a sub-round Gain applyMovesSortedByGainAndRevertUnbalanced(PartitionedHypergraph& phg); std::pair applyMovesByMaximalPrefixesInBlockPairs(PartitionedHypergraph& phg); - Gain applyMovesSortedByGainWithRecalculation(PartitionedHypergraph& phg); Gain performMoveWithAttributedGain(PartitionedHypergraph& phg, const Move& m, bool activate_neighbors); template Gain applyMovesIf(PartitionedHypergraph& phg, const vec& moves, size_t end, Predicate&& predicate); @@ -96,16 +94,6 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { size_t p1_begin, size_t p1_end, size_t p2_begin, size_t p2_end, size_t p1_inv, size_t p2_inv, HypernodeWeight lb_p1, HypernodeWeight ub_p2); - struct RecalculationData { - MoveID first_in, last_out; - HypernodeID remaining_pins; - RecalculationData() : - first_in(std::numeric_limits::max()), - last_out(std::numeric_limits::min()), - remaining_pins(0) - { } - }; - const Context& context; vec cumulative_node_weights; ds::BufferedVector moves; @@ -117,10 +105,8 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { vec> last_moved_in_round; uint32_t round = 0; - tbb::enumerable_thread_specific< vec > ets_recalc_data; vec> last_recalc_round; vec move_pos_of_node; - uint32_t recalc_round = 1; size_t max_num_nodes = 0, max_num_edges = 0; }; From e6dba198b1fb9d383f61d7dc02b7a4aa54efba21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:23:03 +0200 Subject: [PATCH 44/66] sql plottools serializer --- mt-kahypar/io/sql_plottools_serializer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mt-kahypar/io/sql_plottools_serializer.cpp b/mt-kahypar/io/sql_plottools_serializer.cpp index fe1b2f8d1..94ff2d89e 100644 --- a/mt-kahypar/io/sql_plottools_serializer.cpp +++ b/mt-kahypar/io/sql_plottools_serializer.cpp @@ -118,7 +118,6 @@ std::string serialize(const PartitionedHypergraph& hypergraph, << " lp_hyperedge_size_activation_threshold=" << context.refinement.label_propagation.hyperedge_size_activation_threshold << " sync_lp_num_sub_rounds_sync_lp=" << context.refinement.deterministic_refinement.num_sub_rounds_sync_lp << " sync_lp_use_active_node_set=" << context.refinement.deterministic_refinement.use_active_node_set - << " sync_lp_recalculate_gains_on_second_apply=" << context.refinement.deterministic_refinement.recalculate_gains_on_second_apply; oss << " fm_algorithm=" << context.refinement.fm.algorithm << " fm_multitry_rounds=" << context.refinement.fm.multitry_rounds << " fm_perform_moves_global=" << std::boolalpha << context.refinement.fm.perform_moves_global From 547029302a797777b29b34182e09b10846485ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:23:23 +0200 Subject: [PATCH 45/66] sql plottools serializer again --- mt-kahypar/io/sql_plottools_serializer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/io/sql_plottools_serializer.cpp b/mt-kahypar/io/sql_plottools_serializer.cpp index 94ff2d89e..9fdb825c3 100644 --- a/mt-kahypar/io/sql_plottools_serializer.cpp +++ b/mt-kahypar/io/sql_plottools_serializer.cpp @@ -117,7 +117,7 @@ std::string serialize(const PartitionedHypergraph& hypergraph, << " lp_relative_improvement_threshold=" << context.refinement.label_propagation.relative_improvement_threshold << " lp_hyperedge_size_activation_threshold=" << context.refinement.label_propagation.hyperedge_size_activation_threshold << " sync_lp_num_sub_rounds_sync_lp=" << context.refinement.deterministic_refinement.num_sub_rounds_sync_lp - << " sync_lp_use_active_node_set=" << context.refinement.deterministic_refinement.use_active_node_set + << " sync_lp_use_active_node_set=" << context.refinement.deterministic_refinement.use_active_node_set; oss << " fm_algorithm=" << context.refinement.fm.algorithm << " fm_multitry_rounds=" << context.refinement.fm.multitry_rounds << " fm_perform_moves_global=" << std::boolalpha << context.refinement.fm.perform_moves_global From a48d5454cb91928b5588dce731f35620959f2983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:31:43 +0200 Subject: [PATCH 46/66] fix determinism test --- tests/partition/determinism/determinism_test.cc | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tests/partition/determinism/determinism_test.cc b/tests/partition/determinism/determinism_test.cc index c1e386dd1..0fec23bfd 100644 --- a/tests/partition/determinism/determinism_test.cc +++ b/tests/partition/determinism/determinism_test.cc @@ -89,7 +89,6 @@ class DeterminismTest : public Test { context.refinement.deterministic_refinement.num_sub_rounds_sync_lp = 2; context.refinement.label_propagation.maximum_iterations = 5; context.refinement.deterministic_refinement.use_active_node_set = false; - context.refinement.deterministic_refinement.recalculate_gains_on_second_apply = false; context.partition.objective = Objective::km1; context.partition.gain_policy = GainPolicy::km1; @@ -130,7 +129,7 @@ class DeterminismTest : public Test { } mt_kahypar_partitioned_hypergraph_t phg = utils::partitioned_hg_cast(partitioned_hypergraph); - DeterministicLabelPropagationRefiner refiner( + DeterministicLabelPropagationRefiner refiner( hypergraph.initialNumNodes(), hypergraph.initialNumEdges(), context); refiner.initialize(phg); vec dummy_refinement_nodes; @@ -244,17 +243,4 @@ TEST_F(DeterminismTest, RefinementOnCoarseHypergraph) { performRepeatedRefinement(); } -TEST_F(DeterminismTest, RefinementOnCoarseHypergraphWithSecondaryGainRecalculation) { - UncoarseningData uncoarseningData(false, hypergraph, context); - uncoarsening_data_t* data_ptr = uncoarsening::to_pointer(uncoarseningData); - mt_kahypar_hypergraph_t hg = utils::hypergraph_cast(hypergraph); - DeterministicMultilevelCoarsener coarsener(hg, context, data_ptr); - coarsener.coarsen(); - hypergraph = utils::cast(coarsener.coarsestHypergraph()).copy(); - partitioned_hypergraph = PartitionedHypergraph( - context.partition.k, hypergraph, parallel_tag_t()); - context.refinement.deterministic_refinement.recalculate_gains_on_second_apply = true; - performRepeatedRefinement(); -} - } // namespace mt_kahypar From 6a788c015c11d7f0a9c255d34912b0a690d046d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:33:34 +0200 Subject: [PATCH 47/66] use custom assert --- .../deterministic_label_propagation.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index db748038d..28b8362d8 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -406,12 +406,12 @@ namespace mt_kahypar { HypernodeWeight lb_p1, HypernodeWeight ub_p2) { auto balance = [&](size_t p1_ind, size_t p2_ind) { - assert(p1_ind == p1_invalid || p1_ind < p1_end); - assert(p1_ind >= p1_invalid || p1_invalid == (size_t(0) - 1)); - assert(p2_ind == p2_invalid || p2_ind < p2_end); - assert(p2_ind >= p2_invalid || p2_invalid == (size_t(0) - 1)); - assert(p1_ind == p1_invalid || p1_ind < cumulative_node_weights.size()); - assert(p2_ind == p2_invalid || p2_ind < cumulative_node_weights.size()); + ASSERT(p1_ind == p1_invalid || p1_ind < p1_end); + ASSERT(p1_ind >= p1_invalid || p1_invalid == (size_t(0) - 1)); + ASSERT(p2_ind == p2_invalid || p2_ind < p2_end); + ASSERT(p2_ind >= p2_invalid || p2_invalid == (size_t(0) - 1)); + ASSERT(p1_ind == p1_invalid || p1_ind < cumulative_node_weights.size()); + ASSERT(p2_ind == p2_invalid || p2_ind < cumulative_node_weights.size()); const auto a = (p1_ind == p1_invalid) ? 0 : cumulative_node_weights[p1_ind]; const auto b = (p2_ind == p2_invalid) ? 0 : cumulative_node_weights[p2_ind]; return a - b; From ebff4825b3201451acc74d7d545f3ba97569f177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:37:25 +0200 Subject: [PATCH 48/66] clarify command line message comment --- mt-kahypar/io/command_line_options.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mt-kahypar/io/command_line_options.cpp b/mt-kahypar/io/command_line_options.cpp index 1ce9f1d71..f2f2022f4 100644 --- a/mt-kahypar/io/command_line_options.cpp +++ b/mt-kahypar/io/command_line_options.cpp @@ -72,8 +72,7 @@ namespace mt_kahypar { options.add_options() ("help", "show help message") ("deterministic", po::value(&context.partition.deterministic)->value_name("")->default_value(false), - "Enables determinism in preprocessing in initial partitioning. " - "Coarsening and refinement routines must still be set to the deterministic versions.") + "Enables deterministic mode.") ("verbose,v", po::value(&context.partition.verbose_output)->value_name("")->default_value(true), "Verbose main partitioning output") ("fixed,f", From b5d2933323b9619809603c839208a1ab27d35557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:37:51 +0200 Subject: [PATCH 49/66] remove old TODO that was fixed in the meantime --- mt-kahypar/datastructures/static_hypergraph.h | 1 - 1 file changed, 1 deletion(-) diff --git a/mt-kahypar/datastructures/static_hypergraph.h b/mt-kahypar/datastructures/static_hypergraph.h index 5ec48893d..9c7616340 100644 --- a/mt-kahypar/datastructures/static_hypergraph.h +++ b/mt-kahypar/datastructures/static_hypergraph.h @@ -799,7 +799,6 @@ class StaticHypergraph { ASSERT(edgeIsEnabled(he), "Hyperedge" << he << "is disabled"); const size_t incidence_array_start = hyperedge(he).firstEntry(); const size_t incidence_array_end = hyperedge(he).firstInvalidEntry(); - // TODO this breaks if we have multi-pins. same for restore. we don't have a check for multi-pins in the input tbb::parallel_for(incidence_array_start, incidence_array_end, [&](const size_t pos) { const HypernodeID pin = _incidence_array[pos]; removeIncidentEdgeFromHypernode(he, pin); From 5c2dd5e5bb0e27f2923a4cdd97989173c9101ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:41:39 +0200 Subject: [PATCH 50/66] forgot to disable randomization in new gain computation --- .../deterministic/deterministic_label_propagation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 28b8362d8..2d876f17a 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -51,7 +51,7 @@ namespace mt_kahypar { size_t num_sub_rounds = context.refinement.deterministic_refinement.num_sub_rounds_sync_lp; using GainComputation = typename GainTypes::GainComputation; - GainComputation gain_computation(context); + GainComputation gain_computation(context, true); for (size_t iter = 0; iter < context.refinement.label_propagation.maximum_iterations; ++iter) { if (context.refinement.deterministic_refinement.use_active_node_set && ++round == 0) { From 59b386fe6fc336866341f84ea7c04fe2860b921f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:49:19 +0200 Subject: [PATCH 51/66] add deterministic flag to contraction to speed up incident nets construction if non-deterministic --- mt-kahypar/datastructures/static_hypergraph.cpp | 10 ++++++---- mt-kahypar/datastructures/static_hypergraph.h | 2 +- mt-kahypar/partition/coarsening/coarsening_commons.h | 4 ++-- .../coarsening/deterministic_multilevel_coarsener.cpp | 2 +- mt-kahypar/partition/coarsening/multilevel_coarsener.h | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/mt-kahypar/datastructures/static_hypergraph.cpp b/mt-kahypar/datastructures/static_hypergraph.cpp index 92d87d190..c5295609b 100644 --- a/mt-kahypar/datastructures/static_hypergraph.cpp +++ b/mt-kahypar/datastructures/static_hypergraph.cpp @@ -58,7 +58,7 @@ namespace mt_kahypar::ds { * * \param communities Community structure that should be contracted */ - StaticHypergraph StaticHypergraph::contract(parallel::scalable_vector& communities) { + StaticHypergraph StaticHypergraph::contract(parallel::scalable_vector& communities, bool deterministic) { ASSERT(communities.size() == _num_hypernodes); @@ -287,9 +287,11 @@ namespace mt_kahypar::ds { const size_t contracted_size = incident_nets_pos.load() - incident_nets_start; tmp_hypernodes[coarse_hn].setSize(contracted_size); - // sort for determinism - tbb::parallel_sort(tmp_incident_nets.begin() + incident_nets_start, - tmp_incident_nets.begin() + incident_nets_start + contracted_size); + if (deterministic) { + // sort for determinism + tbb::parallel_sort(tmp_incident_nets.begin() + incident_nets_start, + tmp_incident_nets.begin() + incident_nets_start + contracted_size); + } } duplicate_incident_nets_map.free(); } diff --git a/mt-kahypar/datastructures/static_hypergraph.h b/mt-kahypar/datastructures/static_hypergraph.h index 9c7616340..c0184ec8c 100644 --- a/mt-kahypar/datastructures/static_hypergraph.h +++ b/mt-kahypar/datastructures/static_hypergraph.h @@ -738,7 +738,7 @@ class StaticHypergraph { * * \param communities Community structure that should be contracted */ - StaticHypergraph contract(parallel::scalable_vector& communities); + StaticHypergraph contract(parallel::scalable_vector& communities, bool deterministic = false); bool registerContraction(const HypernodeID, const HypernodeID) { throw NonSupportedOperationException( diff --git a/mt-kahypar/partition/coarsening/coarsening_commons.h b/mt-kahypar/partition/coarsening/coarsening_commons.h index bd485e87b..26b6e4d16 100644 --- a/mt-kahypar/partition/coarsening/coarsening_commons.h +++ b/mt-kahypar/partition/coarsening/coarsening_commons.h @@ -164,12 +164,12 @@ class UncoarseningData { } void performMultilevelContraction( - parallel::scalable_vector&& communities, + parallel::scalable_vector&& communities, bool deterministic, const HighResClockTimepoint& round_start) { ASSERT(!is_finalized); Hypergraph& current_hg = hierarchy.empty() ? _hg : hierarchy.back().contractedHypergraph(); ASSERT(current_hg.initialNumNodes() == communities.size()); - Hypergraph contracted_hg = current_hg.contract(communities); + Hypergraph contracted_hg = current_hg.contract(communities, deterministic); const HighResClockTimepoint round_end = std::chrono::high_resolution_clock::now(); const double elapsed_time = std::chrono::duration(round_end - round_start).count(); hierarchy.emplace_back(std::move(contracted_hg), std::move(communities), elapsed_time); diff --git a/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp b/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp index 7084e8811..dc22b6c9c 100644 --- a/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp +++ b/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp @@ -99,7 +99,7 @@ bool DeterministicMultilevelCoarsener::coarseningPassImpl() { if (num_nodes_before_pass / num_nodes <= _context.coarsening.minimum_shrink_factor) { return false; } - _uncoarseningData.performMultilevelContraction(std::move(clusters), pass_start_time); + _uncoarseningData.performMultilevelContraction(std::move(clusters), /*deterministic=*/true, pass_start_time); return true; } diff --git a/mt-kahypar/partition/coarsening/multilevel_coarsener.h b/mt-kahypar/partition/coarsening/multilevel_coarsener.h index be8bcf5ce..9543d4115 100644 --- a/mt-kahypar/partition/coarsening/multilevel_coarsener.h +++ b/mt-kahypar/partition/coarsening/multilevel_coarsener.h @@ -213,7 +213,7 @@ class MultilevelCoarsener : public ICoarsener, _timer.start_timer("contraction", "Contraction"); // Perform parallel contraction - _uncoarseningData.performMultilevelContraction(std::move(cluster_ids), round_start); + _uncoarseningData.performMultilevelContraction(std::move(cluster_ids), /*deterministic=*/false, round_start); _timer.stop_timer("contraction"); ++_pass_nr; From b633aafb87bba0736fd1b0eba424a15f0fdfafce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 12:57:25 +0200 Subject: [PATCH 52/66] also add flag to graph --- mt-kahypar/datastructures/dynamic_graph.h | 4 ++-- mt-kahypar/datastructures/dynamic_hypergraph.h | 4 ++-- mt-kahypar/datastructures/static_graph.cpp | 6 +++--- mt-kahypar/datastructures/static_graph.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mt-kahypar/datastructures/dynamic_graph.h b/mt-kahypar/datastructures/dynamic_graph.h index 655dd8c78..90e867471 100644 --- a/mt-kahypar/datastructures/dynamic_graph.h +++ b/mt-kahypar/datastructures/dynamic_graph.h @@ -680,7 +680,7 @@ class DynamicGraph { // ####################### Contract / Uncontract ####################### - DynamicGraph contract(parallel::scalable_vector&) { + DynamicGraph contract(parallel::scalable_vector&, bool deterministic = false) { throw NonSupportedOperationException( "contract(c, id) is not supported in dynamic graph"); return DynamicGraph(); @@ -929,4 +929,4 @@ class DynamicGraph { }; } // namespace ds -} // namespace mt_kahypar \ No newline at end of file +} // namespace mt_kahypar diff --git a/mt-kahypar/datastructures/dynamic_hypergraph.h b/mt-kahypar/datastructures/dynamic_hypergraph.h index 6a817946c..c36ac98a4 100644 --- a/mt-kahypar/datastructures/dynamic_hypergraph.h +++ b/mt-kahypar/datastructures/dynamic_hypergraph.h @@ -774,7 +774,7 @@ class DynamicHypergraph { // ####################### Contract / Uncontract ####################### - DynamicHypergraph contract(parallel::scalable_vector&) { + DynamicHypergraph contract(parallel::scalable_vector&, bool deterministic = false) { throw NonSupportedOperationException( "contract(c, id) is not supported in dynamic hypergraph"); return DynamicHypergraph(); @@ -1164,4 +1164,4 @@ class DynamicHypergraph { }; } // namespace ds -} // namespace mt_kahypar \ No newline at end of file +} // namespace mt_kahypar diff --git a/mt-kahypar/datastructures/static_graph.cpp b/mt-kahypar/datastructures/static_graph.cpp index b5fc6ee6f..eb0c0535c 100644 --- a/mt-kahypar/datastructures/static_graph.cpp +++ b/mt-kahypar/datastructures/static_graph.cpp @@ -46,14 +46,14 @@ namespace mt_kahypar::ds { * * \param communities Community structure that should be contracted */ - StaticGraph StaticGraph::contract(parallel::scalable_vector& communities) { + StaticGraph StaticGraph::contract(parallel::scalable_vector& communities, bool deterministic) { ASSERT(communities.size() == _num_nodes); if ( !_tmp_contraction_buffer ) { allocateTmpContractionBuffer(); } - // AUXILLIARY BUFFERS - Reused during multilevel hierarchy to prevent expensive allocations + // AUXILIARY BUFFERS - Reused during multilevel hierarchy to prevent expensive allocations Array& mapping = _tmp_contraction_buffer->mapping; Array& tmp_nodes = _tmp_contraction_buffer->tmp_nodes; Array& node_sizes = _tmp_contraction_buffer->node_sizes; @@ -507,4 +507,4 @@ namespace mt_kahypar::ds { }, std::plus<>()); } -} // namespace \ No newline at end of file +} // namespace diff --git a/mt-kahypar/datastructures/static_graph.h b/mt-kahypar/datastructures/static_graph.h index 7ed82800b..513a0cfbf 100644 --- a/mt-kahypar/datastructures/static_graph.h +++ b/mt-kahypar/datastructures/static_graph.h @@ -767,7 +767,7 @@ class StaticGraph { * * \param communities Community structure that should be contracted */ - StaticGraph contract(parallel::scalable_vector& communities); + StaticGraph contract(parallel::scalable_vector& communities, bool deterministic = false); bool registerContraction(const HypernodeID, const HypernodeID) { throw NonSupportedOperationException( @@ -960,4 +960,4 @@ class StaticGraph { }; } // namespace ds -} // namespace mt_kahypar \ No newline at end of file +} // namespace mt_kahypar From 162322265d982435f311c3ec23fc65ab91c5656e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 13:06:07 +0200 Subject: [PATCH 53/66] remove old flag from context test --- tests/io/context_test.cc.in | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/io/context_test.cc.in b/tests/io/context_test.cc.in index 31890e06c..5052e43d3 100644 --- a/tests/io/context_test.cc.in +++ b/tests/io/context_test.cc.in @@ -492,9 +492,6 @@ TEST(AContext, LoadsDeterministicPresetCorrectly) { expected.initial_partitioning.refinement.deterministic_refinement.num_sub_rounds_sync_lp); ASSERT_EQ(actual.initial_partitioning.refinement.deterministic_refinement.use_active_node_set, expected.initial_partitioning.refinement.deterministic_refinement.use_active_node_set); - ASSERT_EQ(actual.initial_partitioning.refinement.deterministic_refinement.recalculate_gains_on_second_apply, - expected.initial_partitioning.refinement.deterministic_refinement.recalculate_gains_on_second_apply); - // initial partitioning -> refinement -> fm ASSERT_EQ(actual.initial_partitioning.refinement.fm.algorithm, From 8da6668717542b9452421f17aa40b8536e7240e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 13:10:17 +0200 Subject: [PATCH 54/66] remove old flag from context test again --- tests/io/context_test.cc.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/io/context_test.cc.in b/tests/io/context_test.cc.in index 5052e43d3..0608c6908 100644 --- a/tests/io/context_test.cc.in +++ b/tests/io/context_test.cc.in @@ -532,8 +532,6 @@ TEST(AContext, LoadsDeterministicPresetCorrectly) { expected.refinement.deterministic_refinement.num_sub_rounds_sync_lp); ASSERT_EQ(actual.refinement.deterministic_refinement.use_active_node_set, expected.refinement.deterministic_refinement.use_active_node_set); - ASSERT_EQ(actual.refinement.deterministic_refinement.recalculate_gains_on_second_apply, - expected.refinement.deterministic_refinement.recalculate_gains_on_second_apply); // mapping ASSERT_EQ(actual.mapping.strategy, From 66d7823f71dac69a207bd3ee24b62e6e1857252e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Fri, 29 Sep 2023 23:36:58 +0200 Subject: [PATCH 55/66] graph contraction is already deterministic --> mark parameter as unused --- mt-kahypar/datastructures/static_graph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/datastructures/static_graph.cpp b/mt-kahypar/datastructures/static_graph.cpp index eb0c0535c..de055d5de 100644 --- a/mt-kahypar/datastructures/static_graph.cpp +++ b/mt-kahypar/datastructures/static_graph.cpp @@ -46,7 +46,7 @@ namespace mt_kahypar::ds { * * \param communities Community structure that should be contracted */ - StaticGraph StaticGraph::contract(parallel::scalable_vector& communities, bool deterministic) { + StaticGraph StaticGraph::contract(parallel::scalable_vector& communities, bool /*deterministic*/) { ASSERT(communities.size() == _num_nodes); if ( !_tmp_contraction_buffer ) { From 4629319e77c76711d32457174352d51c9405b810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Sat, 30 Sep 2023 00:10:37 +0200 Subject: [PATCH 56/66] Revert change where ConcurrentBucketMap's number of buckets is independent of the machine's number of threads (the algorithms using it don't have non-determinism concerning the distribution of elements to buckets) --- mt-kahypar/datastructures/concurrent_bucket_map.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/datastructures/concurrent_bucket_map.h b/mt-kahypar/datastructures/concurrent_bucket_map.h index 5c97e8949..1cd2b41d7 100644 --- a/mt-kahypar/datastructures/concurrent_bucket_map.h +++ b/mt-kahypar/datastructures/concurrent_bucket_map.h @@ -69,7 +69,7 @@ class ConcurrentBucketMap { public: ConcurrentBucketMap() : - _num_buckets(align_to_next_power_of_two(BUCKET_FACTOR * BUCKET_FACTOR)), + _num_buckets(align_to_next_power_of_two(BUCKET_FACTOR * std::thread::hardware_concurrency())), _mod_mask(_num_buckets - 1), _spin_locks(_num_buckets), _buckets(_num_buckets) { } @@ -78,7 +78,7 @@ class ConcurrentBucketMap { ConcurrentBucketMap & operator= (const ConcurrentBucketMap &) = delete; ConcurrentBucketMap(ConcurrentBucketMap&& other) : - _num_buckets(align_to_next_power_of_two(BUCKET_FACTOR * BUCKET_FACTOR)), + _num_buckets(other._num_buckets), _mod_mask(_num_buckets - 1), _spin_locks(_num_buckets), _buckets(std::move(other._buffer)) { } From 58409c511f46df41f64bb94d6f8f02e258f2c52e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Sat, 30 Sep 2023 00:33:15 +0200 Subject: [PATCH 57/66] add a deterministic refinement test with low imbalance --- .../deterministic/deterministic_label_propagation.cpp | 1 + tests/partition/determinism/determinism_test.cc | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 2d876f17a..076b6b607 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -377,6 +377,7 @@ namespace mt_kahypar { if (pos < swap_prefix[index(sorted_moves[pos].from, sorted_moves[pos].to)]) { return true; } else { + // save non-applied moves as backup, to try to apply them in a second step. moves.push_back_buffered(sorted_moves[pos]); return false; } diff --git a/tests/partition/determinism/determinism_test.cc b/tests/partition/determinism/determinism_test.cc index 0fec23bfd..7fc386bc1 100644 --- a/tests/partition/determinism/determinism_test.cc +++ b/tests/partition/determinism/determinism_test.cc @@ -218,6 +218,12 @@ TEST_F(DeterminismTest, Refinement) { performRepeatedRefinement(); } +TEST_F(DeterminismTest, RefinementOnSmallImbalance) { + context.partition.epsilon = 0.03; + context.setupPartWeights(hypergraph.totalWeight()); + performRepeatedRefinement(); +} + TEST_F(DeterminismTest, RefinementWithActiveNodeSet) { context.refinement.deterministic_refinement.use_active_node_set = true; performRepeatedRefinement(); From d8c474398dc37ca4da402737c263a3c98f833c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 2 Oct 2023 11:19:51 +0200 Subject: [PATCH 58/66] use HyperedgeID cast instead of size_t in static_hypergraph --- mt-kahypar/datastructures/static_hypergraph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mt-kahypar/datastructures/static_hypergraph.cpp b/mt-kahypar/datastructures/static_hypergraph.cpp index c5295609b..e230c85fd 100644 --- a/mt-kahypar/datastructures/static_hypergraph.cpp +++ b/mt-kahypar/datastructures/static_hypergraph.cpp @@ -397,7 +397,7 @@ namespace mt_kahypar::ds { // Compute start position of each hyperedge in incidence array parallel::TBBPrefixSum num_pins_prefix_sum(he_sizes); tbb::parallel_invoke([&] { - tbb::parallel_for(size_t(0), size_t(_num_hyperedges), [&](const HyperedgeID& id) { + tbb::parallel_for(HyperedgeID(0), _num_hyperedges, [&](HyperedgeID id) { if ( he_mapping.value(id) ) { he_sizes[id] = tmp_hyperedges[id].size(); } else { From 33a29212a73e8a9d804b3c1542946a036b2b6a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 2 Oct 2023 11:22:55 +0200 Subject: [PATCH 59/66] define gain types at class scopes --- .../deterministic/deterministic_label_propagation.cpp | 3 --- .../refinement/deterministic/deterministic_label_propagation.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 076b6b607..6f75198a2 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -31,7 +31,6 @@ #include "mt-kahypar/parallel/chunking.h" #include "mt-kahypar/parallel/parallel_counting_sort.h" #include "mt-kahypar/utils/cast.h" -#include "mt-kahypar/partition/refinement/gains/gain_definitions.h" #include #include @@ -50,7 +49,6 @@ namespace mt_kahypar { constexpr size_t num_buckets = utils::ParallelPermutation::num_buckets; size_t num_sub_rounds = context.refinement.deterministic_refinement.num_sub_rounds_sync_lp; - using GainComputation = typename GainTypes::GainComputation; GainComputation gain_computation(context, true); for (size_t iter = 0; iter < context.refinement.label_propagation.maximum_iterations; ++iter) { @@ -133,7 +131,6 @@ namespace mt_kahypar { PartitionedHypergraph& phg, const Move& m, bool activate_neighbors) { Gain attributed_gain = 0; auto objective_delta = [&](const SynchronizedEdgeUpdate& sync_update) { - using AttributedGains = typename GainTypes::AttributedGains; attributed_gain -= AttributedGains::gain(sync_update); }; const bool was_moved = phg.changeNodePart(m.node, m.from, m.to, objective_delta); diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index d0ee553b3..95ddf31c5 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -32,6 +32,7 @@ #include "mt-kahypar/partition/refinement/i_refiner.h" #include "mt-kahypar/partition/refinement/i_rebalancer.h" +#include "mt-kahypar/partition/refinement/gains/gain_definitions.h" #include "mt-kahypar/partition/refinement/gains/gain_cache_ptr.h" #include "mt-kahypar/utils/reproducible_random.h" @@ -41,6 +42,8 @@ template class DeterministicLabelPropagationRefiner final : public IRefiner { using PartitionedHypergraph = typename TypeTraits::PartitionedHypergraph; + using GainComputation = typename GainTypes::GainComputation; + using AttributedGains = typename GainTypes::AttributedGains; public: explicit DeterministicLabelPropagationRefiner(const HypernodeID num_hypernodes, From d7968f5c7ccb6294e9ee3443f11270b7e8e9ea37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 2 Oct 2023 11:24:59 +0200 Subject: [PATCH 60/66] other comment style/syntax for named parameters --- .../partition/coarsening/deterministic_multilevel_coarsener.cpp | 2 +- mt-kahypar/partition/coarsening/multilevel_coarsener.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp b/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp index dc22b6c9c..68d1ce948 100644 --- a/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp +++ b/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp @@ -99,7 +99,7 @@ bool DeterministicMultilevelCoarsener::coarseningPassImpl() { if (num_nodes_before_pass / num_nodes <= _context.coarsening.minimum_shrink_factor) { return false; } - _uncoarseningData.performMultilevelContraction(std::move(clusters), /*deterministic=*/true, pass_start_time); + _uncoarseningData.performMultilevelContraction(std::move(clusters), true /* deterministic */, pass_start_time); return true; } diff --git a/mt-kahypar/partition/coarsening/multilevel_coarsener.h b/mt-kahypar/partition/coarsening/multilevel_coarsener.h index 9543d4115..a89948998 100644 --- a/mt-kahypar/partition/coarsening/multilevel_coarsener.h +++ b/mt-kahypar/partition/coarsening/multilevel_coarsener.h @@ -213,7 +213,7 @@ class MultilevelCoarsener : public ICoarsener, _timer.start_timer("contraction", "Contraction"); // Perform parallel contraction - _uncoarseningData.performMultilevelContraction(std::move(cluster_ids), /*deterministic=*/false, round_start); + _uncoarseningData.performMultilevelContraction(std::move(cluster_ids), false /* deterministic */, round_start); _timer.stop_timer("contraction"); ++_pass_nr; From 7a91aa0b6a625dcee033caf272b92e7ac30835d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 2 Oct 2023 11:26:49 +0200 Subject: [PATCH 61/66] remove NonSupportedOperationException for fixed vertices in deterministic mode --- mt-kahypar/partition/partitioner.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mt-kahypar/partition/partitioner.cpp b/mt-kahypar/partition/partitioner.cpp index 1fea42da1..66200838a 100644 --- a/mt-kahypar/partition/partitioner.cpp +++ b/mt-kahypar/partition/partitioner.cpp @@ -130,10 +130,6 @@ namespace mt_kahypar { // Check fixed vertex support compatibility if ( hypergraph.hasFixedVertices() ) { - if ( context.partition.preset_type == PresetType::deterministic ) { - throw NonSupportedOperationException( - "Deterministic partitioning mode does not support fixed vertices!"); - } if ( context.partition.mode == Mode::deep_multilevel || context.initial_partitioning.mode == Mode::deep_multilevel ) { throw NonSupportedOperationException( @@ -469,4 +465,4 @@ namespace mt_kahypar { } INSTANTIATE_CLASS_WITH_TYPE_TRAITS(Partitioner) -} \ No newline at end of file +} From f5e416081e2b3f753e633b423279976cc06507f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 2 Oct 2023 11:53:43 +0200 Subject: [PATCH 62/66] remove old members --- .../deterministic/deterministic_label_propagation.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index 95ddf31c5..e8e9f5f12 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -107,11 +107,6 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { ds::BufferedVector active_nodes; vec> last_moved_in_round; uint32_t round = 0; - - vec> last_recalc_round; - vec move_pos_of_node; - size_t max_num_nodes = 0, max_num_edges = 0; - }; } From d99722c3b35bde3d05db2e5f6e8e764dc90d9f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Mon, 2 Oct 2023 13:03:17 +0200 Subject: [PATCH 63/66] fix --- .../deterministic/deterministic_label_propagation.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index e8e9f5f12..7a6c3ec5e 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -61,9 +61,7 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { moves(num_hypernodes), sorted_moves(num_hypernodes), prng(context.partition.seed), - active_nodes(0), - max_num_nodes(num_hypernodes), - max_num_edges(num_hyperedges) { + active_nodes(0) { if (context.refinement.deterministic_refinement.use_active_node_set) { active_nodes.adapt_capacity(num_hypernodes); last_moved_in_round.resize(num_hypernodes + num_hyperedges, CAtomic(0)); From d01c0dbffcb2691a93668af86102dcf219d14783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Wed, 4 Oct 2023 11:41:47 +0200 Subject: [PATCH 64/66] add gain computation as member to deterministic label prop --- .../deterministic/deterministic_label_propagation.cpp | 8 ++++++-- .../deterministic/deterministic_label_propagation.h | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 6f75198a2..063662843 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -46,11 +46,15 @@ namespace mt_kahypar { const double) { PartitionedHypergraph& phg = utils::cast(hypergraph); Gain overall_improvement = 0; + + if (context.partition.k != current_k) { + current_k = context.partition.k; + gain_computation.changeNumberOfBlocks(current_k); + } + constexpr size_t num_buckets = utils::ParallelPermutation::num_buckets; size_t num_sub_rounds = context.refinement.deterministic_refinement.num_sub_rounds_sync_lp; - GainComputation gain_computation(context, true); - for (size_t iter = 0; iter < context.refinement.label_propagation.maximum_iterations; ++iter) { if (context.refinement.deterministic_refinement.use_active_node_set && ++round == 0) { std::fill(last_moved_in_round.begin(), last_moved_in_round.end(), CAtomic(0)); diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h index 7a6c3ec5e..030e371fd 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.h @@ -57,9 +57,11 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { const HyperedgeID num_hyperedges, const Context& context) : context(context), + gain_computation(context, true /* disable_randomization */), cumulative_node_weights(num_hypernodes), moves(num_hypernodes), sorted_moves(num_hypernodes), + current_k(context.partition.k), prng(context.partition.seed), active_nodes(0) { if (context.refinement.deterministic_refinement.use_active_node_set) { @@ -96,10 +98,12 @@ class DeterministicLabelPropagationRefiner final : public IRefiner { HypernodeWeight lb_p1, HypernodeWeight ub_p2); const Context& context; + GainComputation gain_computation; vec cumulative_node_weights; ds::BufferedVector moves; vec sorted_moves; + PartitionID current_k; std::mt19937 prng; utils::ParallelPermutation permutation; ds::BufferedVector active_nodes; From d0f12ffe60b7cd8b59d6082014b2ef5efc91a684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Wed, 4 Oct 2023 11:42:39 +0200 Subject: [PATCH 65/66] use current_k instead of phg.k() in deterministic label prop --- .../deterministic/deterministic_label_propagation.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 063662843..6a31469b7 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -180,7 +180,7 @@ namespace mt_kahypar { vec aggregatePartWeightDeltas(PartitionedHypergraph& phg, const vec& moves, size_t end) { // parallel reduce makes way too many vector copies tbb::enumerable_thread_specific> - ets_part_weight_diffs(phg.k(), 0); + ets_part_weight_diffs(current_k, 0); auto accum = [&](const tbb::blocked_range& r) { auto& part_weights = ets_part_weight_diffs.local(); for (size_t i = r.begin(); i < r.end(); ++i) { @@ -189,7 +189,7 @@ namespace mt_kahypar { } }; tbb::parallel_for(tbb::blocked_range(UL(0), end), accum); - vec res(phg.k(), 0); + vec res(current_k, 0); auto combine = [&](const vec& a) { for (size_t i = 0; i < res.size(); ++i) { res[i] += a[i]; @@ -209,7 +209,7 @@ namespace mt_kahypar { const auto& max_part_weights = context.partition.max_part_weights; size_t num_overloaded_blocks = 0, num_overloaded_before_round = 0; vec part_weights = aggregatePartWeightDeltas(phg, moves.getData(), num_moves); - for (PartitionID i = 0; i < phg.k(); ++i) { + for (PartitionID i = 0; i < current_k; ++i) { part_weights[i] += phg.partWeight(i); if (part_weights[i] > max_part_weights[i]) { num_overloaded_blocks++; @@ -292,7 +292,7 @@ namespace mt_kahypar { template std::pair DeterministicLabelPropagationRefiner::applyMovesByMaximalPrefixesInBlockPairs(PartitionedHypergraph& phg) { - PartitionID k = phg.k(); + PartitionID k = current_k; PartitionID max_key = k * k; auto index = [&](PartitionID b1, PartitionID b2) { return b1 * k + b2; }; auto get_key = [&](const Move& m) { return index(m.from, m.to); }; From beaac7f678598d262b62bf284445e205a9b17cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gottesb=C3=BCren?= Date: Wed, 4 Oct 2023 12:59:32 +0200 Subject: [PATCH 66/66] fix --- .../deterministic/deterministic_label_propagation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp index 6a31469b7..be8ba1a1d 100644 --- a/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp +++ b/mt-kahypar/partition/refinement/deterministic/deterministic_label_propagation.cpp @@ -177,7 +177,7 @@ namespace mt_kahypar { } template - vec aggregatePartWeightDeltas(PartitionedHypergraph& phg, const vec& moves, size_t end) { + vec aggregatePartWeightDeltas(PartitionedHypergraph& phg, PartitionID current_k, const vec& moves, size_t end) { // parallel reduce makes way too many vector copies tbb::enumerable_thread_specific> ets_part_weight_diffs(current_k, 0); @@ -208,7 +208,7 @@ namespace mt_kahypar { const auto& max_part_weights = context.partition.max_part_weights; size_t num_overloaded_blocks = 0, num_overloaded_before_round = 0; - vec part_weights = aggregatePartWeightDeltas(phg, moves.getData(), num_moves); + vec part_weights = aggregatePartWeightDeltas(phg, current_k, moves.getData(), num_moves); for (PartitionID i = 0; i < current_k; ++i) { part_weights[i] += phg.partWeight(i); if (part_weights[i] > max_part_weights[i]) {