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 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
EdgeWeight quality_metrics::edge_cut(graph_access & G) { EdgeWeight edgeCut = 0; forall_nodes(G, n) { PartitionID partitionIDSource = G.getPartitionIndex(n); forall_out_edges(G, e, n) { NodeID targetNode = G.getEdgeTarget(e); PartitionID partitionIDTarget = G.getPartitionIndex(targetNode); if (partitionIDSource != partitionIDTarget) { edgeCut += G.getEdgeWeight(e); } } endfor
EdgeWeight parallel_mh_async::collect_best_partitioning(graph_access & G) { //perform partitioning locally EdgeWeight min_objective = 0; m_island->apply_fittest(G, min_objective); int best_local_objective = min_objective; int best_global_objective = 0; PartitionID* best_local_map = new PartitionID[G.number_of_nodes()]; std::vector< NodeWeight > block_sizes(G.get_partition_count(),0); forall_nodes(G, node) { best_local_map[node] = G.getPartitionIndex(node); block_sizes[G.getPartitionIndex(node)]++; } endfor
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 two_way_fm::init_queue_with_boundary(const PartitionConfig & config, graph_access & G, std::vector<NodeID> & bnd_nodes, refinement_pq * queue, PartitionID partition_of_boundary, PartitionID other) { if(config.permutation_during_refinement == PERMUTATION_QUALITY_FAST) { random_functions::permutate_vector_fast(bnd_nodes, false); } else if(config.permutation_during_refinement == PERMUTATION_QUALITY_GOOD) { random_functions::permutate_vector_good(bnd_nodes, false); } for( unsigned int i = 0, end = bnd_nodes.size(); i < end; i++) { NodeID cur_bnd_node = bnd_nodes[i]; //compute gain EdgeWeight int_degree = 0; EdgeWeight ext_degree = 0; int_ext_degree(G, cur_bnd_node, partition_of_boundary, other, int_degree, ext_degree); Gain gain = ext_degree - int_degree; queue->insert(cur_bnd_node, gain); ASSERT_TRUE(ext_degree > 0); ASSERT_EQ(partition_of_boundary, G.getPartitionIndex(cur_bnd_node)); } }
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); }
void initial_partition_bipartition::initial_partition( const PartitionConfig & config, const unsigned int seed, graph_access & G, int* partition_map) { graph_partitioner gp; PartitionConfig rec_config = config; rec_config.initial_partitioning_type = INITIAL_PARTITIONING_BIPARTITION; rec_config.initial_partitioning_repetitions = 0; rec_config.global_cycle_iterations = 1; rec_config.use_wcycles = false; rec_config.use_fullmultigrid = false; rec_config.fm_search_limit = config.bipartition_post_ml_limits; rec_config.matching_type = MATCHING_GPA; //rec_config.matching_type = CLUSTER_COARSENING; rec_config.permutation_quality = PERMUTATION_QUALITY_GOOD; rec_config.initial_partitioning = true; std::streambuf* backup = std::cout.rdbuf(); std::ofstream ofs; ofs.open("/dev/null"); std::cout.rdbuf(ofs.rdbuf()); gp.perform_recursive_partitioning(rec_config, G); ofs.close(); std::cout.rdbuf(backup); forall_nodes(G, n) { partition_map[n] = G.getPartitionIndex(n); } endfor
bool vertex_separator_flow_solver::construct_flow_pb( const PartitionConfig & config, graph_access & G, PartitionID & lhs, PartitionID & rhs, std::vector<NodeID> & lhs_nodes, std::vector<NodeID> & rhs_nodes, std::vector<NodeID> & new_to_old_ids, long *n_ad, long* m_ad, node** nodes_ad, arc** arcs_ad, long ** cap_ad, node** source_ad, node** sink_ad, long* node_min_ad, EdgeID & no_edges_in_flow_graph) { //very dirty for loading variables :). some time this should all be refactored. for now we can focus on the important stuff. #include "../refinement/quotient_graph_refinement/flow_refinement/flow_solving_kernel/convert_ds_variables.h" //building up the graph as in parse.h of hi_pr code //first we have to count the number of edges // s to lhs + rhs to t + lhs to rhs unsigned no_edges = 0; for( unsigned i = 0; i < lhs_nodes.size(); i++) { NodeID node = lhs_nodes[i]; forall_out_edges(G, e, node) { NodeID target = G.getEdgeTarget(e); if(rhs == G.getPartitionIndex(target)) { ++no_edges; } } endfor }
void mis_permutation::construct(graph_access & G) { inconsistencies = 0; solution_size = 0; free_size = 0; total_size = G.number_of_nodes(); nodes.clear(); tightness.clear(); position.clear(); nodes.resize(total_size); tightness.resize(total_size); position.resize(total_size); onetight_all.init(G.number_of_nodes()); // Insert solution nodes forall_nodes(G, n) { nodes[n] = n; position[n] = n; unsigned int index = G.getPartitionIndex(n); // Maybe implement tightness calculations here if (index == 1) { move_to_solution(n, G); } else { int tight = calculate_tightness(n, G); tightness[n] = tight; if (tight == 0) move_to_free(n, G); else move_to_non_free(n, G); if (tight == 1) onetight_all.insert(n); } } endfor
void partition_snapshooter::addSnapshot(graph_access & G) { std::cout << "idx " << m_partition_map_buffer.size() << std::endl; std::vector<PartitionID>* partition_map = new std::vector<PartitionID>(); m_partition_map_buffer.push_back(partition_map); forall_nodes(G, node) { partition_map->push_back(G.getPartitionIndex(node)); } endfor
int mis_permutation::calculate_tightness(NodeID node, graph_access & G) { int tightness = 0; forall_out_edges(G, edge, node) { NodeID target = G.getEdgeTarget(edge); bool target_index = G.getPartitionIndex(target); if (target_index == 1) { tightness++; } } endfor
EdgeWeight tabu_search::perform_refinement(PartitionConfig & config, graph_access & G, complete_boundary & boundary) { quality_metrics qm; EdgeWeight input_cut = qm.edge_cut(G); EdgeWeight cur_cut = input_cut; EdgeWeight best_cut = input_cut; std::vector< PartitionID > bestmap(G.number_of_nodes(), 0); forall_nodes(G, node) { bestmap[node] = G.getPartitionIndex(node); } endfor
unsigned int population_mis::create_solution(graph_access & G, NodeID *solution) { unsigned int solution_size = 0; forall_nodes(G, node) { if (G.getPartitionIndex(node) == 1) { solution[node] = 1; solution_size++; } else solution[node] = 0; } endfor return solution_size; }
EdgeID edge_cut_flow_solver::regions_no_edges( graph_access & G, std::vector<NodeID> & lhs_boundary_stripe, std::vector<NodeID> & rhs_boundary_stripe, PartitionID & lhs, PartitionID & rhs, std::vector<NodeID> & outer_lhs_boundary_nodes, std::vector<NodeID> & outer_rhs_boundary_nodes ) { EdgeID no_of_edges = 0; unsigned idx = 0; for( unsigned i = 0; i < lhs_boundary_stripe.size(); i++, idx++) { NodeID node = lhs_boundary_stripe[i]; bool is_outer_boundary = false; forall_out_edges(G, e, node) { if(G.getPartitionIndex(G.getEdgeTarget(e)) == BOUNDARY_STRIPE_NODE) no_of_edges++; else is_outer_boundary = true; } endfor if(is_outer_boundary) { outer_lhs_boundary_nodes.push_back(idx); } } for( unsigned i = 0; i < rhs_boundary_stripe.size(); i++, idx++) { NodeID node = rhs_boundary_stripe[i]; bool is_outer_boundary = false; forall_out_edges(G, e, node) { if(G.getPartitionIndex(G.getEdgeTarget(e)) == BOUNDARY_STRIPE_NODE) no_of_edges++; else is_outer_boundary = true; } endfor if(is_outer_boundary) { outer_rhs_boundary_nodes.push_back(idx); } } return no_of_edges; }
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; }
bool population_mis::insert(MISConfig & config, graph_access & G, individuum_mis & ind) { ASSERT_TRUE(is_mis(config, G, ind)); bool successful_insertion = false; if (internal_population.size() < population_size) { ind.id = internal_population.size(); internal_population.push_back(ind); } else { unsigned int worst_solution = std::numeric_limits<unsigned int>::max(); unsigned int worst_id = 0; // Get worst solution for (unsigned int i = 0; i < internal_population.size(); ++i) { if (internal_population[i].solution_size < worst_solution) { worst_solution = internal_population[i].solution_size; worst_id = i; } } individuum_mis worst = internal_population[worst_id]; // Should the solution be inserted by force? if (insert_no_change > config.insert_threshold) { // std::cout << "Force" << std::endl; set_mis_for_individuum(config, G, ind); ils iterate; iterate.perform_ils(config, G, config.ils_iterations); ind.solution_size = 0; forall_nodes(G, node) { if (G.getPartitionIndex(node) == 1) ind.solution_size++; ind.solution[node] = G.getPartitionIndex(node); } endfor replace(worst, ind); insert_no_change = 0; return true; } // Is the solution bigger than any so far? if (ind.solution_size <= worst_solution) { // std::cout << "Worse" << std::endl; insert_no_change++; delete [] ind.solution; ind.solution = NULL; return false; } // Else perform ILS and search most similar set_mis_for_individuum(config, G, ind); ils iterate; iterate.perform_ils(config, G, config.ils_iterations); ind.solution_size = 0; forall_nodes(G, node) { if (G.getPartitionIndex(node) == 1) ind.solution_size++; ind.solution[node] = G.getPartitionIndex(node); } endfor individuum_mis remove; bool valid_replacement = get_most_similar_replacement(config, G, ind, remove); if (!valid_replacement) { // std::cout << "Not Valid" << ind.solution_size << std::endl; insert_no_change++; delete [] ind.solution; ind.solution = NULL; return false; } else { // std::cout << "Valid: " << ind.solution_size << std::endl; replace(remove, ind); successful_insertion = true; insert_no_change = 0; } }
// implements our version of gal combine // compute a matching between blocks (greedily) // extend to partition // apply our refinements and tabu search void gal_combine::perform_gal_combine( PartitionConfig & config, graph_access & G) { //first greedily compute a matching of the partitions std::vector< std::unordered_map<PartitionID, unsigned> > counters(config.k); forall_nodes(G, node) { //boundary_pair bp; if(counters[G.getPartitionIndex(node)].find(G.getSecondPartitionIndex(node)) != counters[G.getPartitionIndex(node)].end()) { counters[G.getPartitionIndex(node)][G.getSecondPartitionIndex(node)] += 1; } else { counters[G.getPartitionIndex(node)][G.getSecondPartitionIndex(node)] = 1; } } endfor std::vector< PartitionID > permutation(config.k); for( unsigned i = 0; i < permutation.size(); i++) { permutation[i] = i; } random_functions::permutate_vector_good_small(permutation); std::vector<bool> rhs_matched(config.k, false); std::vector<PartitionID> bipartite_matching(config.k); for( unsigned i = 0; i < permutation.size(); i++) { PartitionID cur_partition = permutation[i]; PartitionID best_unassigned = config.k; NodeWeight best_value = 0; for( std::unordered_map<PartitionID, unsigned>::iterator it = counters[cur_partition].begin(); it != counters[cur_partition].end(); ++it) { if( rhs_matched[it->first] == false && it->second > best_value ) { best_unassigned = it->first; best_value = it->second; } } bipartite_matching[cur_partition] = best_unassigned; if( best_unassigned != config.k ) { rhs_matched[best_unassigned] = true; } } std::vector<bool> blocked_vertices(G.number_of_nodes(), false); forall_nodes(G, node) { if( bipartite_matching[G.getPartitionIndex(node)] == G.getSecondPartitionIndex(node) ){ blocked_vertices[node] = true; } else { // we will reassign this vertex since the partitions do not agree on it G.setPartitionIndex(node, config.k); } } endfor construct_partition cp; cp.construct_starting_from_partition( config, G ); refinement* refine = new mixed_refinement(); double real_epsilon = config.imbalance/100.0; double epsilon = random_functions::nextDouble(real_epsilon+0.005,real_epsilon+config.kabaE_internal_bal); PartitionConfig copy = config; copy.upper_bound_partition = (1+epsilon)*ceil(config.largest_graph_weight/(double)config.k); complete_boundary boundary(&G); boundary.build(); tabu_search ts; ts.perform_refinement( copy, G, boundary); //now obtain the quotient graph complete_boundary boundary2(&G); boundary2.build(); copy = config; copy.upper_bound_partition = (1+epsilon)*ceil(config.largest_graph_weight/(double)config.k); refine->perform_refinement( copy, G, boundary2); copy = config; cycle_refinement cr; cr.perform_refinement(config, G, boundary2); delete refine; }
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
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
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 edge_cut_flow_solver::convert_ds( const PartitionConfig & config, graph_access & G, PartitionID & lhs, PartitionID & rhs, std::vector<NodeID> & lhs_boundary_stripe, std::vector<NodeID> & rhs_boundary_stripe, std::vector<NodeID> & new_to_old_ids, long *n_ad, long* m_ad, node** nodes_ad, arc** arcs_ad, long ** cap_ad, node** source_ad, node** sink_ad, long* node_min_ad, EdgeID & no_edges_in_flow_graph) { //should soon be refactored #include "convert_ds_variables.h" //building up the graph as in parse.h of hi_pr code NodeID idx = 0; new_to_old_ids.resize(lhs_boundary_stripe.size() + rhs_boundary_stripe.size()); std::unordered_map<NodeID, NodeID> old_to_new; for( unsigned i = 0; i < lhs_boundary_stripe.size(); i++) { G.setPartitionIndex(lhs_boundary_stripe[i], BOUNDARY_STRIPE_NODE); new_to_old_ids[idx] = lhs_boundary_stripe[i]; old_to_new[lhs_boundary_stripe[i]] = idx++ ; } for( unsigned i = 0; i < rhs_boundary_stripe.size(); i++) { G.setPartitionIndex(rhs_boundary_stripe[i], BOUNDARY_STRIPE_NODE); new_to_old_ids[idx] = rhs_boundary_stripe[i]; old_to_new[rhs_boundary_stripe[i]] = idx++; } std::vector<NodeID> outer_lhs_boundary; std::vector<NodeID> outer_rhs_boundary; EdgeID no_edges = regions_no_edges(G, lhs_boundary_stripe, rhs_boundary_stripe, lhs, rhs, outer_lhs_boundary, outer_rhs_boundary); no_edges_in_flow_graph = no_edges; if(outer_lhs_boundary.size() == 0 || outer_rhs_boundary.size() == 0) return false; n = lhs_boundary_stripe.size() + rhs_boundary_stripe.size() + 2; //+source and target m = no_edges + outer_lhs_boundary.size() + outer_rhs_boundary.size(); nodes = (node*) calloc ( n+2, sizeof(node) ); arcs = (arc*) calloc ( 2*m+1, sizeof(arc) ); arc_tail = (long*) calloc ( 2*m, sizeof(long) ); arc_first= (long*) calloc ( n+2, sizeof(long) ); acap = (long*) calloc ( 2*m, sizeof(long) ); arc_current = arcs; node_max = 0; node_min = n; unsigned nodeoffset = 1; source = n - 2 + nodeoffset; sink = source+1; idx = 0; for( unsigned i = 0; i < lhs_boundary_stripe.size(); i++, idx++) { NodeID node = lhs_boundary_stripe[i]; NodeID sourceID = idx + nodeoffset; forall_out_edges(G, e, node) { if(G.getPartitionIndex(G.getEdgeTarget(e)) == BOUNDARY_STRIPE_NODE) { NodeID targetID = old_to_new[G.getEdgeTarget(e)] + nodeoffset; EdgeWeight capacity = G.getEdgeWeight(e); tail = sourceID; head = targetID; cap = capacity; createEdge() } } endfor }