From 99cf3219d43faf050d43d6dc27d9643082f8fa9d Mon Sep 17 00:00:00 2001 From: Huyen Chau Nguyen Date: Wed, 19 Aug 2015 11:35:36 +0200 Subject: [PATCH] have less redundant code for requests with one or multiple SCCs --- plugins/round_trip.hpp | 142 ++++------- routing_algorithms/tsp_brute_force.hpp | 27 +- routing_algorithms/tsp_farthest_insertion.hpp | 231 ++++++++++-------- routing_algorithms/tsp_nearest_neighbour.hpp | 64 ----- 4 files changed, 175 insertions(+), 289 deletions(-) diff --git a/plugins/round_trip.hpp b/plugins/round_trip.hpp index 14f5b4bfa..e1d95e72c 100644 --- a/plugins/round_trip.hpp +++ b/plugins/round_trip.hpp @@ -197,112 +197,66 @@ template class RoundTripPlugin final : public BasePlugin const constexpr std::size_t BF_MAX_FEASABLE = 10; auto number_of_locations = phantom_node_vector.size(); BOOST_ASSERT_MSG(result_table->size() > 0, "Distance Table is empty."); + std::vector> components; //check if locations are in different strongly connected components (SCC) const auto maxint = INVALID_EDGE_WEIGHT; if (*std::max_element(std::begin(*result_table), std::end(*result_table)) == maxint) { - - //TODO DELETE - // JSON output related objects - std::unique_ptr> descriptor; - descriptor = osrm::make_unique>(facade); - descriptor->SetConfig(route_parameters); - - TIMER_START(tsp); // Compute all SCC - std::vector> components; SplitUnaccessibleLocations(number_of_locations, *result_table, components); - // std::vector> res_route (components.size()-1); - std::vector> res_route; + } else { + // fill a vector with node ids + std::vector location_ids(number_of_locations); + std::iota(location_ids.begin(), location_ids.end(), 0); + components.push_back(location_ids); + } - //run TSP computation for every SCC - for(auto k = 0; k < components.size(); ++k) { - if (components[k].size() > 1) { - std::vector scc_route; + std::vector> res_route; + TIMER_START(tsp); + //run TSP computation for every SCC + for(auto k = 0; k < components.size(); ++k) { + if (components[k].size() > 1) { + std::vector scc_route; - // Compute the TSP with the given algorithm - if (route_parameters.tsp_algo == "BF" && route_parameters.coordinates.size() < BF_MAX_FEASABLE) { - SimpleLogger().Write() << "Running brute force on multiple SCC"; - scc_route = osrm::tsp::BruteForceTSP(components[k], number_of_locations, *result_table); - res_route.push_back(scc_route); - } else if (route_parameters.tsp_algo == "NN") { - SimpleLogger().Write() << "Running nearest neighbour on multiple SCC"; - scc_route = osrm::tsp::NearestNeighbourTSP(components[k], number_of_locations, *result_table); - res_route.push_back(scc_route); - } else if (route_parameters.tsp_algo == "FI") { - SimpleLogger().Write() << "Running farthest insertion on multiple SCC"; - scc_route = osrm::tsp::FarthestInsertionTSP(components[k], number_of_locations, *result_table); - res_route.push_back(scc_route); - } else{ - SimpleLogger().Write() << "Running farthest insertion on multiple SCC"; - scc_route = osrm::tsp::FarthestInsertionTSP(components[k], number_of_locations, *result_table); - res_route.push_back(scc_route); - } + // Compute the TSP with the given algorithm + if (route_parameters.tsp_algo == "BF" && route_parameters.coordinates.size() < BF_MAX_FEASABLE) { + SimpleLogger().Write() << "Running brute force"; + scc_route = osrm::tsp::BruteForceTSP(components[k], number_of_locations, *result_table); + res_route.push_back(scc_route); + } else if (route_parameters.tsp_algo == "NN") { + SimpleLogger().Write() << "Running nearest neighbour"; + scc_route = osrm::tsp::NearestNeighbourTSP(components[k], number_of_locations, *result_table); + res_route.push_back(scc_route); + } else if (route_parameters.tsp_algo == "FI") { + SimpleLogger().Write() << "Running farthest insertion"; + scc_route = osrm::tsp::FarthestInsertionTSP(components[k], number_of_locations, *result_table); + res_route.push_back(scc_route); + } else{ + SimpleLogger().Write() << "Running farthest insertion"; + scc_route = osrm::tsp::FarthestInsertionTSP(components[k], number_of_locations, *result_table); + res_route.push_back(scc_route); } } - std::vector route; - ComputeRoute(phantom_node_vector, route_parameters, res_route, route); - TIMER_STOP(tsp); - SetRuntimeOutput(TIMER_MSEC(tsp), json_result); - SimpleLogger().Write() << "Computed roundtrip in " << TIMER_MSEC(tsp) << "ms"; - // SimpleLogger().Write() << "Route is"; - // for (auto x : res_route) { - // for (auto y : x) - // std::cout << y << " "; - // } - // SimpleLogger().Write() << ""; - - auto dist = 0; - for (auto curr_route : route) { - dist += curr_route.shortest_path_length; - SetGeometry(route_parameters, curr_route, json_result); - } - SetDistanceOutput(dist, json_result); - } else { //run TSP computation for all locations - std::vector res_route; - - // Compute the TSP with the given algorithm - TIMER_START(tsp); - // TODO patrick nach userfreundlichkeit fragen, BF vs bf usw - if (route_parameters.tsp_algo == "BF" && route_parameters.coordinates.size() < BF_MAX_FEASABLE) { - SimpleLogger().Write() << "Running brute force"; - res_route = osrm::tsp::BruteForceTSP(number_of_locations, *result_table); - } else if (route_parameters.tsp_algo == "NN") { - SimpleLogger().Write() << "Running nearest neighbour"; - res_route = osrm::tsp::NearestNeighbourTSP(number_of_locations, *result_table); - } else if (route_parameters.tsp_algo == "FI") { - SimpleLogger().Write() << "Running farthest insertion"; - res_route = osrm::tsp::FarthestInsertionTSP(number_of_locations, *result_table); - } else { - SimpleLogger().Write() << "Running farthest insertion"; - res_route = osrm::tsp::FarthestInsertionTSP(number_of_locations, *result_table); - } - // TODO asserts numer of result blablabla size - // TODO std::is_permutation - // TODO boost range - - - - InternalRouteResult min_route; - ComputeRoute(phantom_node_vector, route_parameters, res_route, min_route); - TIMER_STOP(tsp); - - // SimpleLogger().Write() << "Route is"; - // for (auto x : res_route) { - // std::cout << x << " "; - // } - // SimpleLogger().Write() << ""; - - //TODO TIMER im LOGGER - SetRuntimeOutput(TIMER_MSEC(tsp), json_result); - SimpleLogger().Write() << "Computed roundtrip in " << TIMER_MSEC(tsp) << "ms"; - SetLocPermutationOutput(res_route, json_result); - //TODO MEHR ASSERTIONS! :O - SetDistanceOutput(min_route.shortest_path_length, json_result); - SetGeometry(route_parameters, min_route, json_result); - BOOST_ASSERT(min_route.segment_end_coordinates.size() == route_parameters.coordinates.size()); } + std::vector route; + ComputeRoute(phantom_node_vector, route_parameters, res_route, route); + TIMER_STOP(tsp); + SetRuntimeOutput(TIMER_MSEC(tsp), json_result); + SimpleLogger().Write() << "Computed roundtrip in " << TIMER_MSEC(tsp) << "ms"; + // SimpleLogger().Write() << "Route is"; + // for (auto x : res_route) { + // for (auto y : x) + // std::cout << y << " "; + // } + // SimpleLogger().Write() << ""; + + auto dist = 0; + for (auto curr_route : route) { + dist += curr_route.shortest_path_length; + SetGeometry(route_parameters, curr_route, json_result); + } + SetDistanceOutput(dist, json_result); diff --git a/routing_algorithms/tsp_brute_force.hpp b/routing_algorithms/tsp_brute_force.hpp index 2665d68f2..022804e5a 100644 --- a/routing_algorithms/tsp_brute_force.hpp +++ b/routing_algorithms/tsp_brute_force.hpp @@ -89,29 +89,6 @@ std::vector BruteForceTSP(std::vector & component, return route; } -std::vector BruteForceTSP(const std::size_t number_of_locations, - const std::vector & dist_table) { - std::vector route; - route.reserve(number_of_locations); - - // fill a vector with node ids - std::vector location_ids(number_of_locations); - std::iota(location_ids.begin(), location_ids.end(), 0); - - EdgeWeight min_route_dist = INVALID_EDGE_WEIGHT; - // check length of all possible permutation of the location ids - do { - const auto new_distance = ReturnDistance(dist_table, location_ids, min_route_dist, number_of_locations); - - if (new_distance <= min_route_dist) { - min_route_dist = new_distance; - route = location_ids; - } - } while(std::next_permutation(location_ids.begin(), location_ids.end())); - - return route; -} - -} -} +} //end namespace osrm +} //end namespace tsp #endif // TSP_BRUTE_FORCE_HPP \ No newline at end of file diff --git a/routing_algorithms/tsp_farthest_insertion.hpp b/routing_algorithms/tsp_farthest_insertion.hpp index 5f53447e7..03cd451ca 100644 --- a/routing_algorithms/tsp_farthest_insertion.hpp +++ b/routing_algorithms/tsp_farthest_insertion.hpp @@ -49,12 +49,16 @@ namespace osrm namespace tsp { -void GetShortestRoundTrip(const int current_loc, - const std::vector & dist_table, - const int number_of_locations, - std::vector & route, - int & min_trip_distance, - std::vector::iterator & next_insert_point_candidate){ +using NodeIterator = typename std::vector::iterator; + +std::pair GetShortestRoundTrip(const int current_loc, + const std::vector & dist_table, + const int number_of_locations, + std::vector & route){ + + auto min_trip_distance = INVALID_EDGE_WEIGHT; + NodeIterator next_insert_point_candidate; + // for all nodes in the current trip find the best insertion resulting in the shortest path // assert min 2 nodes in route for (auto from_node = route.begin(); from_node != std::prev(route.end()); ++from_node) { @@ -81,6 +85,55 @@ void GetShortestRoundTrip(const int current_loc, min_trip_distance = trip_dist; next_insert_point_candidate = to_node; } + + return std::make_pair(min_trip_distance, next_insert_point_candidate); +} + +// given two initial start nodes, find a roundtrip route using the farthest insertion algorithm +std::vector FindRoute(const std::size_t & number_of_locations, + const std::size_t & size_of_component, + const std::vector & locations, + const std::vector & dist_table, + const NodeID & start1, + const NodeID & start2) { + std::vector route; + route.reserve(number_of_locations); + + // tracks which nodes have been already visited + std::vector visited(number_of_locations, false); + + visited[start1] = true; + visited[start2] = true; + route.push_back(start1); + route.push_back(start2); + + // add all other nodes missing (two nodes are already in the initial start trip) + for (int j = 2; j < size_of_component; ++j) { + + auto farthest_distance = 0; + auto next_node = -1; + NodeIterator next_insert_point; + + // find unvisited loc i that is the farthest away from all other visited locs + for (auto i : locations) { + // find the shortest distance from i to all visited nodes + if (!visited[i]) { + auto insert_candidate = GetShortestRoundTrip(i, dist_table, number_of_locations, route); + + // add the location to the current trip such that it results in the shortest total tour + if (insert_candidate.first >= farthest_distance) { + farthest_distance = insert_candidate.first; + next_node = i; + next_insert_point = insert_candidate.second; + } + } + } + + // mark as visited and insert node + visited[next_node] = true; + route.insert(next_insert_point, next_node); + } + return route; } // osrm::tsp::FarthestInsertionTSP(components[k], phantom_node_vector, *result_table, scc_route); @@ -96,126 +149,92 @@ std::vector FarthestInsertionTSP(const std::vector & locations, // 5. DONE! ////////////////////////////////////////////////////////////////////////////////////////////////// - std::vector route; - route.reserve(number_of_locations); - const int size_of_component = locations.size(); - // tracks which nodes have been already visited - std::vector visited(number_of_locations, false); - - auto max_dist = 0; auto max_from = -1; auto max_to = -1; - //TODO - for (auto x : locations) { - for (auto y : locations) { - auto xy_dist = *(dist_table.begin() + x * number_of_locations + y); - if (xy_dist > max_dist) { - max_dist = xy_dist; - max_from = x; - max_to = y; - } - } - } + if (size_of_component == number_of_locations) { + // find the pair of location with the biggest distance and make the pair the initial start trip + const auto index = std::distance(dist_table.begin(), std::max_element(dist_table.begin(), dist_table.end())); + max_from = index / number_of_locations; + max_to = index % number_of_locations; - visited[max_from] = true; - visited[max_to] = true; - route.push_back(max_from); - route.push_back(max_to); - // SimpleLogger().Write() << size_of_component; - // add all other nodes missing (two nodes are already in the initial start trip) - for (int j = 2; j < size_of_component; ++j) { - // SimpleLogger().Write() << j << "/" << size_of_component; - auto farthest_distance = 0; - auto next_node = -1; - std::vector::iterator next_insert_point; - - // find unvisited loc i that is the farthest away from all other visited locs - for (auto i : locations) { - // find the shortest distance from i to all visited nodes - if (!visited[i]) { - auto min_trip_distance = INVALID_EDGE_WEIGHT; - std::vector::iterator next_insert_point_candidate; - - GetShortestRoundTrip(i, dist_table, number_of_locations, route, min_trip_distance, next_insert_point_candidate); - - // add the location to the current trip such that it results in the shortest total tour - // SimpleLogger().Write() << "min_trip_distance " << min_trip_distance; - if (min_trip_distance >= farthest_distance) { - farthest_distance = min_trip_distance; - next_node = i; - next_insert_point = next_insert_point_candidate; + } else { + auto max_dist = 0; + for (auto x : locations) { + for (auto y : locations) { + auto xy_dist = *(dist_table.begin() + x * number_of_locations + y); + if (xy_dist > max_dist) { + max_dist = xy_dist; + max_from = x; + max_to = y; } } } - // SimpleLogger().Write() << "next node " << next_node; - // mark as visited and insert node - visited[next_node] = true; - route.insert(next_insert_point, next_node); } - return route; + + return FindRoute(number_of_locations, size_of_component, locations, dist_table, max_from, max_to); } -std::vector FarthestInsertionTSP(const std::size_t number_of_locations, - const std::vector & dist_table) { - ////////////////////////////////////////////////////////////////////////////////////////////////// - // START FARTHEST INSERTION HERE - // 1. start at a random round trip of 2 locations - // 2. find the location that is the farthest away from the visited locations and whose insertion will make the round trip the longest - // 3. add the found location to the current round trip such that round trip is the shortest - // 4. repeat 2-3 until all locations are visited - // 5. DONE! - ////////////////////////////////////////////////////////////////////////////////////////////////// +// std::vector FarthestInsertionTSP(const std::size_t number_of_locations, +// const std::vector & dist_table) { +// ////////////////////////////////////////////////////////////////////////////////////////////////// +// // START FARTHEST INSERTION HERE +// // 1. start at a random round trip of 2 locations +// // 2. find the location that is the farthest away from the visited locations and whose insertion will make the round trip the longest +// // 3. add the found location to the current round trip such that round trip is the shortest +// // 4. repeat 2-3 until all locations are visited +// // 5. DONE! +// ////////////////////////////////////////////////////////////////////////////////////////////////// - std::vector route; - route.reserve(number_of_locations); +// std::vector route; +// route.reserve(number_of_locations); - // tracks which nodes have been already visited - std::vector visited(number_of_locations, false); +// // tracks which nodes have been already visited +// std::vector visited(number_of_locations, false); - // find the pair of location with the biggest distance and make the pair the initial start trip - const auto index = std::distance(dist_table.begin(), std::max_element(dist_table.begin(), dist_table.end())); - const int max_from = index / number_of_locations; - const int max_to = index % number_of_locations; - visited[max_from] = true; - visited[max_to] = true; - route.push_back(max_from); - route.push_back(max_to); +// // find the pair of location with the biggest distance and make the pair the initial start trip +// const auto index = std::distance(dist_table.begin(), std::max_element(dist_table.begin(), dist_table.end())); +// const int max_from = index / number_of_locations; +// const int max_to = index % number_of_locations; +// visited[max_from] = true; +// visited[max_to] = true; +// route.push_back(max_from); +// route.push_back(max_to); - // add all other nodes missing (two nodes are already in the initial start trip) - for (int j = 2; j < number_of_locations; ++j) { - auto farthest_distance = 0; - auto next_node = -1; - //todo move out of loop and overwrite - std::vector::iterator next_insert_point; +// // add all other nodes missing (two nodes are already in the initial start trip) +// for (int j = 2; j < number_of_locations; ++j) { +// auto farthest_distance = 0; +// auto next_node = -1; +// //todo move out of loop and overwrite +// NodeIterator next_insert_point; - // find unvisited loc i that is the farthest away from all other visited locs - for (int i = 0; i < number_of_locations; ++i) { - if (!visited[i]) { - auto min_trip_distance = INVALID_EDGE_WEIGHT; - std::vector::iterator next_insert_point_candidate; +// // find unvisited loc i that is the farthest away from all other visited locs +// for (int i = 0; i < number_of_locations; ++i) { +// if (!visited[i]) { +// auto min_trip_distance = INVALID_EDGE_WEIGHT; +// NodeIterator next_insert_point_candidate; - GetShortestRoundTrip(i, dist_table, number_of_locations, route, min_trip_distance, next_insert_point_candidate); +// GetShortestRoundTrip(i, dist_table, number_of_locations, route, min_trip_distance, next_insert_point_candidate); - // add the location to the current trip such that it results in the shortest total tour - if (min_trip_distance >= farthest_distance) { - farthest_distance = min_trip_distance; - next_node = i; - next_insert_point = next_insert_point_candidate; - } - } - } +// // add the location to the current trip such that it results in the shortest total tour +// if (min_trip_distance >= farthest_distance) { +// farthest_distance = min_trip_distance; +// next_node = i; +// next_insert_point = next_insert_point_candidate; +// } +// } +// } - // mark as visited and insert node - visited[next_node] = true; - route.insert(next_insert_point, next_node); - } - return route; -} +// // mark as visited and insert node +// visited[next_node] = true; +// route.insert(next_insert_point, next_node); +// } +// return route; +// } -} -} +} //end namespace osrm +} //end namespace tsp #endif // TSP_FARTHEST_INSERTION_HPP \ No newline at end of file diff --git a/routing_algorithms/tsp_nearest_neighbour.hpp b/routing_algorithms/tsp_nearest_neighbour.hpp index e7820c506..cd2adadec 100644 --- a/routing_algorithms/tsp_nearest_neighbour.hpp +++ b/routing_algorithms/tsp_nearest_neighbour.hpp @@ -110,70 +110,6 @@ std::vector NearestNeighbourTSP(const std::vector & locations, return route; } -std::vector NearestNeighbourTSP(const std::size_t number_of_locations, - const std::vector & dist_table) { - ////////////////////////////////////////////////////////////////////////////////////////////////// - // START GREEDY NEAREST NEIGHBOUR HERE - // 1. grab a random location and mark as starting point - // 2. find the nearest unvisited neighbour, set it as the current location and mark as visited - // 3. repeat 2 until there is no unvisited location - // 4. return route back to starting point - // 5. compute route - // 6. repeat 1-5 with different starting points and choose iteration with shortest trip - // 7. DONE! - ////////////////////////////////////////////////////////////////////////////////////////////////// - - std::vector route; - route.reserve(number_of_locations); - - int shortest_trip_distance = INVALID_EDGE_WEIGHT; - - // ALWAYS START AT ANOTHER STARTING POINT - for(int start_node = 0; start_node < number_of_locations; ++start_node) - { - int curr_node = start_node; - - std::vector curr_route; - curr_route.reserve(number_of_locations); - curr_route.push_back(start_node); - - // visited[i] indicates whether node i was already visited by the salesman - std::vector visited(number_of_locations, false); - visited[start_node] = true; - - // 3. REPEAT FOR EVERY UNVISITED NODE - int trip_dist = 0; - for(int via_point = 1; via_point < number_of_locations; ++via_point) - { - int min_dist = INVALID_EDGE_WEIGHT; - int min_id = -1; - - // 2. FIND NEAREST NEIGHBOUR - auto row_begin_iterator = dist_table.begin() + (curr_node * number_of_locations); - auto row_end_iterator = dist_table.begin() + ((curr_node + 1) * number_of_locations); - for (auto it = row_begin_iterator; it != row_end_iterator; ++it) { - const auto index = std::distance(row_begin_iterator, it); - if (!visited[index] && *it < min_dist) - { - min_dist = *it; - min_id = index; - } - } - visited[min_id] = true; - curr_route.push_back(min_id); - trip_dist += min_dist; - curr_node = min_id; - } - - // check round trip with this starting point is shorter than the shortest round trip found till now - if (trip_dist < shortest_trip_distance) { - shortest_trip_distance = trip_dist; - route = curr_route; - } - } - return route; -} - } } #endif // TSP_NEAREST_NEIGHBOUR_HPP \ No newline at end of file