コード例 #1
0
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
コード例 #2
0
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);
}
コード例 #3
0
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 {
コード例 #4
0
ファイル: cycle_refinement.cpp プロジェクト: gkuznets/KaHIP
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; 
}
コード例 #5
0
ファイル: cycle_refinement.cpp プロジェクト: gkuznets/KaHIP
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; 
}
コード例 #6
0
ファイル: two_way_fm.cpp プロジェクト: SebastianSchlag/KaHIP
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;
}
コード例 #7
0
ファイル: two_way_fm.cpp プロジェクト: SebastianSchlag/KaHIP
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
コード例 #8
0
ファイル: two_way_fm.cpp プロジェクト: SebastianSchlag/KaHIP
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
コード例 #9
0
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; 
}