diff --git a/plugins/round_trip.hpp b/plugins/round_trip.hpp index be55d4dfc..3b984623b 100644 --- a/plugins/round_trip.hpp +++ b/plugins/round_trip.hpp @@ -98,11 +98,9 @@ template class RoundTripPlugin final : public BasePlugin phantom_node_vector[i], 1); if (phantom_node_vector[i].size() > 1) { - phantom_node_vector[i].pop_back(); + phantom_node_vector[i].erase(phantom_node_vector[i].begin()); } - BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes())); - // SimpleLogger().Write() << "In loop 1"; } // compute the distance table of all phantom nodes @@ -114,9 +112,6 @@ template class RoundTripPlugin final : public BasePlugin return 400; } - // SimpleLogger().Write() << "Distance Table Computed"; - - ////////////////////////////////////////////////////////////////////////////////////////////////// // START GREEDY NEAREST NEIGHBOUR HERE // 1. grab a random location and mark as starting point @@ -124,87 +119,123 @@ template class RoundTripPlugin final : public BasePlugin // 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 // 6. DONE! ////////////////////////////////////////////////////////////////////////////////////////////////// const auto number_of_locations = phantom_node_vector.size(); - InternalRouteResult raw_route; - // 1. START WITH LOCATION 0 AS START POINT - int curr_node = 0; - std::vector loc_permutation(number_of_locations, -1); - loc_permutation[0] = 0; - std::vector visited(number_of_locations, false); - visited[0] = true; + // min_route is the shortest route found + InternalRouteResult min_route; + min_route.shortest_path_length = std::numeric_limits::max(); + // min_loc_permutation stores the order of visited locations of the shortest route + std::vector min_loc_permutation; - // SimpleLogger().Write() << "Added an initial via"; - // SimpleLogger().Write() << "Started from location 0"; - // SimpleLogger().Write() << "Number of locs: " << number_of_locations; + // is_lonely_island[i] indicates whether node i is a node that cannot be reached from other nodes + // 1 means that node i is a lonely island + // 0 means that it is not known for node i + // -1 means that node i is not a lonely island but a reachable, connected node + std::vector is_lonely_island(number_of_locations, 0); + int count_unreachables; - PhantomNodes subroute; - // 3. REPEAT FOR EVERY UNVISITED NODE - for(int stopover = 1; stopover < number_of_locations; ++stopover) + // ALWAYS START AT ANOTHER STARTING POINT + for(int start_node = 0; start_node < number_of_locations; ++start_node) { - auto row_begin_iterator = result_table->begin() + (curr_node * number_of_locations); - auto row_end_iterator = result_table->begin() + ((curr_node + 1) * number_of_locations); - int min_dist = std::numeric_limits::max(); - int min_id = -1; - - // 2. FIND NEAREST NEIGHBOUR - for (auto it = row_begin_iterator; it != row_end_iterator; ++it) { - auto index = std::distance(row_begin_iterator, it); - - if (!visited[index] && *it < min_dist) - { - min_dist = *it; - min_id = index; + + 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 + if (is_lonely_island[start_node]) + continue; + count_unreachables = 0; + auto start_dist_begin = result_table->begin() + (start_node * number_of_locations); + auto start_dist_end = result_table->begin() + ((start_node + 1) * number_of_locations); + for (auto it2 = start_dist_begin; it2 != start_dist_end; ++it2) { + if (*it2 == 0 || *it2 == std::numeric_limits::max()) { + ++count_unreachables; + } + } + if (count_unreachables >= number_of_locations) { + is_lonely_island[start_node] = 1; + continue; } - - // SimpleLogger().Write() << "In loop 2"; } - // SimpleLogger().Write() << "After loop 2"; + 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? + std::vector loc_permutation(number_of_locations, -1); + loc_permutation[start_node] = 0; + // visited[i] indicates whether node i was already visited by the salesman + std::vector visited(number_of_locations, false); + visited[start_node] = true; + + PhantomNodes viapoint; + // 3. REPEAT FOR EVERY UNVISITED NODE + for(int via_point = 1; via_point < number_of_locations; ++via_point) + { + int min_dist = std::numeric_limits::max(); + int min_id = -1; + + // 2. FIND NEAREST NEIGHBOUR + auto row_begin_iterator = result_table->begin() + (curr_node * number_of_locations); + auto row_end_iterator = result_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); + if (is_lonely_island[index] < 1 && !visited[index] && *it < min_dist) + { + min_dist = *it; + min_id = index; + } + } + // in case there was no unvisited and reachable node found, it means that all remaining (unvisited) nodes must be lonely islands + if (min_id == -1) + { + for(int loc = 0; loc < visited.size(); ++loc) { + if (!visited[loc]) { + is_lonely_island[loc] = 1; + } + } + break; + } + // set the nearest unvisited location as the next via_point + else + { + is_lonely_island[min_id] = -1; + loc_permutation[min_id] = via_point; + visited[min_id] = true; + viapoint = PhantomNodes{phantom_node_vector[curr_node][0], phantom_node_vector[min_id][0]}; + raw_route.segment_end_coordinates.emplace_back(viapoint); + curr_node = min_id; + } + } + + // 4. ROUTE BACK TO STARTING POINT + viapoint = PhantomNodes{raw_route.segment_end_coordinates.back().target_phantom, phantom_node_vector[start_node][0]}; + raw_route.segment_end_coordinates.emplace_back(viapoint); + + // 5. COMPUTE ROUTE + search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, route_parameters.uturns, raw_route); + // SimpleLogger().Write() << "Route starting at " << start_node << " with length " << raw_route.shortest_path_length; - // SimpleLogger().Write() << "visited size is " << visited.size(); - - if (min_id == -1) - { - SimpleLogger().Write() << "ALARM: NO ROUTE!"; - break; - } - else - { - loc_permutation[min_id] = stopover; - visited[min_id] = true; - subroute = PhantomNodes{phantom_node_vector[curr_node][0], phantom_node_vector[min_id][0]}; - raw_route.segment_end_coordinates.emplace_back(subroute); - - // SimpleLogger().Write() << "Found location " << curr_node; - // SimpleLogger().Write() << "Added a looped via" << curr_node << " " << min_id; - - curr_node = min_id; - - // SimpleLogger().Write() << "In loop 3"; + // 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; + min_loc_permutation = loc_permutation; } } - // 4. ROUTE BACK TO STARTING POINT - // SimpleLogger().Write() << "Added a final via"; - subroute = PhantomNodes{raw_route.segment_end_coordinates.back().target_phantom, phantom_node_vector[0][0]}; - raw_route.segment_end_coordinates.emplace_back(subroute); - - // 5. COMPUTE ROUTE - search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, - route_parameters.uturns, raw_route); + SimpleLogger().Write() << "Shortest route " << min_route.shortest_path_length; // return result to json std::unique_ptr> descriptor; descriptor = osrm::make_unique>(facade); descriptor->SetConfig(route_parameters); - descriptor->Run(raw_route, json_result); + descriptor->Run(min_route, json_result); osrm::json::Array json_loc_permutation; - json_loc_permutation.values.insert(json_loc_permutation.values.end(), loc_permutation.begin(), loc_permutation.end()); + json_loc_permutation.values.insert(json_loc_permutation.values.end(), min_loc_permutation.begin(), min_loc_permutation.end()); json_result.values["loc_permutation"] = json_loc_permutation; return 200;