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; }
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; }