capsule tsp round trip computation in a private method
This commit is contained in:
		
							parent
							
								
									108f87678a
								
							
						
					
					
						commit
						b570e89dbd
					
				| @ -59,6 +59,122 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin | ||||
|     DataFacadeT *facade; | ||||
|     std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr; | ||||
| 
 | ||||
|     void NearestNeighbour(const RouteParameters & route_parameters, | ||||
|                           const PhantomNodeArray & phantom_node_vector, | ||||
|                           std::vector<EdgeWeight> & result_table,  | ||||
|                           InternalRouteResult & min_route, | ||||
|                           std::vector<int> & min_loc_permutation) { | ||||
|         //////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|         // 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
 | ||||
|         // 6. DONE!
 | ||||
|         //////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|         const auto number_of_locations = phantom_node_vector.size(); | ||||
|         min_route.shortest_path_length = std::numeric_limits<int>::max(); | ||||
| 
 | ||||
|         // 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<int> is_lonely_island(number_of_locations, 0); | ||||
|         int count_unreachables; | ||||
| 
 | ||||
|         // 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
 | ||||
|                 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<int>::max()) { | ||||
|                         ++count_unreachables; | ||||
|                     } | ||||
|                 } | ||||
|                 if (count_unreachables >= number_of_locations) { | ||||
|                     is_lonely_island[start_node] = 1; | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             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<int> 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<bool> 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<int>::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); | ||||
|              | ||||
|             // 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; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         SimpleLogger().Write() << "Shortest route " << min_route.shortest_path_length; | ||||
|     } | ||||
| 
 | ||||
|   public: | ||||
|     explicit RoundTripPlugin(DataFacadeT *facade) | ||||
|         : descriptor_string("trip"), facade(facade) | ||||
| @ -104,7 +220,7 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin | ||||
|         } | ||||
| 
 | ||||
|         // compute the distance table of all phantom nodes
 | ||||
|         std::shared_ptr<std::vector<EdgeWeight>> result_table = | ||||
|         const std::shared_ptr<std::vector<EdgeWeight>> result_table = | ||||
|             search_engine_ptr->distance_table(phantom_node_vector); | ||||
| 
 | ||||
|         if (!result_table) | ||||
| @ -112,120 +228,10 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin | ||||
|             return 400; | ||||
|         } | ||||
| 
 | ||||
|         //////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|         // 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
 | ||||
|         // 6. DONE!
 | ||||
|         //////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|         const auto number_of_locations = phantom_node_vector.size(); | ||||
|         // min_route is the shortest route found
 | ||||
|         // compute TSP round trip
 | ||||
|         InternalRouteResult min_route; | ||||
|         min_route.shortest_path_length = std::numeric_limits<int>::max(); | ||||
|         // min_loc_permutation stores the order of visited locations of the shortest route
 | ||||
|         std::vector<int> min_loc_permutation; | ||||
| 
 | ||||
|         // 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<int> is_lonely_island(number_of_locations, 0); | ||||
|         int count_unreachables; | ||||
| 
 | ||||
|         // 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
 | ||||
|                 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<int>::max()) { | ||||
|                         ++count_unreachables; | ||||
|                     } | ||||
|                 } | ||||
|                 if (count_unreachables >= number_of_locations) { | ||||
|                     is_lonely_island[start_node] = 1; | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             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<int> 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<bool> 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<int>::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;
 | ||||
|              | ||||
|             // 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; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         SimpleLogger().Write() << "Shortest route " << min_route.shortest_path_length; | ||||
|         NearestNeighbour(route_parameters, phantom_node_vector, *result_table, min_route, min_loc_permutation); | ||||
| 
 | ||||
|         // return result to json
 | ||||
|         std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user