@@ -62,6 +62,35 @@ void RepairEmtpyBlocks<GraphAndGainTypes>::computeEmptyParts(PartitionedHypergra
6262 _empty_parts.push_back (block);
6363 }
6464 }
65+
66+ const auto & max_weights = _context.partition .max_part_weights ;
67+ if (!_empty_parts.empty () && _context.partition .use_individual_part_weights ) {
68+ // We sort the empty parts, so that
69+ // (1) we can determine which parts to skip for degree zero nodes
70+ // (2) computeBestMovesBlockIndependent can maintain the invariant that the last entry
71+ // of best_move_for_part is the worst move in the list. This invariant could be broken
72+ // if a node does not fit in a block (unlikely, but possible) and therefore "skips"
73+ // a part of the list. However, by sorting descending by part weight, this can't happen
74+ // since a move at position i + 1 is guaranteed to also fit in position i, and thus
75+ // can not be better than the move at position i (or it would be placed there).
76+ std::sort (_empty_parts.begin (), _empty_parts.end (), [&](PartitionID lhs, PartitionID rhs) {
77+ // deterministic tie breaking
78+ return max_weights[lhs] > max_weights[rhs] || (max_weights[lhs] == max_weights[rhs] && lhs < rhs);
79+ });
80+ }
81+
82+ if (!_empty_parts.empty () && phg.numRemovedHypernodes () > 0 ) {
83+ // since some of the blocks can be filled by degree zero nodes at the end, we can throw
84+ // out all blocks that can be filled in this way
85+ HypernodeWeight max_removed_weight = phg.maxWeightOfRemovedDegreeZeroNode ();
86+ size_t last_fitting = 0 ;
87+ while (last_fitting < _empty_parts.size ()
88+ && max_removed_weight <= max_weights[_empty_parts[last_fitting]]) {
89+ ++last_fitting;
90+ }
91+ size_t start = (phg.numRemovedHypernodes () >= last_fitting) ? 0 : last_fitting - phg.numRemovedHypernodes ();
92+ _empty_parts.erase (_empty_parts.begin () + start, _empty_parts.begin () + last_fitting);
93+ }
6594}
6695
6796template <typename GraphAndGainTypes>
@@ -74,20 +103,6 @@ void RepairEmtpyBlocks<GraphAndGainTypes>::computeBestMovesBlockIndependent(Part
74103 _global_best_move_for_part.clear ();
75104 _global_best_move_for_part.resize (_empty_parts.size (), Move{});
76105
77- if (_context.partition .use_individual_part_weights ) {
78- // We sort the empty parts, so that we can maintain the invariant that the last entry
79- // of best_move_for_part is the worst move in the list. This invariant could be broken
80- // if a node does not fit in a block (unlikely, but possible) and therefore "skips"
81- // a part of the list. However, by sorting descending by part weight, this can't happen
82- // since a move at position i + 1 is guaranteed to also fit in position i, and thus
83- // can not be better than the move at position i (or it would be placed there).
84- const auto & max_weights = _context.partition .max_part_weights ;
85- std::sort (_empty_parts.begin (), _empty_parts.end (), [&](PartitionID lhs, PartitionID rhs) {
86- // deterministic tie breaking
87- return max_weights[lhs] > max_weights[rhs] || (max_weights[lhs] == max_weights[rhs] && lhs < rhs);
88- });
89- }
90-
91106 auto insert_move_into_list = [&](Move& current_move, vec<Move>& move_for_part) {
92107 const Move& worst_move = move_for_part.back ();
93108 if (moveIsBetter (current_move, worst_move)) {
0 commit comments