have less redundant code for requests with one or multiple SCCs

This commit is contained in:
Huyen Chau Nguyen 2015-08-19 11:35:36 +02:00
parent 7587e97d46
commit 99cf3219d4
4 changed files with 175 additions and 289 deletions

View File

@ -197,112 +197,66 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
const constexpr std::size_t BF_MAX_FEASABLE = 10;
auto number_of_locations = phantom_node_vector.size();
BOOST_ASSERT_MSG(result_table->size() > 0, "Distance Table is empty.");
std::vector<std::vector<NodeID>> components;
//check if locations are in different strongly connected components (SCC)
const auto maxint = INVALID_EDGE_WEIGHT;
if (*std::max_element(std::begin(*result_table), std::end(*result_table)) == maxint) {
//TODO DELETE
// JSON output related objects
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
descriptor->SetConfig(route_parameters);
TIMER_START(tsp);
// Compute all SCC
std::vector<std::vector<NodeID>> components;
SplitUnaccessibleLocations(number_of_locations, *result_table, components);
// std::vector<std::vector<NodeID>> res_route (components.size()-1);
std::vector<std::vector<NodeID>> res_route;
} else {
// fill a vector with node ids
std::vector<NodeID> location_ids(number_of_locations);
std::iota(location_ids.begin(), location_ids.end(), 0);
components.push_back(location_ids);
}
//run TSP computation for every SCC
for(auto k = 0; k < components.size(); ++k) {
if (components[k].size() > 1) {
std::vector<NodeID> scc_route;
std::vector<std::vector<NodeID>> res_route;
TIMER_START(tsp);
//run TSP computation for every SCC
for(auto k = 0; k < components.size(); ++k) {
if (components[k].size() > 1) {
std::vector<NodeID> scc_route;
// Compute the TSP with the given algorithm
if (route_parameters.tsp_algo == "BF" && route_parameters.coordinates.size() < BF_MAX_FEASABLE) {
SimpleLogger().Write() << "Running brute force on multiple SCC";
scc_route = osrm::tsp::BruteForceTSP(components[k], number_of_locations, *result_table);
res_route.push_back(scc_route);
} else if (route_parameters.tsp_algo == "NN") {
SimpleLogger().Write() << "Running nearest neighbour on multiple SCC";
scc_route = osrm::tsp::NearestNeighbourTSP(components[k], number_of_locations, *result_table);
res_route.push_back(scc_route);
} else if (route_parameters.tsp_algo == "FI") {
SimpleLogger().Write() << "Running farthest insertion on multiple SCC";
scc_route = osrm::tsp::FarthestInsertionTSP(components[k], number_of_locations, *result_table);
res_route.push_back(scc_route);
} else{
SimpleLogger().Write() << "Running farthest insertion on multiple SCC";
scc_route = osrm::tsp::FarthestInsertionTSP(components[k], number_of_locations, *result_table);
res_route.push_back(scc_route);
}
// Compute the TSP with the given algorithm
if (route_parameters.tsp_algo == "BF" && route_parameters.coordinates.size() < BF_MAX_FEASABLE) {
SimpleLogger().Write() << "Running brute force";
scc_route = osrm::tsp::BruteForceTSP(components[k], number_of_locations, *result_table);
res_route.push_back(scc_route);
} else if (route_parameters.tsp_algo == "NN") {
SimpleLogger().Write() << "Running nearest neighbour";
scc_route = osrm::tsp::NearestNeighbourTSP(components[k], number_of_locations, *result_table);
res_route.push_back(scc_route);
} else if (route_parameters.tsp_algo == "FI") {
SimpleLogger().Write() << "Running farthest insertion";
scc_route = osrm::tsp::FarthestInsertionTSP(components[k], number_of_locations, *result_table);
res_route.push_back(scc_route);
} else{
SimpleLogger().Write() << "Running farthest insertion";
scc_route = osrm::tsp::FarthestInsertionTSP(components[k], number_of_locations, *result_table);
res_route.push_back(scc_route);
}
}
std::vector<InternalRouteResult> route;
ComputeRoute(phantom_node_vector, route_parameters, res_route, route);
TIMER_STOP(tsp);
SetRuntimeOutput(TIMER_MSEC(tsp), json_result);
SimpleLogger().Write() << "Computed roundtrip in " << TIMER_MSEC(tsp) << "ms";
// SimpleLogger().Write() << "Route is";
// for (auto x : res_route) {
// for (auto y : x)
// std::cout << y << " ";
// }
// SimpleLogger().Write() << "";
auto dist = 0;
for (auto curr_route : route) {
dist += curr_route.shortest_path_length;
SetGeometry(route_parameters, curr_route, json_result);
}
SetDistanceOutput(dist, json_result);
} else { //run TSP computation for all locations
std::vector<NodeID> res_route;
// Compute the TSP with the given algorithm
TIMER_START(tsp);
// TODO patrick nach userfreundlichkeit fragen, BF vs bf usw
if (route_parameters.tsp_algo == "BF" && route_parameters.coordinates.size() < BF_MAX_FEASABLE) {
SimpleLogger().Write() << "Running brute force";
res_route = osrm::tsp::BruteForceTSP(number_of_locations, *result_table);
} else if (route_parameters.tsp_algo == "NN") {
SimpleLogger().Write() << "Running nearest neighbour";
res_route = osrm::tsp::NearestNeighbourTSP(number_of_locations, *result_table);
} else if (route_parameters.tsp_algo == "FI") {
SimpleLogger().Write() << "Running farthest insertion";
res_route = osrm::tsp::FarthestInsertionTSP(number_of_locations, *result_table);
} else {
SimpleLogger().Write() << "Running farthest insertion";
res_route = osrm::tsp::FarthestInsertionTSP(number_of_locations, *result_table);
}
// TODO asserts numer of result blablabla size
// TODO std::is_permutation
// TODO boost range
InternalRouteResult min_route;
ComputeRoute(phantom_node_vector, route_parameters, res_route, min_route);
TIMER_STOP(tsp);
// SimpleLogger().Write() << "Route is";
// for (auto x : res_route) {
// std::cout << x << " ";
// }
// SimpleLogger().Write() << "";
//TODO TIMER im LOGGER
SetRuntimeOutput(TIMER_MSEC(tsp), json_result);
SimpleLogger().Write() << "Computed roundtrip in " << TIMER_MSEC(tsp) << "ms";
SetLocPermutationOutput(res_route, json_result);
//TODO MEHR ASSERTIONS! :O
SetDistanceOutput(min_route.shortest_path_length, json_result);
SetGeometry(route_parameters, min_route, json_result);
BOOST_ASSERT(min_route.segment_end_coordinates.size() == route_parameters.coordinates.size());
}
std::vector<InternalRouteResult> route;
ComputeRoute(phantom_node_vector, route_parameters, res_route, route);
TIMER_STOP(tsp);
SetRuntimeOutput(TIMER_MSEC(tsp), json_result);
SimpleLogger().Write() << "Computed roundtrip in " << TIMER_MSEC(tsp) << "ms";
// SimpleLogger().Write() << "Route is";
// for (auto x : res_route) {
// for (auto y : x)
// std::cout << y << " ";
// }
// SimpleLogger().Write() << "";
auto dist = 0;
for (auto curr_route : route) {
dist += curr_route.shortest_path_length;
SetGeometry(route_parameters, curr_route, json_result);
}
SetDistanceOutput(dist, json_result);

View File

@ -89,29 +89,6 @@ std::vector<NodeID> BruteForceTSP(std::vector<NodeID> & component,
return route;
}
std::vector<NodeID> BruteForceTSP(const std::size_t number_of_locations,
const std::vector<EdgeWeight> & dist_table) {
std::vector<NodeID> route;
route.reserve(number_of_locations);
// fill a vector with node ids
std::vector<NodeID> location_ids(number_of_locations);
std::iota(location_ids.begin(), location_ids.end(), 0);
EdgeWeight min_route_dist = INVALID_EDGE_WEIGHT;
// check length of all possible permutation of the location ids
do {
const auto new_distance = ReturnDistance(dist_table, location_ids, min_route_dist, number_of_locations);
if (new_distance <= min_route_dist) {
min_route_dist = new_distance;
route = location_ids;
}
} while(std::next_permutation(location_ids.begin(), location_ids.end()));
return route;
}
}
}
} //end namespace osrm
} //end namespace tsp
#endif // TSP_BRUTE_FORCE_HPP

View File

@ -49,12 +49,16 @@ namespace osrm
namespace tsp
{
void GetShortestRoundTrip(const int current_loc,
const std::vector<EdgeWeight> & dist_table,
const int number_of_locations,
std::vector<NodeID> & route,
int & min_trip_distance,
std::vector<NodeID>::iterator & next_insert_point_candidate){
using NodeIterator = typename std::vector<NodeID>::iterator;
std::pair<EdgeWeight, NodeIterator> GetShortestRoundTrip(const int current_loc,
const std::vector<EdgeWeight> & dist_table,
const int number_of_locations,
std::vector<NodeID> & route){
auto min_trip_distance = INVALID_EDGE_WEIGHT;
NodeIterator next_insert_point_candidate;
// for all nodes in the current trip find the best insertion resulting in the shortest path
// assert min 2 nodes in route
for (auto from_node = route.begin(); from_node != std::prev(route.end()); ++from_node) {
@ -81,6 +85,55 @@ void GetShortestRoundTrip(const int current_loc,
min_trip_distance = trip_dist;
next_insert_point_candidate = to_node;
}
return std::make_pair(min_trip_distance, next_insert_point_candidate);
}
// given two initial start nodes, find a roundtrip route using the farthest insertion algorithm
std::vector<NodeID> FindRoute(const std::size_t & number_of_locations,
const std::size_t & size_of_component,
const std::vector<NodeID> & locations,
const std::vector<EdgeWeight> & dist_table,
const NodeID & start1,
const NodeID & start2) {
std::vector<NodeID> route;
route.reserve(number_of_locations);
// tracks which nodes have been already visited
std::vector<bool> visited(number_of_locations, false);
visited[start1] = true;
visited[start2] = true;
route.push_back(start1);
route.push_back(start2);
// add all other nodes missing (two nodes are already in the initial start trip)
for (int j = 2; j < size_of_component; ++j) {
auto farthest_distance = 0;
auto next_node = -1;
NodeIterator next_insert_point;
// find unvisited loc i that is the farthest away from all other visited locs
for (auto i : locations) {
// find the shortest distance from i to all visited nodes
if (!visited[i]) {
auto insert_candidate = GetShortestRoundTrip(i, dist_table, number_of_locations, route);
// add the location to the current trip such that it results in the shortest total tour
if (insert_candidate.first >= farthest_distance) {
farthest_distance = insert_candidate.first;
next_node = i;
next_insert_point = insert_candidate.second;
}
}
}
// mark as visited and insert node
visited[next_node] = true;
route.insert(next_insert_point, next_node);
}
return route;
}
// osrm::tsp::FarthestInsertionTSP(components[k], phantom_node_vector, *result_table, scc_route);
@ -96,126 +149,92 @@ std::vector<NodeID> FarthestInsertionTSP(const std::vector<NodeID> & locations,
// 5. DONE!
//////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<NodeID> route;
route.reserve(number_of_locations);
const int size_of_component = locations.size();
// tracks which nodes have been already visited
std::vector<bool> visited(number_of_locations, false);
auto max_dist = 0;
auto max_from = -1;
auto max_to = -1;
//TODO
for (auto x : locations) {
for (auto y : locations) {
auto xy_dist = *(dist_table.begin() + x * number_of_locations + y);
if (xy_dist > max_dist) {
max_dist = xy_dist;
max_from = x;
max_to = y;
}
}
}
if (size_of_component == number_of_locations) {
// find the pair of location with the biggest distance and make the pair the initial start trip
const auto index = std::distance(dist_table.begin(), std::max_element(dist_table.begin(), dist_table.end()));
max_from = index / number_of_locations;
max_to = index % number_of_locations;
visited[max_from] = true;
visited[max_to] = true;
route.push_back(max_from);
route.push_back(max_to);
// SimpleLogger().Write() << size_of_component;
// add all other nodes missing (two nodes are already in the initial start trip)
for (int j = 2; j < size_of_component; ++j) {
// SimpleLogger().Write() << j << "/" << size_of_component;
auto farthest_distance = 0;
auto next_node = -1;
std::vector<NodeID>::iterator next_insert_point;
// find unvisited loc i that is the farthest away from all other visited locs
for (auto i : locations) {
// find the shortest distance from i to all visited nodes
if (!visited[i]) {
auto min_trip_distance = INVALID_EDGE_WEIGHT;
std::vector<NodeID>::iterator next_insert_point_candidate;
GetShortestRoundTrip(i, dist_table, number_of_locations, route, min_trip_distance, next_insert_point_candidate);
// add the location to the current trip such that it results in the shortest total tour
// SimpleLogger().Write() << "min_trip_distance " << min_trip_distance;
if (min_trip_distance >= farthest_distance) {
farthest_distance = min_trip_distance;
next_node = i;
next_insert_point = next_insert_point_candidate;
} else {
auto max_dist = 0;
for (auto x : locations) {
for (auto y : locations) {
auto xy_dist = *(dist_table.begin() + x * number_of_locations + y);
if (xy_dist > max_dist) {
max_dist = xy_dist;
max_from = x;
max_to = y;
}
}
}
// SimpleLogger().Write() << "next node " << next_node;
// mark as visited and insert node
visited[next_node] = true;
route.insert(next_insert_point, next_node);
}
return route;
return FindRoute(number_of_locations, size_of_component, locations, dist_table, max_from, max_to);
}
std::vector<NodeID> FarthestInsertionTSP(const std::size_t number_of_locations,
const std::vector<EdgeWeight> & dist_table) {
//////////////////////////////////////////////////////////////////////////////////////////////////
// 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 and whose insertion will make the round trip the longest
// 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!
//////////////////////////////////////////////////////////////////////////////////////////////////
// std::vector<NodeID> FarthestInsertionTSP(const std::size_t number_of_locations,
// const std::vector<EdgeWeight> & dist_table) {
// //////////////////////////////////////////////////////////////////////////////////////////////////
// // 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 and whose insertion will make the round trip the longest
// // 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!
// //////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<NodeID> route;
route.reserve(number_of_locations);
// std::vector<NodeID> route;
// route.reserve(number_of_locations);
// tracks which nodes have been already visited
std::vector<bool> visited(number_of_locations, false);
// // tracks which nodes have been already visited
// std::vector<bool> visited(number_of_locations, false);
// find the pair of location with the biggest distance and make the pair the initial start trip
const auto index = std::distance(dist_table.begin(), std::max_element(dist_table.begin(), dist_table.end()));
const int max_from = index / number_of_locations;
const int max_to = index % number_of_locations;
visited[max_from] = true;
visited[max_to] = true;
route.push_back(max_from);
route.push_back(max_to);
// // find the pair of location with the biggest distance and make the pair the initial start trip
// const auto index = std::distance(dist_table.begin(), std::max_element(dist_table.begin(), dist_table.end()));
// const int max_from = index / number_of_locations;
// const int max_to = index % number_of_locations;
// visited[max_from] = true;
// visited[max_to] = true;
// route.push_back(max_from);
// route.push_back(max_to);
// add all other nodes missing (two nodes are already in the initial start trip)
for (int j = 2; j < number_of_locations; ++j) {
auto farthest_distance = 0;
auto next_node = -1;
//todo move out of loop and overwrite
std::vector<NodeID>::iterator next_insert_point;
// // add all other nodes missing (two nodes are already in the initial start trip)
// for (int j = 2; j < number_of_locations; ++j) {
// auto farthest_distance = 0;
// auto next_node = -1;
// //todo move out of loop and overwrite
// NodeIterator next_insert_point;
// find unvisited loc i that is the farthest away from all other visited locs
for (int i = 0; i < number_of_locations; ++i) {
if (!visited[i]) {
auto min_trip_distance = INVALID_EDGE_WEIGHT;
std::vector<NodeID>::iterator next_insert_point_candidate;
// // find unvisited loc i that is the farthest away from all other visited locs
// for (int i = 0; i < number_of_locations; ++i) {
// if (!visited[i]) {
// auto min_trip_distance = INVALID_EDGE_WEIGHT;
// NodeIterator next_insert_point_candidate;
GetShortestRoundTrip(i, dist_table, number_of_locations, route, min_trip_distance, next_insert_point_candidate);
// GetShortestRoundTrip(i, dist_table, number_of_locations, route, min_trip_distance, next_insert_point_candidate);
// add the location to the current trip such that it results in the shortest total tour
if (min_trip_distance >= farthest_distance) {
farthest_distance = min_trip_distance;
next_node = i;
next_insert_point = next_insert_point_candidate;
}
}
}
// // add the location to the current trip such that it results in the shortest total tour
// if (min_trip_distance >= farthest_distance) {
// farthest_distance = min_trip_distance;
// next_node = i;
// next_insert_point = next_insert_point_candidate;
// }
// }
// }
// mark as visited and insert node
visited[next_node] = true;
route.insert(next_insert_point, next_node);
}
return route;
}
// // mark as visited and insert node
// visited[next_node] = true;
// route.insert(next_insert_point, next_node);
// }
// return route;
// }
}
}
} //end namespace osrm
} //end namespace tsp
#endif // TSP_FARTHEST_INSERTION_HPP

View File

@ -110,70 +110,6 @@ std::vector<NodeID> NearestNeighbourTSP(const std::vector<NodeID> & locations,
return route;
}
std::vector<NodeID> NearestNeighbourTSP(const std::size_t number_of_locations,
const std::vector<EdgeWeight> & dist_table) {
//////////////////////////////////////////////////////////////////////////////////////////////////
// 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
// 7. DONE!
//////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<NodeID> route;
route.reserve(number_of_locations);
int shortest_trip_distance = INVALID_EDGE_WEIGHT;
// ALWAYS START AT ANOTHER STARTING POINT
for(int start_node = 0; start_node < number_of_locations; ++start_node)
{
int curr_node = start_node;
std::vector<NodeID> curr_route;
curr_route.reserve(number_of_locations);
curr_route.push_back(start_node);
// visited[i] indicates whether node i was already visited by the salesman
std::vector<bool> visited(number_of_locations, false);
visited[start_node] = true;
// 3. REPEAT FOR EVERY UNVISITED NODE
int trip_dist = 0;
for(int via_point = 1; via_point < number_of_locations; ++via_point)
{
int min_dist = INVALID_EDGE_WEIGHT;
int min_id = -1;
// 2. FIND NEAREST NEIGHBOUR
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) {
const auto index = std::distance(row_begin_iterator, it);
if (!visited[index] && *it < min_dist)
{
min_dist = *it;
min_id = index;
}
}
visited[min_id] = true;
curr_route.push_back(min_id);
trip_dist += min_dist;
curr_node = min_id;
}
// check round trip with this starting point is shorter than the shortest round trip found till now
if (trip_dist < shortest_trip_distance) {
shortest_trip_distance = trip_dist;
route = curr_route;
}
}
return route;
}
}
}
#endif // TSP_NEAREST_NEIGHBOUR_HPP