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
3435namespace 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
102114template <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
185208template <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
270302template <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)) {
0 commit comments