@@ -31,10 +31,15 @@ class GenericFM {
3131 unsigned max_number_of_passes = 10 ;
3232 index_type max_nodes_in_part = 0 ;
3333
34+ // auxiliary for RecursiveFM
35+ std::vector<index_type> getMaxNodesOnLevel (index_type nr_nodes, unsigned nr_parts) const ;
36+
3437 public:
3538
3639 void ImprovePartitioning (Partitioning<index_type, workw_type, memw_type, commw_type>& partition);
3740
41+ void RecursiveFM (Partitioning<index_type, workw_type, memw_type, commw_type>& partition);
42+
3843 inline unsigned getMaxNumberOfPasses () const { return max_number_of_passes; }
3944 inline void setMaxNumberOfPasses (unsigned passes_) { max_number_of_passes = passes_; }
4045 inline index_type getMaxNodesInPart () const { return max_nodes_in_part; }
@@ -81,6 +86,20 @@ void GenericFM<index_type, workw_type, memw_type, commw_type>::ImprovePartitioni
8186 if (partition.assignedPartition (node) == 0 )
8287 ++left_side;
8388
89+ if (left_side > max_nodes_in_part || Hgraph.num_vertices () - left_side > max_nodes_in_part)
90+ {
91+ if (pass_idx == 0 )
92+ {
93+ std::cout<<" Error: initial partitioning of FM is not balanced." <<std::endl;
94+ return ;
95+ }
96+ else
97+ {
98+ std::cout<<" Error during FM: partitionming somehow became imbalanced." <<std::endl;
99+ return ;
100+ }
101+ }
102+
84103 // Initialize gain values
85104 for (index_type hyperedge = 0 ; hyperedge < Hgraph.num_hyperedges (); ++hyperedge)
86105 {
@@ -96,6 +115,11 @@ void GenericFM<index_type, workw_type, memw_type, commw_type>::ImprovePartitioni
96115 for (index_type node : Hgraph.get_vertices_in_hyperedge (hyperedge))
97116 if (partition.assignedPartition (node) == part)
98117 ++gain[node];
118+
119+ if (nr_nodes_in_hyperedge_on_side[hyperedge][part] == 0 )
120+ for (index_type node : Hgraph.get_vertices_in_hyperedge (hyperedge))
121+ if (partition.assignedPartition (node) != part)
122+ --gain[node];
99123 }
100124 }
101125
@@ -232,10 +256,113 @@ void GenericFM<index_type, workw_type, memw_type, commw_type>::ImprovePartitioni
232256 if (best_index == 0 )
233257 break ;
234258
235- for (index_type node_idx = 0 ; node_idx < best_index; ++node_idx)
259+ for (index_type node_idx = 0 ; node_idx < best_index && node_idx < static_cast <index_type>(moved_nodes. size ()) ; ++node_idx)
236260 partition.setAssignedPartition (moved_nodes[node_idx], 1U -partition.assignedPartition (moved_nodes[node_idx]));
237261
238262 }
239263}
240264
265+ template <typename index_type, typename workw_type, typename memw_type, typename commw_type>
266+ void GenericFM<index_type, workw_type, memw_type, commw_type>::RecursiveFM(Partitioning<index_type, workw_type, memw_type, commw_type>& partition)
267+ {
268+ const unsigned & nr_parts = partition.getInstance ().getNumberOfPartitions ();
269+ const index_type& nr_nodes = partition.getInstance ().getHypergraph ().num_vertices ();
270+
271+ using Hgraph = Hypergraph<index_type, workw_type, memw_type, commw_type>;
272+
273+ // Note: this is just a simple recursive heuristic for the case when the partitions are a small power of 2
274+ if (nr_parts != 4 && nr_parts != 8 && nr_parts != 16 && nr_parts != 32 )
275+ {
276+ std::cout << " Error: Recursive FM can only be used for 4, 8, 16 or 32 partitions currently." << std::endl;
277+ return ;
278+ }
279+
280+ for (index_type node = 0 ; node < nr_nodes; ++node)
281+ partition.setAssignedPartition (node, static_cast <unsigned >(node % 2 ));
282+
283+ if (max_nodes_in_part == 0 ) // if not initialized
284+ max_nodes_in_part = static_cast <index_type>(ceil (static_cast <double >(nr_nodes) * static_cast <double >(partition.getInstance ().getMaxWorkWeightPerPartition ())
285+ / static_cast <double >(partition.getInstance ().getHypergraph ().compute_total_vertex_work_weight ()) ));
286+
287+ const std::vector<index_type> max_nodes_on_level = getMaxNodesOnLevel (nr_nodes, nr_parts);
288+
289+ unsigned parts = 1 ;
290+ unsigned level = 0 ;
291+ std::vector<Hgraph> sub_hgraphs ({partition.getInstance ().getHypergraph ()});
292+ unsigned start_index = 0 ;
293+
294+ std::map<index_type, std::pair<unsigned , index_type> > node_to_new_hgraph_and_id;
295+ std::map<std::pair<unsigned , index_type>, index_type> hgraph_and_id_to_old_idx;
296+ for (index_type node = 0 ; node < nr_nodes; ++node)
297+ {
298+ node_to_new_hgraph_and_id[node] = std::make_pair (0 , node);
299+ hgraph_and_id_to_old_idx[std::make_pair (0 , node)] = node;
300+ }
301+
302+ while (parts < nr_parts)
303+ {
304+ unsigned end_idx = static_cast <unsigned >(sub_hgraphs.size ());
305+ for (unsigned sub_hgraph_index = start_index; sub_hgraph_index < end_idx; ++sub_hgraph_index)
306+ {
307+ const Hgraph& hgraph = sub_hgraphs[sub_hgraph_index];
308+ PartitioningProblem instance (hgraph, 2 );
309+ Partitioning sub_partition (instance);
310+ for (index_type node = 0 ; node < hgraph.num_vertices (); ++node)
311+ sub_partition.setAssignedPartition (node, node%2 );
312+
313+ GenericFM sub_fm;
314+ sub_fm.setMaxNodesInPart (max_nodes_on_level[level]);
315+ // std::cout<<"Hgraph of size "<<hgraph.num_vertices()<<" split into two parts of at most "<<max_nodes_on_level[level]<<std::endl;
316+ sub_fm.ImprovePartitioning (sub_partition);
317+
318+ std::vector<unsigned > current_idx (2 , 0 );
319+ std::vector<std::vector<bool > > part_indicator (2 , std::vector<bool >(hgraph.num_vertices (), false ));
320+ for (index_type node = 0 ; node < hgraph.num_vertices (); ++node)
321+ {
322+ const unsigned part_id = sub_partition.assignedPartition (node);
323+ const index_type original_id = hgraph_and_id_to_old_idx[std::make_pair (sub_hgraph_index, node)];
324+ node_to_new_hgraph_and_id[original_id] = std::make_pair (sub_hgraphs.size ()+part_id, current_idx[part_id]);
325+ hgraph_and_id_to_old_idx[std::make_pair (sub_hgraphs.size ()+part_id, current_idx[part_id])] = original_id;
326+ ++current_idx[part_id];
327+ part_indicator[part_id][node] = true ;
328+ }
329+
330+ for (unsigned part = 0 ; part < 2 ; ++part)
331+ sub_hgraphs.push_back (sub_hgraphs[sub_hgraph_index].create_induced_hypergraph (part_indicator[part]));
332+
333+ ++start_index;
334+ }
335+
336+ parts *= 2 ;
337+ ++level;
338+ }
339+
340+ for (index_type node = 0 ; node < nr_nodes; ++node)
341+ partition.setAssignedPartition (node, node_to_new_hgraph_and_id[node].first - (static_cast <unsigned >(sub_hgraphs.size ())-nr_parts));
342+
343+ }
344+
345+ template <typename index_type, typename workw_type, typename memw_type, typename commw_type>
346+ std::vector<index_type> GenericFM<index_type, workw_type, memw_type, commw_type>::getMaxNodesOnLevel(index_type nr_nodes, unsigned nr_parts) const
347+ {
348+ std::vector<index_type> max_nodes_on_level;
349+ std::vector<index_type> limit_per_level ({static_cast <index_type>(ceil (static_cast <double >(nr_nodes) / 2.0 ))});
350+ for (unsigned parts = nr_parts / 4 ; parts > 0 ; parts /= 2 )
351+ limit_per_level.push_back (static_cast <index_type>(ceil (static_cast <double >(limit_per_level.back ()) / 2.0 )));
352+
353+ max_nodes_on_level.push_back (max_nodes_in_part);
354+ for (unsigned parts = 2 ; parts < nr_parts; parts *= 2 )
355+ {
356+ index_type next_limit = max_nodes_on_level.back ()*2 ;
357+ if (next_limit > limit_per_level.back ())
358+ --next_limit;
359+
360+ limit_per_level.pop_back ();
361+ max_nodes_on_level.push_back (next_limit);
362+ }
363+
364+ std::reverse (max_nodes_on_level.begin (),max_nodes_on_level.end ());
365+ return max_nodes_on_level;
366+ }
367+
241368} // namespace osp
0 commit comments