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; |     DataFacadeT *facade; | ||||||
|     std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr; |     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: |   public: | ||||||
|     explicit RoundTripPlugin(DataFacadeT *facade) |     explicit RoundTripPlugin(DataFacadeT *facade) | ||||||
|         : descriptor_string("trip"), facade(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
 |         // 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); |             search_engine_ptr->distance_table(phantom_node_vector); | ||||||
| 
 | 
 | ||||||
|         if (!result_table) |         if (!result_table) | ||||||
| @ -112,120 +228,10 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin | |||||||
|             return 400; |             return 400; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         //////////////////////////////////////////////////////////////////////////////////////////////////
 |         // compute TSP round trip
 | ||||||
|         // 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
 |  | ||||||
|         InternalRouteResult min_route; |         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; |         std::vector<int> min_loc_permutation; | ||||||
| 
 |         NearestNeighbour(route_parameters, phantom_node_vector, *result_table, min_route, 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; |  | ||||||
| 
 | 
 | ||||||
|         // return result to json
 |         // return result to json
 | ||||||
|         std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor; |         std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user