Skip to content

Commit da0a0e8

Browse files
FM fixes and recursive FM
1 parent 65c80f1 commit da0a0e8

File tree

3 files changed

+186
-1
lines changed

3 files changed

+186
-1
lines changed

include/osp/partitioning/model/hypergraph.hpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class Hypergraph {
7171
template<typename Graph_t>
7272
void convert_from_cdag_as_hyperdag(const Graph_t& dag);
7373

74+
Hypergraph<index_type, workw_type, memw_type, commw_type> create_induced_hypergraph(const std::vector<bool>& include) const;
75+
7476
private:
7577
index_type Num_vertices = 0, Num_hyperedges = 0, Num_pins = 0;
7678

@@ -247,4 +249,41 @@ void Hypergraph<index_type, workw_type, memw_type, commw_type>::convert_from_cda
247249
}
248250
}
249251

252+
template<typename index_type, typename workw_type, typename memw_type, typename commw_type>
253+
Hypergraph<index_type, workw_type, memw_type, commw_type> Hypergraph<index_type, workw_type, memw_type, commw_type>::create_induced_hypergraph(const std::vector<bool>& include) const
254+
{
255+
if(include.size() != Num_vertices)
256+
throw std::invalid_argument("Invalid Argument while extracting induced hypergraph: input bool array has incorrect size.");
257+
258+
std::vector<index_type> new_index(Num_vertices);
259+
unsigned current_index = 0;
260+
for(index_type node = 0; node < Num_vertices; ++node)
261+
if(include[node])
262+
new_index[node] = current_index++;
263+
264+
Hypergraph<index_type, workw_type, memw_type, commw_type> hgraph(current_index, 0);
265+
for(index_type node = 0; node < Num_vertices; ++node)
266+
if(include[node])
267+
{
268+
hgraph.set_vertex_work_weight(new_index[node], vertex_work_weights[node]);
269+
hgraph.set_vertex_memory_weight(new_index[node], vertex_memory_weights[node]);
270+
}
271+
272+
for(index_type hyperedge = 0; hyperedge < Num_hyperedges; ++hyperedge)
273+
{
274+
unsigned nr_induced_pins = 0;
275+
std::vector<index_type> induced_hyperedge;
276+
for(index_type node : vertices_in_hyperedge[hyperedge])
277+
if(include[node])
278+
{
279+
induced_hyperedge.push_back(new_index[node]);
280+
++nr_induced_pins;
281+
}
282+
283+
if(nr_induced_pins >= 2)
284+
hgraph.add_hyperedge(induced_hyperedge, hyperedge_weights[hyperedge]);
285+
}
286+
return hgraph;
287+
}
288+
250289
} // namespace osp

include/osp/partitioning/partitioners/generic_FM.hpp

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

tests/hypergraph_and_partition.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,30 @@ BOOST_AUTO_TEST_CASE(Hypergraph_and_Partition_test) {
184184

185185
original_cost = partition_to_improve.computeConnectivityCost();
186186

187+
fm.setMaxNodesInPart(0);
187188
fm.ImprovePartitioning(partition_to_improve);
188189
new_cost = partition_to_improve.computeConnectivityCost();
189190

190191
BOOST_CHECK(partition_to_improve.satisfiesBalanceConstraint());
191192
BOOST_CHECK(new_cost <= original_cost);
192193
std::cout<<original_cost<<" --> "<<new_cost<<std::endl;
193194

195+
// Recursive FM
196+
instance.setNumberOfPartitions(16);
197+
instance.setMaxWorkWeightViaImbalanceFactor(0.3);
198+
199+
for(unsigned node = 0; node < instance.getHypergraph().num_vertices(); ++node)
200+
partition_to_improve.setAssignedPartition(node, node % 16);
201+
202+
original_cost = partition_to_improve.computeConnectivityCost();
203+
204+
fm.setMaxNodesInPart(0);
205+
fm.RecursiveFM(partition_to_improve);
206+
new_cost = partition_to_improve.computeConnectivityCost();
207+
208+
BOOST_CHECK(partition_to_improve.satisfiesBalanceConstraint());
209+
BOOST_CHECK(new_cost <= original_cost);
210+
std::cout<<original_cost<<" --> "<<new_cost<<std::endl;
211+
212+
194213
};

0 commit comments

Comments
 (0)