void kway_graph_refinement::setup_start_nodes(PartitionConfig & config, graph_access & G, complete_boundary & boundary, boundary_starting_nodes & start_nodes) { QuotientGraphEdges quotient_graph_edges; boundary.getQuotientGraphEdges(quotient_graph_edges); unordered_map<NodeID, bool> allready_contained; for( unsigned i = 0; i < quotient_graph_edges.size(); i++) { boundary_pair & ret_value = quotient_graph_edges[i]; PartitionID lhs = ret_value.lhs; PartitionID rhs = ret_value.rhs; PartialBoundary & partial_boundary_lhs = boundary.getDirectedBoundary(lhs, lhs, rhs); forall_boundary_nodes(partial_boundary_lhs, cur_bnd_node) { ASSERT_EQ(G.getPartitionIndex(cur_bnd_node), lhs); if(allready_contained.find(cur_bnd_node) == allready_contained.end() ) { start_nodes.push_back(cur_bnd_node); allready_contained[cur_bnd_node] = true; } } endfor PartialBoundary & partial_boundary_rhs = boundary.getDirectedBoundary(rhs, lhs, rhs); forall_boundary_nodes(partial_boundary_rhs, cur_bnd_node) { ASSERT_EQ(G.getPartitionIndex(cur_bnd_node), rhs); if(allready_contained.find(cur_bnd_node) == allready_contained.end()) { start_nodes.push_back(cur_bnd_node); allready_contained[cur_bnd_node] = true; } } 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); }
bool augmented_Qgraph_fabric::build_augmented_quotient_graph( PartitionConfig & config, graph_access & G, complete_boundary & boundary, augmented_Qgraph & aqg, unsigned & s, bool rebalance, bool plus) { graph_access G_bar; boundary.getUnderlyingQuotientGraph(G_bar); if(m_eligible.size() != G.number_of_nodes()) { m_eligible.resize(G.number_of_nodes()); forall_nodes(G, node) { m_eligible[node] = true; } endfor } else {
EdgeWeight cycle_refinement::greedy_ultra_model(PartitionConfig & partition_config, graph_access & G, complete_boundary & boundary) { augmented_Qgraph_fabric augmented_fabric; unsigned s = partition_config.kaba_internal_no_aug_steps_aug; bool something_changed = false; bool overloaded = false; unsigned unsucc_count = 0; do { augmented_Qgraph aqg; augmented_fabric.build_augmented_quotient_graph(partition_config, G, boundary, aqg, s, false); 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 <= partition_config.kaba_unsucc_iterations && partition_config.kaba_enable_zero_weight_cycles) { something_changed = m_advanced_modelling.compute_vertex_movements_ultra_model(partition_config, G, boundary, aqg, s, true); } if(unsucc_count >= partition_config.kaba_unsucc_iterations ) { 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 movs_allready_performed = augmented_fabric.build_augmented_quotient_graph(partition_config, G, boundary, aqg_rebal, s, true); if(!movs_allready_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 < partition_config.kaba_unsucc_iterations || (overloaded)); return 0; }
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; }
EdgeWeight two_way_fm::perform_refinement(PartitionConfig & cfg, graph_access& G, complete_boundary & boundary, std::vector<NodeID> & lhs_start_nodes, std::vector<NodeID> & rhs_start_nodes, boundary_pair * pair, NodeWeight & lhs_part_weight, NodeWeight & rhs_part_weight, EdgeWeight & cut, bool & something_changed) { PartitionConfig config = cfg;//copy it since we make changes on that if(lhs_start_nodes.size() == 0 or rhs_start_nodes.size() == 0) return 0; // nothing to refine quality_metrics qm; ASSERT_NEQ(pair->lhs, pair->rhs); ASSERT_TRUE(assert_directed_boundary_condition(G, boundary, pair->lhs, pair->rhs)); ASSERT_EQ( cut, qm.edge_cut(G, pair->lhs, pair->rhs)); refinement_pq* lhs_queue = NULL; refinement_pq* rhs_queue = NULL; if(config.use_bucket_queues) { EdgeWeight max_degree = G.getMaxDegree(); lhs_queue = new bucket_pq(max_degree); rhs_queue = new bucket_pq(max_degree); } else { lhs_queue = new maxNodeHeap(); rhs_queue = new maxNodeHeap(); } init_queue_with_boundary(config, G, lhs_start_nodes, lhs_queue, pair->lhs, pair->rhs); init_queue_with_boundary(config, G, rhs_start_nodes, rhs_queue, pair->rhs, pair->lhs); queue_selection_strategy* topgain_queue_select = new queue_selection_topgain(config); queue_selection_strategy* diffusion_queue_select = new queue_selection_diffusion(config); queue_selection_strategy* diffusion_queue_select_block_target = new queue_selection_diffusion_block_targets(config); vertex_moved_hashtable moved_idx; std::vector<NodeID> transpositions; EdgeWeight inital_cut = cut; int max_number_of_swaps = (int)(boundary.getBlockNoNodes(pair->lhs) + boundary.getBlockNoNodes(pair->rhs)); int step_limit = (int)((config.fm_search_limit/100.0)*max_number_of_swaps); step_limit = std::max(step_limit, 15); int min_cut_index = -1; refinement_pq* from_queue = 0; refinement_pq* to_queue = 0; PartitionID from = 0; PartitionID to = 0; NodeWeight * from_part_weight = 0; NodeWeight * to_part_weight = 0; stop_rule* st_rule = new easy_stop_rule(); partition_accept_rule* accept_partition = NULL; if(config.initial_bipartitioning) { accept_partition = new ip_partition_accept_rule(config, cut,lhs_part_weight, rhs_part_weight, pair->lhs, pair->rhs); } else { accept_partition = new normal_partition_accept_rule(config, cut,lhs_part_weight, rhs_part_weight); } queue_selection_strategy* q_select; if(config.softrebalance || config.rebalance || config.initial_bipartitioning) { if(config.initial_bipartitioning) { q_select = diffusion_queue_select_block_target; } else { q_select = diffusion_queue_select; } } else { q_select = topgain_queue_select; } //roll forwards EdgeWeight best_cut = cut; int number_of_swaps = 0; for(number_of_swaps = 0; number_of_swaps < max_number_of_swaps; number_of_swaps++) { if(st_rule->search_should_stop(min_cut_index, number_of_swaps, step_limit)) break; if(lhs_queue->empty() && rhs_queue->empty()) { break; } q_select->selectQueue(lhs_part_weight, rhs_part_weight, pair->lhs, pair->rhs, from,to, lhs_queue, rhs_queue, &from_queue, &to_queue); if(!from_queue->empty()) { Gain gain = from_queue->maxValue(); NodeID node = from_queue->deleteMax(); ASSERT_TRUE(moved_idx[node].index == NOT_MOVED); boundary.setBlockNoNodes(from, boundary.getBlockNoNodes(from)-1); boundary.setBlockNoNodes(to, boundary.getBlockNoNodes(to)+1); if(from == pair->lhs) { from_part_weight = &lhs_part_weight; to_part_weight = &rhs_part_weight; } else { from_part_weight = &rhs_part_weight; to_part_weight = &lhs_part_weight; } move_node(config, G, node, moved_idx, from_queue, to_queue, from, to, pair, from_part_weight, to_part_weight, boundary); cut -= gain; if( accept_partition->accept_partition(config, cut, lhs_part_weight, rhs_part_weight, pair->lhs, pair->rhs, config.rebalance)) { ASSERT_TRUE( cut <= best_cut || config.rebalance); if( cut < best_cut ) { something_changed = true; } best_cut = cut; min_cut_index = number_of_swaps; } transpositions.push_back(node); moved_idx[node].index = MOVED; } else { break; } } ASSERT_TRUE(assert_directed_boundary_condition(G, boundary, pair->lhs, pair->rhs)); ASSERT_EQ( cut, qm.edge_cut(G, pair->lhs, pair->rhs)); //roll backwards for(number_of_swaps--; number_of_swaps > min_cut_index; number_of_swaps--) { ASSERT_TRUE(transpositions.size() > 0); NodeID node = transpositions.back(); transpositions.pop_back(); PartitionID nodes_partition = G.getPartitionIndex(node); if(nodes_partition == pair->lhs) { from_queue = lhs_queue; to_queue = rhs_queue; from = pair->lhs; to = pair->rhs; from_part_weight = &lhs_part_weight; to_part_weight = &rhs_part_weight; } else { from_queue = rhs_queue; to_queue = lhs_queue; from = pair->rhs; to = pair->lhs; from_part_weight = &rhs_part_weight; to_part_weight = &lhs_part_weight; } boundary.setBlockNoNodes(from, boundary.getBlockNoNodes(from)-1); boundary.setBlockNoNodes(to, boundary.getBlockNoNodes(to)+1); move_node_back(config, G, node, moved_idx, from_queue, to_queue, from, to, pair, from_part_weight, to_part_weight, boundary); } //clean up cut = best_cut; boundary.setEdgeCut(pair, best_cut); boundary.setBlockWeight(pair->lhs, lhs_part_weight); boundary.setBlockWeight(pair->rhs, rhs_part_weight); delete lhs_queue; delete rhs_queue; delete topgain_queue_select; delete diffusion_queue_select; delete diffusion_queue_select_block_target; delete st_rule; delete accept_partition; ASSERT_EQ( cut, qm.edge_cut(G, pair->lhs, pair->rhs)); ASSERT_TRUE(assert_directed_boundary_condition(G, boundary, pair->lhs, pair->rhs)); ASSERT_TRUE( (int)inital_cut-(int)best_cut >= 0 || cfg.rebalance); // the computed partition shouldnt have a edge cut which is worse than the initial one return inital_cut-best_cut; }
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
EdgeWeight kway_graph_refinement_core::single_kway_refinement_round_internal(PartitionConfig & config, graph_access & G, complete_boundary & boundary, boundary_starting_nodes & start_nodes, int step_limit, vertex_moved_hashtable & moved_idx, bool compute_touched_partitions, std::unordered_map<PartitionID, PartitionID> & touched_blocks) { commons = kway_graph_refinement_commons::getInstance(config); refinement_pq* queue = NULL; if(config.use_bucket_queues) { EdgeWeight max_degree = G.getMaxDegree(); queue = new bucket_pq(max_degree); } else { queue = new maxNodeHeap(); } init_queue_with_boundary(config, G, start_nodes, queue, moved_idx); if(queue->empty()) {delete queue; return 0;} std::vector<NodeID> transpositions; std::vector<PartitionID> from_partitions; std::vector<PartitionID> to_partitions; int max_number_of_swaps = (int)(G.number_of_nodes()); int min_cut_index = -1; EdgeWeight cut = std::numeric_limits<int>::max()/2; // so we dont need to compute the edge cut EdgeWeight initial_cut = cut; //roll forwards EdgeWeight best_cut = cut; int number_of_swaps = 0; int movements = 0; kway_stop_rule* stopping_rule = NULL; switch(config.kway_stop_rule) { case KWAY_SIMPLE_STOP_RULE: stopping_rule = new kway_simple_stop_rule(config); break; case KWAY_ADAPTIVE_STOP_RULE: stopping_rule = new kway_adaptive_stop_rule(config); break; } for(number_of_swaps = 0, movements = 0; movements < max_number_of_swaps; movements++, number_of_swaps++) { if( queue->empty() ) break; if( stopping_rule->search_should_stop(min_cut_index, number_of_swaps, step_limit) ) break; Gain gain = queue->maxValue(); NodeID node = queue->deleteMax(); #ifndef NDEBUG PartitionID maxgainer; EdgeWeight ext_degree; ASSERT_TRUE(moved_idx[node].index == NOT_MOVED); ASSERT_EQ(gain, commons->compute_gain(G, node, maxgainer, ext_degree)); ASSERT_TRUE(ext_degree > 0); #endif PartitionID from = G.getPartitionIndex(node); bool successfull = move_node(config, G, node, moved_idx, queue, boundary); if(successfull) { cut -= gain; stopping_rule->push_statistics(gain); bool accept_equal = random_functions::nextBool(); if( cut < best_cut || ( cut == best_cut && accept_equal )) { best_cut = cut; min_cut_index = number_of_swaps; if(cut < best_cut) stopping_rule->reset_statistics(); } from_partitions.push_back(from); to_partitions.push_back(G.getPartitionIndex(node)); transpositions.push_back(node); } else { number_of_swaps--; //because it wasnt swaps } moved_idx[node].index = MOVED; ASSERT_TRUE(boundary.assert_bnodes_in_boundaries()); ASSERT_TRUE(boundary.assert_boundaries_are_bnodes()); } ASSERT_TRUE(boundary.assert_bnodes_in_boundaries()); ASSERT_TRUE(boundary.assert_boundaries_are_bnodes()); //roll backwards for(number_of_swaps--; number_of_swaps>min_cut_index; number_of_swaps--) { ASSERT_TRUE(transpositions.size() > 0); NodeID node = transpositions.back(); transpositions.pop_back(); PartitionID to = from_partitions.back(); from_partitions.pop_back(); to_partitions.pop_back(); move_node_back(config, G, node, to, moved_idx, queue, boundary); } //reconstruct the touched partitions if(compute_touched_partitions) { ASSERT_EQ(from_partitions.size(), to_partitions.size()); for(unsigned i = 0; i < from_partitions.size(); i++) { touched_blocks[from_partitions[i]] = from_partitions[i]; touched_blocks[to_partitions[i]] = to_partitions[i]; } } ASSERT_TRUE(boundary.assert_bnodes_in_boundaries()); ASSERT_TRUE(boundary.assert_boundaries_are_bnodes()); delete queue; delete stopping_rule; return initial_cut - best_cut; }