void bipartition::initial_partition( const PartitionConfig & config, const unsigned int seed, graph_access & G, int* partition_map) { timer t; t.restart(); unsigned iterations = config.bipartition_tries; EdgeWeight best_cut = std::numeric_limits<EdgeWeight>::max(); int best_load = std::numeric_limits<int>::max(); for( unsigned i = 0; i < iterations; i++) { if(config.bipartition_algorithm == BIPARTITION_BFS) { grow_regions_bfs(config, G); } else if( config.bipartition_algorithm == BIPARTITION_FM) { grow_regions_fm(config, G); } G.set_partition_count(2); post_fm(config, G); quality_metrics qm; EdgeWeight curcut = qm.edge_cut(G); int lhs_block_weight = 0; int rhs_block_weight = 0; forall_nodes(G, node) { if(G.getPartitionIndex(node) == 0) { lhs_block_weight += G.getNodeWeight(node); } else { rhs_block_weight += G.getNodeWeight(node); } } endfor int lhs_overload = std::max(lhs_block_weight - config.target_weights[0],0); int rhs_overload = std::max(rhs_block_weight - config.target_weights[1],0); if(curcut < best_cut || (curcut == best_cut && lhs_overload + rhs_block_weight < best_load) ) { //store it best_cut = curcut; best_load = lhs_overload + rhs_overload; forall_nodes(G, n) { partition_map[n] = G.getPartitionIndex(n); } endfor }
void graph_extractor::extract_block(graph_access & G, graph_access & extracted_block, PartitionID block, std::vector<NodeID> & mapping) { // build reverse mapping std::vector<NodeID> reverse_mapping; NodeID nodes = 0; NodeID dummy_node = G.number_of_nodes() + 1; forall_nodes(G, node) { if(G.getPartitionIndex(node) == block) { reverse_mapping.push_back(nodes++); } else { reverse_mapping.push_back(dummy_node); } } endfor extracted_block.start_construction(nodes, G.number_of_edges()); forall_nodes(G, node) { if(G.getPartitionIndex(node) == block) { NodeID new_node = extracted_block.new_node(); mapping.push_back(node); extracted_block.setNodeWeight( new_node, G.getNodeWeight(node)); forall_out_edges(G, e, node) { NodeID target = G.getEdgeTarget(e); if( G.getPartitionIndex( target ) == block ) { EdgeID new_edge = extracted_block.new_edge(new_node, reverse_mapping[target]); extracted_block.setEdgeWeight(new_edge, G.getEdgeWeight(e)); } } endfor }
void fast_construct_mapping::construct_initial_mapping_bottomup_internal( PartitionConfig & config, graph_access & C, matrix & D, int idx, std::vector< NodeID > & perm_rank) { PartitionID num_parts = C.number_of_nodes()/config.group_sizes[idx]; partition_C_perfectly_balanced( config, C, num_parts); if( idx ==(int)(config.group_sizes.size() - 1) ) { // build initial offsets int nodes_per_block = m_tmp_num_nodes / config.group_sizes[idx]; perm_rank[0] = 0; for( unsigned int block = 1; block < perm_rank.size(); block++) { perm_rank[block] = perm_rank[block-1]+nodes_per_block; } } else { //contract partitioned graph graph_access Q; complete_boundary bnd(&C); bnd.build(); bnd.getUnderlyingQuotientGraph(Q); std::vector< NodeID > rec_ranks( num_parts, 0); construct_initial_mapping_bottomup_internal( config, Q, D, idx+1, rec_ranks); //recompute offsets forall_nodes(C, node) { PartitionID block = C.getPartitionIndex(node); perm_rank[node] = rec_ranks[block]; rec_ranks[block] += C.getNodeWeight(node); } endfor }
void kway_graph_refinement_core::move_node_back(PartitionConfig & config, graph_access & G, NodeID & node, PartitionID & to, vertex_moved_hashtable & moved_idx, refinement_pq * queue, complete_boundary & boundary) { PartitionID from = G.getPartitionIndex(node); G.setPartitionIndex(node, to); boundary_pair pair; pair.k = config.k; pair.lhs = from; pair.rhs = to; //update all boundaries boundary.postMovedBoundaryNodeUpdates(node, &pair, true, true); NodeWeight this_nodes_weight = G.getNodeWeight(node); boundary.setBlockNoNodes(from, boundary.getBlockNoNodes(from)-1); boundary.setBlockNoNodes(to, boundary.getBlockNoNodes(to)+1); boundary.setBlockWeight( from, boundary.getBlockWeight(from)-this_nodes_weight); boundary.setBlockWeight( to, boundary.getBlockWeight(to)+this_nodes_weight); }
int graph_io::writeGraphWeighted(graph_access & G, std::string filename) { std::ofstream f(filename.c_str()); f << G.number_of_nodes() << " " << G.number_of_edges()/2 << " 11" << std::endl; forall_nodes(G, node) { f << G.getNodeWeight(node) ; forall_out_edges(G, e, node) { f << " " << (G.getEdgeTarget(e)+1) << " " << G.getEdgeWeight(e) ; } endfor
void most_balanced_minimum_cuts::compute_good_balanced_min_cut( graph_access & residualGraph, const PartitionConfig & config, NodeWeight & perfect_rhs_weight, std::vector< NodeID > & new_rhs_nodes ) { strongly_connected_components scc; std::vector<int> components(residualGraph.number_of_nodes()); int comp_count = scc.strong_components(residualGraph,components); std::vector< std::vector<NodeID> > comp_nodes(comp_count); std::vector< NodeWeight > comp_weights(comp_count, 0); forall_nodes(residualGraph, node) { comp_nodes[components[node]].push_back(node); comp_weights[components[node]] += residualGraph.getNodeWeight(node); } endfor
// for documentation see technical reports of christian schulz void contraction::contract(const PartitionConfig & partition_config, graph_access & G, graph_access & coarser, const Matching & edge_matching, const CoarseMapping & coarse_mapping, const NodeID & no_of_coarse_vertices, const NodePermutationMap & permutation) const { if(partition_config.combine) { coarser.resizeSecondPartitionIndex(no_of_coarse_vertices); } std::vector<NodeID> new_edge_targets(G.number_of_edges()); forall_edges(G, e) { new_edge_targets[e] = coarse_mapping[G.getEdgeTarget(e)]; } endfor std::vector<EdgeID> edge_positions(no_of_coarse_vertices, UNDEFINED_EDGE); //we dont know the number of edges jet, so we use the old number for //construction of the coarser graph and then resize the field according //to the number of edges we really got coarser.start_construction(no_of_coarse_vertices, G.number_of_edges()); NodeID cur_no_vertices = 0; forall_nodes(G, n) { NodeID node = permutation[n]; //we look only at the coarser nodes if(coarse_mapping[node] != cur_no_vertices) continue; NodeID coarseNode = coarser.new_node(); coarser.setNodeWeight(coarseNode, G.getNodeWeight(node)); if(partition_config.combine) { coarser.setSecondPartitionIndex(coarseNode, G.getSecondPartitionIndex(node)); } // do something with all outgoing edges (in auxillary graph) forall_out_edges(G, e, node) { visit_edge(G, coarser, edge_positions, coarseNode, e, new_edge_targets); } endfor
EdgeWeight cycle_refinement::greedy_ultra_model_plus(PartitionConfig & partition_config, graph_access & G, complete_boundary & boundary) { unsigned s = partition_config.kaba_internal_no_aug_steps_aug; bool something_changed = false; bool overloaded = false; augmented_Qgraph_fabric augmented_fabric; bool first_level = true; forall_nodes(G, node) { if(G.getNodeWeight(node) != 1) { first_level = false; break; } } endfor int unsucc_count = 0; do { augmented_Qgraph aqg; augmented_fabric.build_augmented_quotient_graph(partition_config, G, boundary, aqg, s, false, true); something_changed = m_advanced_modelling.compute_vertex_movements_ultra_model(partition_config, G, boundary, aqg, s, false); if( something_changed ) { unsucc_count = 0; } else { unsucc_count++; } if(unsucc_count > 2 && unsucc_count < 19) { something_changed = m_advanced_modelling.compute_vertex_movements_ultra_model(partition_config, G, boundary, aqg, s, true); } if(unsucc_count > 19 && first_level) { graph_access G_bar; boundary.getUnderlyingQuotientGraph(G_bar); overloaded = false; forall_nodes(G_bar, block) { if(boundary.getBlockWeight(block) > partition_config.upper_bound_partition ) { overloaded = true; break; } } endfor if(overloaded) { augmented_Qgraph aqg_rebal; bool moves_performed = augmented_fabric.build_augmented_quotient_graph(partition_config, G, boundary, aqg_rebal, s, true, true); if(!moves_performed) { m_advanced_modelling.compute_vertex_movements_rebalance(partition_config, G, boundary, aqg_rebal, s); } // else the fall back solution has been applied } } } while(unsucc_count < 20 || overloaded); return 0; }
void two_way_fm::move_node_back(const PartitionConfig & config, graph_access & G, const NodeID & node, vertex_moved_hashtable & moved_idx, refinement_pq * from_queue, refinement_pq * to_queue, PartitionID from, PartitionID to, boundary_pair * pair, NodeWeight * from_part_weight, NodeWeight * to_part_weight, complete_boundary & boundary) { ASSERT_NEQ(from, to); ASSERT_EQ(from, G.getPartitionIndex(node)); //move node G.setPartitionIndex(node, to); boundary.deleteNode(node, from, pair); EdgeWeight int_degree_node = 0; EdgeWeight ext_degree_node = 0; bool update_difficult = int_ext_degree(G, node, to, from, int_degree_node, ext_degree_node); if(ext_degree_node > 0) { boundary.insert(node, to, pair); } if(update_difficult) { boundary.postMovedBoundaryNodeUpdates(node, pair, true, false); } NodeWeight this_nodes_weight = G.getNodeWeight(node); (*from_part_weight) -= this_nodes_weight; (*to_part_weight) += this_nodes_weight; //update neighbors forall_out_edges(G, e, node) { NodeID target = G.getEdgeTarget(e); PartitionID targets_partition = G.getPartitionIndex(target); if((targets_partition != from && targets_partition != to)) { //at most difficult update nec. continue; //they dont need to be updated during this refinement } EdgeWeight int_degree = 0; EdgeWeight ext_degree = 0; PartitionID other_partition = targets_partition == from ? to : from; int_ext_degree(G, target, targets_partition, other_partition, int_degree, ext_degree); if(boundary.contains(target, targets_partition, pair)) { if(ext_degree == 0) { boundary.deleteNode(target, targets_partition, pair); } } else { if(ext_degree > 0) { boundary.insert(target, targets_partition, pair); } } } endfor
void two_way_fm::move_node(const PartitionConfig & config, graph_access & G, const NodeID & node, vertex_moved_hashtable & moved_idx, refinement_pq * from_queue, refinement_pq * to_queue, PartitionID from, PartitionID to, boundary_pair * pair, NodeWeight * from_part_weight, NodeWeight * to_part_weight, complete_boundary & boundary) { //move node G.setPartitionIndex(node, to); boundary.deleteNode(node, from, pair); EdgeWeight int_degree_node = 0; EdgeWeight ext_degree_node = 0; bool difficult_update = int_ext_degree(G, node, to, from, int_degree_node, ext_degree_node); if(ext_degree_node > 0) { boundary.insert(node, to, pair); } if(difficult_update) boundary.postMovedBoundaryNodeUpdates(node, pair, true, false); NodeWeight this_nodes_weight = G.getNodeWeight(node); (*from_part_weight) -= this_nodes_weight; (*to_part_weight) += this_nodes_weight; //update neighbors forall_out_edges(G, e, node) { NodeID target = G.getEdgeTarget(e); PartitionID targets_partition = G.getPartitionIndex(target); if((targets_partition != from && targets_partition != to)) { continue; } EdgeWeight int_degree = 0; EdgeWeight ext_degree = 0; PartitionID other_partition = targets_partition == from ? to : from; int_ext_degree(G, target, targets_partition, other_partition, int_degree, ext_degree); refinement_pq * queue_to_update = 0; if(targets_partition == from) { queue_to_update = from_queue; } else { queue_to_update = to_queue; } Gain gain = ext_degree - int_degree; if(queue_to_update->contains(target)) { if(ext_degree == 0) { queue_to_update->deleteNode(target); boundary.deleteNode(target, targets_partition, pair); } else { queue_to_update->changeKey(target, gain); } } else { if(ext_degree > 0) { if(moved_idx[target].index == NOT_MOVED) { queue_to_update->insert(target, gain); } boundary.insert(target, targets_partition, pair); } else { boundary.deleteNode(target, targets_partition, pair); } } } endfor