diff --git a/plugins/round_trip.hpp b/plugins/round_trip.hpp index 94b6089fe..85d1f2057 100644 --- a/plugins/round_trip.hpp +++ b/plugins/round_trip.hpp @@ -50,7 +50,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include +#include template class RoundTripPlugin final : public BasePlugin { @@ -59,9 +59,112 @@ template class RoundTripPlugin final : public BasePlugin DataFacadeT *facade; std::unique_ptr> search_engine_ptr; + void FarthestInsertion(const RouteParameters & route_parameters, + const PhantomNodeArray & phantom_node_vector, + const std::vector & dist_table, + InternalRouteResult & min_route, + std::vector & min_loc_permutation) { + ////////////////////////////////////////////////////////////////////////////////////////////////// + // 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 + // 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! + ////////////////////////////////////////////////////////////////////////////////////////////////// + + const auto number_of_locations = phantom_node_vector.size(); + std::list current_trip; + std::vector visited(number_of_locations, false); + + // find two locations that have max distance + auto max_dist = -1; + int max_from = -1; + int max_to = -1; + + auto i = 0; + for (auto it = dist_table.begin(); it != dist_table.end(); ++it) { + if (*it > max_dist) { + max_dist = *it; + max_from = i / number_of_locations; + max_to = i % number_of_locations; + } + ++i; + } + + visited[max_from] = true; + visited[max_to] = true; + + // SimpleLogger().Write() << "Start with " << max_from << " " << max_to; + + current_trip.push_back(max_from); + current_trip.push_back(max_to); + + for (int j = 2; j < number_of_locations; ++j) { + auto max_min_dist = -1; + int next_node = -1; + auto min_max_insert = current_trip.begin(); + + // look for loc i that is the farthest away from all other visited locs + for (int i = 0; i < number_of_locations; ++i) { + if (!visited[i]) { + // SimpleLogger().Write() << "- node " << i << " is not visited yet"; + + auto min_insert = std::numeric_limits::max(); + auto min_to = current_trip.begin(); + + for (auto from_node = current_trip.begin(); from_node != current_trip.end(); ++from_node) { + + auto to_node = std::next(from_node); + if (std::next(from_node) == current_trip.end()) { + to_node = current_trip.begin(); + } + + auto dist_from = *(dist_table.begin() + (*from_node * number_of_locations) + i); + auto dist_to = *(dist_table.begin() + (i * number_of_locations) + *to_node); + auto trip_dist = dist_from + dist_to - *(dist_table.begin() + (*from_node * number_of_locations) + *to_node); + + // SimpleLogger().Write() << " From " << *from_node << " to " << i << " to " << *to_node << " is " << trip_dist; + + if (trip_dist < min_insert) { + min_insert = trip_dist; + min_to = to_node; + } + } + if (min_insert > max_min_dist) { + max_min_dist = min_insert; + next_node = i; + min_max_insert = min_to; + } + } + } + // SimpleLogger().Write() << "- Insert new node " << next_node; + visited[next_node] = true; + + current_trip.insert(min_max_insert, next_node); + } + + int perm = 0; + for (auto it = current_trip.begin(); it != current_trip.end(); ++it) { + // SimpleLogger().Write() << "- Visit location " << *it; + + auto from_node = *it; + auto to_node = *std::next(it); + if (std::next(it) == current_trip.end()) { + to_node = current_trip.front(); + } + PhantomNodes viapoint; + viapoint = PhantomNodes{phantom_node_vector[from_node][0], phantom_node_vector[to_node][0]}; + min_route.segment_end_coordinates.emplace_back(viapoint); + min_loc_permutation[from_node] = perm; + ++perm; + } + search_engine_ptr->shortest_path(min_route.segment_end_coordinates, route_parameters.uturns, min_route); + } + void NearestNeighbour(const RouteParameters & route_parameters, const PhantomNodeArray & phantom_node_vector, - std::vector & dist_table, + const std::vector & dist_table, InternalRouteResult & min_route, std::vector & min_loc_permutation) { ////////////////////////////////////////////////////////////////////////////////////////////////// @@ -72,7 +175,7 @@ template class RoundTripPlugin final : public BasePlugin // 4. return route back to starting point // 5. compute route // 6. repeat 1-5 with different starting points and choose iteration with shortest trip - // 6. DONE! + // 7. DONE! ////////////////////////////////////////////////////////////////////////////////////////////////// const auto number_of_locations = phantom_node_vector.size(); @@ -88,7 +191,7 @@ template class RoundTripPlugin final : public BasePlugin // ALWAYS START AT ANOTHER STARTING POINT for(int start_node = 0; start_node < number_of_locations; ++start_node) { - + if (is_lonely_island[start_node] >= 0) { // if node is a lonely island it is an unsuitable node to start from and shall be skipped @@ -108,7 +211,7 @@ template class RoundTripPlugin final : public BasePlugin } } - int curr_node = start_node; + int curr_node = start_node; is_lonely_island[curr_node] = -1; InternalRouteResult raw_route; //TODO: Should we always use the same vector or does it not matter at all because of loop scope? @@ -129,7 +232,7 @@ template class RoundTripPlugin final : public BasePlugin 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) { - auto index = std::distance(row_begin_iterator, it); + auto index = std::distance(row_begin_iterator, it); if (is_lonely_island[index] < 1 && !visited[index] && *it < min_dist) { min_dist = *it; @@ -164,7 +267,7 @@ template class RoundTripPlugin final : public BasePlugin // 5. COMPUTE ROUTE search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, route_parameters.uturns, raw_route); - + // check round trip with this starting point is shorter than the shortest round trip found till now if (raw_route.shortest_path_length < min_route.shortest_path_length) { min_route = raw_route; @@ -185,6 +288,7 @@ template class RoundTripPlugin final : public BasePlugin int HandleRequest(const RouteParameters &route_parameters, osrm::json::Object &json_result) override final { + TIMER_START(tsp_pre); // check if all inputs are coordinates if (!check_all_coordinates(route_parameters.coordinates)) { @@ -227,27 +331,52 @@ template class RoundTripPlugin final : public BasePlugin } // compute TSP round trip - InternalRouteResult min_route; - std::vector min_loc_permutation; - TIMER_START(tsp_nn); - NearestNeighbour(route_parameters, phantom_node_vector, *result_table, min_route, min_loc_permutation); - TIMER_STOP(tsp_nn); + InternalRouteResult min_route_nn; + InternalRouteResult min_route_fi; + std::vector min_loc_permutation_nn(phantom_node_vector.size(), -1); + std::vector min_loc_permutation_fi(phantom_node_vector.size(), -1); + TIMER_STOP(tsp_pre); - SimpleLogger().Write() << "Distance " << min_route.shortest_path_length; - SimpleLogger().Write() << "Time " << TIMER_MSEC(tsp_nn); + TIMER_START(tsp_nn); + NearestNeighbour(route_parameters, phantom_node_vector, *result_table, min_route_nn, min_loc_permutation_nn); + TIMER_STOP(tsp_nn); + SimpleLogger().Write() << "Distance " << min_route_nn.shortest_path_length; + SimpleLogger().Write() << "Time " << TIMER_MSEC(tsp_nn) + TIMER_MSEC(tsp_pre); + + // std::unique_ptr> descriptor; + // descriptor = osrm::make_unique>(facade); + + // descriptor->SetConfig(route_parameters); + // descriptor->Run(min_route_nn, json_result); + + osrm::json::Array json_loc_permutation_nn; + json_loc_permutation_nn.values.insert(json_loc_permutation_nn.values.end(), min_loc_permutation_nn.begin(), min_loc_permutation_nn.end()); + json_result.values["nn_loc_permutation"] = json_loc_permutation_nn; + json_result.values["nn_distance"] = min_route_nn.shortest_path_length; + json_result.values["nn_runtime"] = TIMER_MSEC(tsp_nn) + TIMER_MSEC(tsp_pre); + + TIMER_START(tsp_fi); + FarthestInsertion(route_parameters, phantom_node_vector, *result_table, min_route_fi, min_loc_permutation_fi); + TIMER_STOP(tsp_fi); + SimpleLogger().Write() << "Distance " << min_route_fi.shortest_path_length; + SimpleLogger().Write() << "Time " << TIMER_MSEC(tsp_fi) + TIMER_MSEC(tsp_pre); // return result to json std::unique_ptr> descriptor; descriptor = osrm::make_unique>(facade); - - descriptor->SetConfig(route_parameters); - descriptor->Run(min_route, json_result); - osrm::json::Array json_loc_permutation; - json_loc_permutation.values.insert(json_loc_permutation.values.end(), min_loc_permutation.begin(), min_loc_permutation.end()); - json_result.values["nn_loc_permutation"] = json_loc_permutation; - json_result.values["nn_distance"] = min_route.shortest_path_length; - json_result.values["nn_runtime"] = TIMER_MSEC(tsp_nn); + descriptor->SetConfig(route_parameters); + descriptor->Run(min_route_fi, json_result); + + osrm::json::Array json_loc_permutation_fi; + json_loc_permutation_fi.values.insert(json_loc_permutation_fi.values.end(), min_loc_permutation_fi.begin(), min_loc_permutation_fi.end()); + json_result.values["fi_loc_permutation"] = json_loc_permutation_fi; + json_result.values["fi_distance"] = min_route_fi.shortest_path_length; + json_result.values["fi_runtime"] = TIMER_MSEC(tsp_fi) + TIMER_MSEC(tsp_pre); + + // for (int i = 0; i < min_loc_permutation_fi.size(); ++i) { + // SimpleLogger().Write() << min_loc_permutation_nn[i] << " " << min_loc_permutation_fi[i]; + // } return 200; }