Skip to content

Commit 76f8eda

Browse files
committed
Coarsening: fixed vertex support
1 parent e88cf30 commit 76f8eda

2 files changed

Lines changed: 64 additions & 18 deletions

File tree

mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.cpp

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <tbb/parallel_sort.h>
3030

3131
#include "mt-kahypar/definitions.h"
32+
#include "mt-kahypar/partition/coarsening/policies/rating_fixed_vertex_acceptance_policy.h"
3233
#include "mt-kahypar/utils/hash.h"
3334

3435
namespace mt_kahypar {
@@ -54,6 +55,9 @@ bool DeterministicMultilevelCoarsener<TypeTraits>::coarseningPassImpl() {
5455
clusters[u] = u;
5556
});
5657

58+
ds::FixedVertexSupport<Hypergraph> fixed_vertices = hg.copyOfFixedVertexSupport();
59+
fixed_vertices.setMaxBlockWeight(_context.partition.max_part_weights);
60+
5761
const bool isPrefixDoublingPass = _context.coarsening.det_prefix_doubling;
5862
if (isPrefixDoublingPass) {
5963
permutation.shuffle(utils::IntegerRange<HypernodeID>{0, num_nodes}, _context.shared_memory.static_balancing_work_packages, config.prng); // need shuffle for prefix-doubling
@@ -75,7 +79,11 @@ bool DeterministicMultilevelCoarsener<TypeTraits>::coarseningPassImpl() {
7579
}
7680
last = std::min<size_t>(num_nodes_before_pass, first + dist);
7781

78-
clusterNodesInRange(clusters, num_nodes, first, last);
82+
if (hg.hasFixedVertices()) {
83+
clusterNodesInRange<true>(clusters, num_nodes, first, last, fixed_vertices);
84+
} else {
85+
clusterNodesInRange<false>(clusters, num_nodes, first, last, fixed_vertices);
86+
}
7987
}
8088
} else {
8189
permutation.random_grouping(num_nodes, _context.shared_memory.static_balancing_work_packages, config.prng());
@@ -84,7 +92,11 @@ bool DeterministicMultilevelCoarsener<TypeTraits>::coarseningPassImpl() {
8492
sub_round, config.num_buckets, config.num_buckets_per_sub_round);
8593
size_t first = permutation.bucket_bounds[first_bucket], last = permutation.bucket_bounds[last_bucket];
8694

87-
clusterNodesInRange(clusters, num_nodes, first, last);
95+
if (hg.hasFixedVertices()) {
96+
clusterNodesInRange<true>(clusters, num_nodes, first, last, fixed_vertices);
97+
} else {
98+
clusterNodesInRange<false>(clusters, num_nodes, first, last, fixed_vertices);
99+
}
88100
}
89101
}
90102

@@ -100,18 +112,23 @@ bool DeterministicMultilevelCoarsener<TypeTraits>::coarseningPassImpl() {
100112
}
101113

102114
template<typename TypeTraits>
103-
void DeterministicMultilevelCoarsener<TypeTraits>::clusterNodesInRange(vec<HypernodeID>& clusters, HypernodeID& num_nodes, size_t first, size_t last) {
115+
template<bool has_fixed_vertices>
116+
void DeterministicMultilevelCoarsener<TypeTraits>::clusterNodesInRange(vec<HypernodeID>& clusters,
117+
HypernodeID& num_nodes,
118+
size_t first,
119+
size_t last,
120+
ds::FixedVertexSupport<Hypergraph>& fixed_vertices) {
104121
const Hypergraph& hg = Base::currentHypergraph();
105122

106123
// each vertex finds a cluster it wants to join
107124
tbb::parallel_for(first, last, [&](size_t pos) {
108125
const HypernodeID u = permutation.at(pos);
109126
if (cluster_weight[u] == hg.nodeWeight(u) && hg.nodeIsEnabled(u)) {
110127
if (useLargeRatingMapForRatingOfHypernode(hg, u)) {
111-
calculatePreferredTargetCluster(u, clusters, default_rating_maps.local());
128+
calculatePreferredTargetCluster<has_fixed_vertices>(u, clusters, default_rating_maps.local(), fixed_vertices);
112129
} else {
113130
// note: the cache efficient rating map is still deterministic since its size (and thus the iteration order) never changes
114-
calculatePreferredTargetCluster(u, clusters, cache_efficient_rating_maps.local());
131+
calculatePreferredTargetCluster<has_fixed_vertices>(u, clusters, cache_efficient_rating_maps.local(), fixed_vertices);
115132
}
116133
}
117134
});
@@ -132,8 +149,14 @@ void DeterministicMultilevelCoarsener<TypeTraits>::clusterNodesInRange(vec<Hyper
132149
} else if (_context.coarsening.det_fix_cluster_weights) {
133150
cluster_weights_to_fix.push_back_buffered(u);
134151
}
135-
clusters[u] = target;
136-
cluster_weight[target] = opportunistic_cluster_weight[target];
152+
bool accept_fixed_vertex_contraction = true;
153+
if constexpr (has_fixed_vertices) {
154+
accept_fixed_vertex_contraction = fixed_vertices.contract(target, u);
155+
}
156+
if (accept_fixed_vertex_contraction) {
157+
clusters[u] = target;
158+
cluster_weight[target] = opportunistic_cluster_weight[target];
159+
}
137160
} else {
138161
if (_context.coarsening.det_fix_cluster_weights && opportunistic_cluster_weight[u] != hg.nodeWeight(u)) {
139162
// node u could still not move
@@ -147,7 +170,7 @@ void DeterministicMultilevelCoarsener<TypeTraits>::clusterNodesInRange(vec<Hyper
147170
num_nodes -= num_contracted_nodes.combine(std::plus<>());
148171
nodes_in_too_heavy_clusters.finalize();
149172
if (nodes_in_too_heavy_clusters.size() > 0) {
150-
num_nodes -= approveVerticesInTooHeavyClusters(clusters);
173+
num_nodes -= approveVerticesInTooHeavyClusters<has_fixed_vertices>(clusters, fixed_vertices);
151174
nodes_in_too_heavy_clusters.clear();
152175
}
153176

@@ -183,8 +206,11 @@ void DeterministicMultilevelCoarsener<TypeTraits>::clusterNodesInRange(vec<Hyper
183206
}
184207

185208
template<typename TypeTraits>
186-
template<typename RatingMap>
187-
void DeterministicMultilevelCoarsener<TypeTraits>::calculatePreferredTargetCluster(HypernodeID u, const vec<HypernodeID>& clusters, RatingMap& tmp_ratings) {
209+
template<bool has_fixed_vertices, typename RatingMap>
210+
void DeterministicMultilevelCoarsener<TypeTraits>::calculatePreferredTargetCluster(HypernodeID u,
211+
const vec<HypernodeID>& clusters,
212+
RatingMap& tmp_ratings,
213+
const ds::FixedVertexSupport<Hypergraph>& fixed_vertices) {
188214
const Hypergraph& hg = Base::currentHypergraph();
189215
tmp_ratings.clear();
190216

@@ -223,8 +249,14 @@ void DeterministicMultilevelCoarsener<TypeTraits>::calculatePreferredTargetClust
223249
for (const auto& entry : tmp_ratings) {
224250
HypernodeID target_cluster = entry.key;
225251
double target_score = entry.value;
252+
bool accept_fixed_vertex_contraction = true;
253+
if constexpr ( has_fixed_vertices ) {
254+
accept_fixed_vertex_contraction = FixedVertexAcceptancePolicy::acceptContraction(hg, fixed_vertices, _context, target_cluster,u);
255+
}
256+
226257
if (target_score >= best_score && target_cluster != u && hg.communityID(target_cluster) == comm_u
227-
&& cluster_weight[target_cluster] + weight_u <= _context.coarsening.max_allowed_node_weight) {
258+
&& cluster_weight[target_cluster] + weight_u <= _context.coarsening.max_allowed_node_weight
259+
&& accept_fixed_vertex_contraction) {
228260
if (target_score > best_score) {
229261
best_targets.clear();
230262
best_score = target_score;
@@ -268,7 +300,8 @@ void DeterministicMultilevelCoarsener<TypeTraits>::calculatePreferredTargetClust
268300
}
269301

270302
template<typename TypeTraits>
271-
size_t DeterministicMultilevelCoarsener<TypeTraits>::approveVerticesInTooHeavyClusters(vec<HypernodeID>& clusters) {
303+
template<bool has_fixed_vertices>
304+
size_t DeterministicMultilevelCoarsener<TypeTraits>::approveVerticesInTooHeavyClusters(vec<HypernodeID>& clusters, ds::FixedVertexSupport<Hypergraph>& fixed_vertices) {
272305
const Hypergraph& hg = Base::currentHypergraph();
273306
tbb::enumerable_thread_specific<size_t> num_contracted_nodes { 0 };
274307

@@ -295,6 +328,9 @@ size_t DeterministicMultilevelCoarsener<TypeTraits>::approveVerticesInTooHeavyCl
295328
if (target_weight + hg.nodeWeight(v) > _context.coarsening.max_allowed_node_weight) {
296329
break;
297330
}
331+
if (has_fixed_vertices && !fixed_vertices.contract(target, v)) {
332+
continue;
333+
}
298334
clusters[v] = target;
299335
target_weight += hg.nodeWeight(v);
300336
if (opportunistic_cluster_weight[v] == hg.nodeWeight(v)) {

mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "mt-kahypar/utils/reproducible_random.h"
3535
#include "mt-kahypar/datastructures/sparse_map.h"
3636
#include "mt-kahypar/datastructures/buffered_vector.h"
37+
#include "mt-kahypar/datastructures/fixed_vertex_support.h"
3738
#include "mt-kahypar/utils/utilities.h"
3839
#include "mt-kahypar/utils/progress_bar.h"
3940
#include "mt-kahypar/utils/cast.h"
@@ -125,12 +126,21 @@ class DeterministicMultilevelCoarsener : public ICoarsener,
125126
(hg.initialNumNodes() - hg.numRemovedHypernodes()) / _context.coarsening.maximum_shrink_factor) );
126127
}
127128

128-
void clusterNodesInRange(vec<HypernodeID>& clusters, HypernodeID& num_nodes, size_t first, size_t last);
129-
130-
template<typename RatingMap>
131-
void calculatePreferredTargetCluster(HypernodeID u, const vec<HypernodeID>& clusters, RatingMap& tmp_ratings);
132-
133-
size_t approveVerticesInTooHeavyClusters(vec<HypernodeID>& clusters);
129+
template<bool has_fixed_vertices>
130+
void clusterNodesInRange(vec<HypernodeID>& clusters,
131+
HypernodeID& num_nodes,
132+
size_t first,
133+
size_t last,
134+
ds::FixedVertexSupport<Hypergraph>& fixed_vertices);
135+
136+
template<bool has_fixed_vertices, typename RatingMap>
137+
void calculatePreferredTargetCluster(HypernodeID u,
138+
const vec<HypernodeID>& clusters,
139+
RatingMap& tmp_ratings,
140+
const ds::FixedVertexSupport<Hypergraph>& fixed_vertices);
141+
142+
template<bool has_fixed_vertices>
143+
size_t approveVerticesInTooHeavyClusters(vec<HypernodeID>& clusters, ds::FixedVertexSupport<Hypergraph>& fixed_vertices);
134144

135145
HypernodeID currentNumberOfNodesImpl() const override {
136146
return Base::currentNumNodes();

0 commit comments

Comments
 (0)