Beispiel #1
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;
}
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; 
}