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