bool improve_solution_2( graph<pair<int, int>>* solution, graph<int>& g1, graph<int>& g2, unordered_map<int, int>& g2_to_g1_mapping, unordered_set<int>& mapped_nodes, unordered_set<int>& unmapped_nodes, vector<int>& unmapped_nodes_vector, float neighbourhood_proportion, bool strict_comparisons, unsigned int tabu_list_size, priority_queue<movement, vector<movement>, movement_compare>& tabu_queue, movement_compare& mc, vector<movement>& tabu_list, bool allow_worse, const float time_delta, int& max_edge_diff, const float aspiration_threshold ) { enum action_type {none, swap, exchange}; vector<pair<int, int>> solution_vertices = solution->get_vertices(); vector<int> g2_vertices = g2.get_vertices(); bool use_tabu = tabu_list_size > 0; bool is_tabu_mapping = false; vector<pair<int, int>> tabu_free_mappings; vector<bool> tabu_free_mapping_type; bool any_improvement = false; int best_edge_diff = 0; action_type best_action = none; pair<int, int> best_node_1; pair<int, int> best_node_2; vector<int> best_new_edges_1; vector<int> best_new_edges_2; for (unsigned int i = 0; i < g2.n(); i++) { bool i_mapped = mapped_nodes.find(g2_vertices[i]) != mapped_nodes.end(); for (unsigned int j = 0; j < i; j++) { if (rand() < neighbourhood_proportion * RAND_MAX) { bool j_mapped = mapped_nodes.find(g2_vertices[j]) != mapped_nodes.end(); action_type action; int node_1; // to add if exchange int node_2; // to remove if exchange int node_1_mapped; int node_2_mapped; int lost_edges; vector<int> new_edges_1; vector<int> new_edges_2; int edge_diff = -1; // to avoid trying to make invalid moves if (i_mapped && j_mapped) { // cout << " try SWAP " << g2_vertices[i] << " <-> " << g2_vertices[j] << endl; action = swap; node_1 = g2_vertices[i]; node_2 = g2_vertices[j]; node_1_mapped = g2_to_g1_mapping[node_1]; node_2_mapped = g2_to_g1_mapping[node_2]; lost_edges = solution->degree({node_1_mapped, node_1}) + solution->degree({node_2_mapped, node_2}); if (solution->adjacent({node_1_mapped, node_1}, {node_2_mapped, node_2})) { lost_edges -= 2; } vector<int> node_1_neigh = g2.neighbours(node_1); for (unsigned int k = 0; k < node_1_neigh.size(); k++) { if (node_1_neigh[k] != node_2 && unmapped_nodes.find(node_1_neigh[k]) == unmapped_nodes.end() && g1.adjacent(node_2_mapped, g2_to_g1_mapping[node_1_neigh[k]]) ) { new_edges_1.push_back(node_1_neigh[k]); } } vector<int> node_2_neigh = g2.neighbours(node_2); for (unsigned int k = 0; k < node_2_neigh.size(); k++) { if (node_2_neigh[k] != node_1 && unmapped_nodes.find(node_2_neigh[k]) == unmapped_nodes.end() && g1.adjacent(node_1_mapped, g2_to_g1_mapping[node_2_neigh[k]]) ) { new_edges_2.push_back(node_2_neigh[k]); } } // cout << " lost edges: " << lost_edges << endl; // cout << " new edges 1: " << new_edges_1 << endl; // cout << " new edges 2: " << new_edges_2 << endl; edge_diff = new_edges_1.size() + new_edges_2.size() - lost_edges; // cout << " edge diff: " << edge_diff << endl; } else if (i_mapped || j_mapped) { unsigned int mapped_node = i_mapped ? i : j; unsigned int unmapped_node = i_mapped ? j : i; // cout << " try EXCHG " << g2_vertices[mapped_node] << " --> " << g2_vertices[unmapped_node] << endl; action = exchange; node_1 = g2_vertices[unmapped_node]; // to add, part of g2 node_2 = g2_vertices[mapped_node]; // to remove, part of g2 node_2_mapped = g2_to_g1_mapping[node_2]; // part of g1 node_1_mapped = node_2_mapped; lost_edges = solution->degree({node_2_mapped, node_2}); vector<int> node_1_neigh = g2.neighbours(node_1); for (unsigned int k = 0; k < node_1_neigh.size(); k++) { if (node_1_neigh[k] != node_2 && unmapped_nodes.find(node_1_neigh[k]) == unmapped_nodes.end() && g1.adjacent(node_1_mapped, g2_to_g1_mapping[node_1_neigh[k]]) ) { new_edges_1.push_back(node_1_neigh[k]); } } // cout << " lost edges: " << lost_edges << endl; // cout << " new edges: " << new_edges_1 << endl; edge_diff = new_edges_1.size() - lost_edges; // cout << " edge diff: " << edge_diff << endl; } // Check if this movement is tabu if (use_tabu && allow_worse) { for (unsigned int k = 0; k < tabu_list.size(); k++) { // If this movement is in the tabu list if (tabu_list[k].mapping.first == node_1 && tabu_list[k].mapping.second == node_2 ) { // If it doesn't gain much edges, we discard it if (((tabu_list[k].is_swap && action == swap) || (!tabu_list[k].is_swap && action == exchange)) && edge_diff < max_edge_diff*aspiration_threshold ) { is_tabu_mapping = true; break; } } } // Try with next potential matching if (is_tabu_mapping) { is_tabu_mapping = false; continue; } else { tabu_free_mappings.push_back({node_1, node_2}); tabu_free_mapping_type.push_back(action == swap); } } bool is_improvement = strict_comparisons ? edge_diff > best_edge_diff : edge_diff >= best_edge_diff; if (is_improvement) { any_improvement = true; best_edge_diff = edge_diff; best_action = action; best_node_1 = {node_1_mapped, node_1}; best_node_2 = {node_2_mapped, node_2}; best_new_edges_1 = new_edges_1; best_new_edges_2 = new_edges_2; } } } } if (use_tabu && allow_worse && !tabu_free_mappings.empty() && !any_improvement) { int random_number = rand() % tabu_free_mappings.size(); int node_1 = tabu_free_mappings[random_number].first; int node_2 = tabu_free_mappings[random_number].second; action_type action = tabu_free_mapping_type[random_number] ? swap : exchange; int node_1_mapped; int node_2_mapped; int lost_edges; vector<int> new_edges_1; vector<int> new_edges_2; int edge_diff; if (action == swap) { node_1_mapped = g2_to_g1_mapping[node_1]; node_2_mapped = g2_to_g1_mapping[node_2]; lost_edges = solution->degree({node_1_mapped, node_1}) + solution->degree({node_2_mapped, node_2}); if (solution->adjacent({node_1_mapped, node_1}, {node_2_mapped, node_2})) { lost_edges -= 2; } vector<int> node_1_neigh = g2.neighbours(node_1); for (unsigned int k = 0; k < node_1_neigh.size(); k++) { if (node_1_neigh[k] != node_2 && unmapped_nodes.find(node_1_neigh[k]) == unmapped_nodes.end() && g1.adjacent(node_2_mapped, g2_to_g1_mapping[node_1_neigh[k]]) ) { new_edges_1.push_back(node_1_neigh[k]); } } vector<int> node_2_neigh = g2.neighbours(node_2); for (unsigned int k = 0; k < node_2_neigh.size(); k++) { if (node_2_neigh[k] != node_1 && unmapped_nodes.find(node_2_neigh[k]) == unmapped_nodes.end() && g1.adjacent(node_1_mapped, g2_to_g1_mapping[node_2_neigh[k]]) ) { new_edges_2.push_back(node_2_neigh[k]); } } edge_diff = new_edges_1.size() + new_edges_2.size() - lost_edges; } else { node_2_mapped = g2_to_g1_mapping[node_2]; node_1_mapped = node_2_mapped; lost_edges = solution->degree({node_2_mapped, node_2}); vector<int> node_1_neigh = g2.neighbours(node_1); for (unsigned int k = 0; k < node_1_neigh.size(); k++) { if (node_1_neigh[k] != node_2 && unmapped_nodes.find(node_1_neigh[k]) == unmapped_nodes.end() && g1.adjacent(node_1_mapped, g2_to_g1_mapping[node_1_neigh[k]]) ) { new_edges_1.push_back(node_1_neigh[k]); } } edge_diff = new_edges_1.size() - lost_edges; } any_improvement = true; best_edge_diff = edge_diff; best_action = action; best_node_1 = {node_1_mapped, node_1}; best_node_2 = {node_2_mapped, node_2}; best_new_edges_1 = new_edges_1; best_new_edges_2 = new_edges_2; } if (any_improvement) { if (best_action == swap) { // cout << "best action SWAP " << best_node_1 << " <-> " << best_node_2 << " (" << best_edge_diff << ")" << endl; bool swapping_adjacents = solution->adjacent(best_node_1, best_node_2); solution->remove_node(best_node_1); solution->remove_node(best_node_2); pair<int, int> new_node_1 = {best_node_2.first, best_node_1.second}; pair<int, int> new_node_2 = {best_node_1.first, best_node_2.second}; solution->add_node(new_node_1); solution->add_node(new_node_2); if (swapping_adjacents) { solution->add_edge(new_node_1, new_node_2); } for (unsigned int i = 0; i < best_new_edges_1.size(); i++) { pair<int, int> new_edge_dest = { g2_to_g1_mapping[best_new_edges_1[i]], best_new_edges_1[i] }; solution->add_edge(new_node_1, new_edge_dest); } for (unsigned int i = 0; i < best_new_edges_2.size(); i++) { pair<int, int> new_edge_dest = { g2_to_g1_mapping[best_new_edges_2[i]], best_new_edges_2[i] }; solution->add_edge(new_node_2, new_edge_dest); } g2_to_g1_mapping[new_node_1.second] = new_node_1.first; g2_to_g1_mapping[new_node_2.second] = new_node_2.first; } else if (best_action == exchange) { // cout << "best action EXCHG " << best_node_2 << " --> " << best_node_1 << " (" << best_edge_diff << ")" << endl; solution->remove_node(best_node_2); g2_to_g1_mapping.erase(best_node_2.second); mapped_nodes.erase(best_node_2.second); unmapped_nodes.insert(best_node_2.second); unmapped_nodes_vector.push_back(best_node_2.second); solution->add_node(best_node_1); g2_to_g1_mapping.insert({best_node_1.second, best_node_1.first}); mapped_nodes.insert(best_node_1.second); unmapped_nodes.erase(best_node_1.second); unmapped_nodes_vector.erase(find(unmapped_nodes_vector.begin(), unmapped_nodes_vector.end(), best_node_1.second)); for (unsigned int i = 0; i < best_new_edges_1.size(); i++) { pair<int, int> new_edge_dest = { g2_to_g1_mapping[best_new_edges_1[i]], best_new_edges_1[i] }; solution->add_edge(best_node_1, new_edge_dest); } } if (use_tabu) { // If this is the new best edge diff, we update our max if (best_edge_diff > max_edge_diff) { max_edge_diff = best_edge_diff; } // Update time for each movement for (unsigned int i = 0; i < tabu_list.size(); i++) { tabu_list[i].time += time_delta; } // Update heap if (!tabu_queue.empty()) { make_heap(const_cast<movement*>(&tabu_queue.top()), const_cast<movement*>(&tabu_queue.top()) + tabu_queue.size(), mc); } movement mov({best_node_2.second, best_node_1.second}, best_edge_diff, 0, best_action == swap); if (tabu_list.size() < tabu_list_size) { mov.pos = tabu_list.size(); tabu_list.push_back(mov); } else { mov.pos = tabu_queue.top().pos; tabu_queue.pop(); tabu_list[mov.pos] = mov; } // Add movement to tabu heap tabu_queue.push(mov); } return true; } else { // cout << "no improvements are possible" << endl; return false; } }
bool improve_solution_1( graph<pair<int, int>>* solution, graph<int>& g1, graph<int>& g2, unordered_map<int, int>& g2_to_g1_mapping, unordered_set<int>& mapped_nodes, unordered_set<int>& unmapped_nodes, vector<int>& unmapped_nodes_vector, float neighbourhood_proportion, bool strict_comparisons, unsigned int tabu_list_size, priority_queue<movement, vector<movement>, movement_compare>& tabu_queue, movement_compare& mc, vector<movement>& tabu_list, bool allow_worse, const float time_delta, int& max_edge_diff, const float aspiration_threshold ) { vector<pair<int, int>> solution_vertices = solution->get_vertices(); bool use_tabu = tabu_list_size > 0; bool is_tabu_mapping = false; vector<pair<int, int>> tabu_free_mappings; bool any_improvement = false; pair<int, int> best_to_remove; pair<int, int> best_to_add; int best_edge_diff = 0; vector<int> best_new_edges; // This iterates over every pair present in the solution, each of // which corresponds to a vertex in g1 for (unsigned int i = 0; i < solution->n(); i++) { // This iterates over the possible nodes in g2 to which the // current g1 vertex could be associated unsigned int neighbourhood_size = unmapped_nodes_vector.size(); for (unsigned int j = 0; j < neighbourhood_size; j++) { if (rand() < neighbourhood_proportion * RAND_MAX) { // Possible new pair. Let's evaluate its potential int node_mapped = solution_vertices[i].first; // part of g1 int node_to_remove = solution_vertices[i].second; // part of g2 int node_to_add = unmapped_nodes_vector[j]; // part of g2 int lost_edges = solution->degree({node_mapped, node_to_remove}); vector<int> new_edges; vector<int> node_to_add_neigh = g2.neighbours(node_to_add); for (unsigned int k = 0; k < node_to_add_neigh.size(); k++) { if (node_to_add_neigh[k] != node_to_remove && unmapped_nodes.find(node_to_add_neigh[k]) == unmapped_nodes.end() && g1.adjacent(node_mapped, g2_to_g1_mapping[node_to_add_neigh[k]]) ) { new_edges.push_back(node_to_add_neigh[k]); } } int edge_diff = new_edges.size() - lost_edges; // Check if this movement is tabu if (use_tabu && allow_worse) { for (unsigned int k = 0; k < tabu_list.size(); k++) { // If this movement is in the tabu list if (tabu_list[k].mapping.first == node_mapped && tabu_list[k].mapping.second == node_to_add ) { // If it doesn't gain much edges, we discard it if (edge_diff < max_edge_diff*aspiration_threshold) { is_tabu_mapping = true; break; } } } // Try with next potential matching if (is_tabu_mapping) { is_tabu_mapping = false; continue; } else { tabu_free_mappings.push_back({i, j}); } } bool is_improvement = strict_comparisons ? edge_diff > best_edge_diff : edge_diff >= best_edge_diff; if (is_improvement) { any_improvement = true; best_to_add = {node_mapped, node_to_add}; best_to_remove = {node_mapped, node_to_remove}; best_edge_diff = edge_diff; best_new_edges = new_edges; } } } } if (use_tabu && allow_worse && !tabu_free_mappings.empty() && !any_improvement) { any_improvement = true; pair<int, int> random_valid_mapping = tabu_free_mappings[rand() % tabu_free_mappings.size()]; int node_mapped = solution_vertices[random_valid_mapping.first].first; // part of g1 int node_to_remove = solution_vertices[random_valid_mapping.first].second; // part of g2 int node_to_add = unmapped_nodes_vector[random_valid_mapping.second]; // part of g2 int lost_edges = solution->degree({node_mapped, node_to_remove}); vector<int> new_edges; vector<int> node_to_add_neigh = g2.neighbours(node_to_add); for (unsigned int k = 0; k < node_to_add_neigh.size(); k++) { if (node_to_add_neigh[k] != node_to_remove && unmapped_nodes.find(node_to_add_neigh[k]) == unmapped_nodes.end() && g1.adjacent(node_mapped, g2_to_g1_mapping[node_to_add_neigh[k]]) ) { new_edges.push_back(node_to_add_neigh[k]); } } int edge_diff = new_edges.size() - lost_edges; best_to_add = {node_mapped, node_to_add}; best_to_remove = {node_mapped, node_to_remove}; best_edge_diff = edge_diff; best_new_edges = new_edges; } if (any_improvement) { solution->remove_node(best_to_remove); g2_to_g1_mapping.erase(best_to_remove.second); unmapped_nodes_vector.push_back(best_to_remove.second); unmapped_nodes.insert(best_to_remove.second); solution->add_node(best_to_add); g2_to_g1_mapping.insert({best_to_add.second, best_to_add.first}); unmapped_nodes_vector.erase(find(unmapped_nodes_vector.begin(), unmapped_nodes_vector.end(), best_to_add.second)); unmapped_nodes.erase(best_to_add.second); for (unsigned int i = 0; i < best_new_edges.size(); i++) { pair<int, int> new_edge_dest = { g2_to_g1_mapping[best_new_edges[i]], best_new_edges[i] }; solution->add_edge(best_to_add, new_edge_dest); } if (use_tabu) { // If this is the new best edge diff, we update our max if (best_edge_diff > max_edge_diff) { max_edge_diff = best_edge_diff; } // Update time for each movement for (unsigned int i = 0; i < tabu_list.size(); i++) { tabu_list[i].time += time_delta; } // Update heap if (!tabu_queue.empty()) { make_heap(const_cast<movement*>(&tabu_queue.top()), const_cast<movement*>(&tabu_queue.top()) + tabu_queue.size(), mc); } movement mov(best_to_remove, best_edge_diff, 0); if (tabu_list.size() < tabu_list_size) { mov.pos = tabu_list.size(); tabu_list.push_back(mov); } else { mov.pos = tabu_queue.top().pos; tabu_queue.pop(); tabu_list[mov.pos] = mov; } // Add movement to tabu heap tabu_queue.push(mov); } return true; } else { return false; } }