add a wrapper for the distance table for better access

This commit is contained in:
Huyen Chau Nguyen 2015-08-19 14:04:59 +02:00
parent 99cf3219d4
commit 78a8cf6982
6 changed files with 157 additions and 74 deletions

View File

@ -36,30 +36,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
template <typename T> class MatrixGraphWrapper {
public:
MatrixGraphWrapper(std::vector<T> table, const unsigned number_of_nodes) : table_(table), number_of_nodes_(number_of_nodes) {};
MatrixGraphWrapper(std::vector<T> table, const std::size_t number_of_nodes) : table_(table), number_of_nodes_(number_of_nodes) {};
unsigned GetNumberOfNodes() const {
std::size_t GetNumberOfNodes() const {
return number_of_nodes_;
}
std::vector<unsigned> GetAdjacentEdgeRange(const unsigned node) const {
std::vector<unsigned> edges;
const auto maxint = std::numeric_limits<int>::max();
for (auto i = 0; i < number_of_nodes_; ++i) {
if (*(table_.begin() + node * number_of_nodes_ + i) != maxint) {
edges.push_back(i);
}
}
std::vector<EdgeWeight> GetAdjacentEdgeRange(const NodeID node) const {
std::vector<EdgeWeight> edges;
auto neq_invalid_edge_weight = [](EdgeWeight e){return (e != INVALID_EDGE_WEIGHT);};
std::copy_if(std::begin(table_),
std::end(table_),
std::back_inserter(edges),
neq_invalid_edge_weight);
return edges;
}
unsigned GetTarget(const unsigned edge) const {
EdgeWeight GetTarget(const EdgeWeight edge) const {
return edge;
}
private:
std::vector<T> table_;
const unsigned number_of_nodes_;
const std::size_t number_of_nodes_;
};

View File

@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../util/string_util.hpp"
#include "../util/timing_util.hpp"
#include "../util/simple_logger.hpp"
#include "../util/dist_table_wrapper.hpp"
#include <osrm/json_container.hpp>
#include <boost/assert.hpp>
@ -56,6 +57,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory>
#include <unordered_map>
#include <string>
#include <utility>
#include <vector>
#include <limits>
#include <iterator>
@ -97,20 +99,18 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
phantom_node_vector[i], 1);
if (phantom_node_vector[i].size() > 1) {
phantom_node_vector[i].erase(phantom_node_vector[i].begin());
phantom_node_vector[i].erase(std::begin(phantom_node_vector[i]));
}
BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes()));
}
}
void SplitUnaccessibleLocations(const std::size_t number_of_locations,
std::vector<EdgeWeight> & result_table,
const DistTableWrapper<EdgeWeight> & result_table,
std::vector<std::vector<NodeID>> & components) {
// Run TarjanSCC
auto wrapper = std::make_shared<MatrixGraphWrapper<EdgeWeight>>(result_table, number_of_locations);
// auto empty_restriction = RestrictionMap(std::vector<TurnRestriction>());
// std::vector<bool> empty_vector;
auto wrapper = std::make_shared<MatrixGraphWrapper<EdgeWeight>>(result_table.GetTable(), number_of_locations);
auto scc = TarjanSCC<MatrixGraphWrapper<EdgeWeight>>(wrapper);
scc.run();
@ -126,7 +126,7 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
template <typename number>
void SetLocPermutationOutput(const std::vector<number> & loc_permutation, osrm::json::Object & 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(std::end(json_loc_permutation.values), std::begin(loc_permutation), std::end(loc_permutation));
json_result.values["loc_permutation"] = json_loc_permutation;
}
@ -152,14 +152,14 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
InternalRouteResult & min_route) {
// given he final trip, compute total distance and return the route and location permutation
PhantomNodes viapoint;
for (auto it = trip.begin(); it != std::prev(trip.end()); ++it) {
for (auto it = std::begin(trip); it != std::prev(std::end(trip)); ++it) {
auto from_node = *it;
auto to_node = *std::next(it);
viapoint = PhantomNodes{phantom_node_vector[from_node][0], phantom_node_vector[to_node][0]};
min_route.segment_end_coordinates.emplace_back(viapoint);
}
// check dist between last and first location too
viapoint = PhantomNodes{phantom_node_vector[*std::prev(trip.end())][0], phantom_node_vector[trip.front()][0]};
viapoint = PhantomNodes{phantom_node_vector[*std::prev(std::end(trip))][0], phantom_node_vector[trip.front()][0]};
min_route.segment_end_coordinates.emplace_back(viapoint);
search_engine_ptr->shortest_path(min_route.segment_end_coordinates, route_parameters.uturns, min_route);
}
@ -186,29 +186,29 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
PhantomNodeArray phantom_node_vector(route_parameters.coordinates.size());
GetPhantomNodes(route_parameters, phantom_node_vector);
auto number_of_locations = phantom_node_vector.size();
// compute the distance table of all phantom nodes
const std::shared_ptr<std::vector<EdgeWeight>> result_table =
search_engine_ptr->distance_table(phantom_node_vector);
if (!result_table){
const auto result_table = DistTableWrapper<EdgeWeight>(*search_engine_ptr->distance_table(phantom_node_vector),
number_of_locations);
if (result_table.size() == 0){
return 400;
}
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.");
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) {
if (*std::max_element(result_table.begin(), result_table.end()) == maxint) {
// Compute all SCC
SplitUnaccessibleLocations(number_of_locations, *result_table, components);
SplitUnaccessibleLocations(number_of_locations, result_table, components);
} 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);
std::iota(std::begin(location_ids), std::end(location_ids), 0);
components.push_back(std::move(location_ids));
}
@ -222,19 +222,19 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
// 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);
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);
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);
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);
scc_route = osrm::tsp::FarthestInsertionTSP(components[k], number_of_locations, result_table);
res_route.push_back(scc_route);
}
}
@ -244,12 +244,6 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
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) {

View File

@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../data_structures/search_engine.hpp"
#include "../util/string_util.hpp"
#include "../util/dist_table_wrapper.hpp"
#include <osrm/json_container.hpp>
@ -52,24 +53,22 @@ namespace tsp
{
template <typename number>
int ReturnDistance(const std::vector<EdgeWeight> & dist_table,
int ReturnDistance(const DistTableWrapper<EdgeWeight> & dist_table,
const std::vector<number> & location_order,
const EdgeWeight min_route_dist,
const int number_of_locations) {
int route_dist = 0;
const std::size_t number_of_locations) {
EdgeWeight route_dist = 0;
int i = 0;
while (i < location_order.size() - 1) {
route_dist += *(dist_table.begin() + (location_order[i] * number_of_locations) + location_order[i+1]);
while (i < location_order.size()) {
route_dist += dist_table(location_order[i], location_order[(i+1) % number_of_locations]);
++i;
}
//get distance from last location to first location
route_dist += *(dist_table.begin() + (location_order[location_order.size()-1] * number_of_locations) + location_order[0]);
return route_dist;
}
std::vector<NodeID> BruteForceTSP(std::vector<NodeID> & component,
const std::size_t number_of_locations,
const std::vector<EdgeWeight> & dist_table) {
const DistTableWrapper<EdgeWeight> & dist_table) {
std::vector<NodeID> route;
route.reserve(number_of_locations);
@ -84,7 +83,7 @@ std::vector<NodeID> BruteForceTSP(std::vector<NodeID> & component,
min_route_dist = new_distance;
route = component;
}
} while(std::next_permutation(component.begin(), component.end()));
} while(std::next_permutation(std::begin(component), std::end(component)));
return route;
}

View File

@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../data_structures/search_engine.hpp"
#include "../util/string_util.hpp"
#include "../util/dist_table_wrapper.hpp"
#include "../tools/tsp_logs.hpp"
#include <osrm/json_container.hpp>
@ -51,8 +52,10 @@ namespace tsp
using NodeIterator = typename std::vector<NodeID>::iterator;
std::pair<EdgeWeight, NodeIterator> GetShortestRoundTrip(const int current_loc,
const std::vector<EdgeWeight> & dist_table,
// given a route and a new location, find the best place of insertion and
// check the distance of roundtrip when the new location is additionally visited
std::pair<EdgeWeight, NodeIterator> GetShortestRoundTrip(const int new_loc,
const DistTableWrapper<EdgeWeight> & dist_table,
const int number_of_locations,
std::vector<NodeID> & route){
@ -61,12 +64,15 @@ std::pair<EdgeWeight, NodeIterator> GetShortestRoundTrip(const int current_loc,
// 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) {
const auto to_node = std::next(from_node);
for (auto from_node = std::begin(route); from_node != std::end(route); ++from_node) {
auto to_node = std::next(from_node);
if (to_node == std::end(route)) {
to_node = std::begin(route);
}
const auto dist_from = *(dist_table.begin() + (*from_node * number_of_locations) + current_loc);
const auto dist_to = *(dist_table.begin() + (current_loc * number_of_locations) + *to_node);
const auto trip_dist = dist_from + dist_to - *(dist_table.begin() + (*from_node * number_of_locations) + *to_node);
const auto dist_from = dist_table(*from_node, new_loc);
const auto dist_to = dist_table(new_loc, *to_node);
const auto trip_dist = dist_from + dist_to - dist_table(*from_node, *to_node);;
// from all possible insertions to the current trip, choose the shortest of all insertions
if (trip_dist < min_trip_distance) {
@ -74,17 +80,6 @@ std::pair<EdgeWeight, NodeIterator> GetShortestRoundTrip(const int current_loc,
next_insert_point_candidate = to_node;
}
}
// check insertion between last and first location too
auto from_node = std::prev(route.end());
auto to_node = route.begin();
auto dist_from = *(dist_table.begin() + (*from_node * number_of_locations) + current_loc);
auto dist_to = *(dist_table.begin() + (current_loc * number_of_locations) + *to_node);
auto trip_dist = dist_from + dist_to - *(dist_table.begin() + (*from_node * number_of_locations) + *to_node);
if (trip_dist < min_trip_distance) {
min_trip_distance = trip_dist;
next_insert_point_candidate = to_node;
}
return std::make_pair(min_trip_distance, next_insert_point_candidate);
}
@ -93,7 +88,7 @@ std::pair<EdgeWeight, NodeIterator> GetShortestRoundTrip(const int current_loc,
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 DistTableWrapper<EdgeWeight> & dist_table,
const NodeID & start1,
const NodeID & start2) {
std::vector<NodeID> route;
@ -136,10 +131,9 @@ std::vector<NodeID> FindRoute(const std::size_t & number_of_locations,
return route;
}
// osrm::tsp::FarthestInsertionTSP(components[k], phantom_node_vector, *result_table, scc_route);
std::vector<NodeID> FarthestInsertionTSP(const std::vector<NodeID> & locations,
const std::size_t number_of_locations,
const std::vector<EdgeWeight> & dist_table) {
const DistTableWrapper<EdgeWeight> & dist_table) {
//////////////////////////////////////////////////////////////////////////////////////////////////
// START FARTHEST INSERTION HERE
// 1. start at a random round trip of 2 locations
@ -149,7 +143,7 @@ std::vector<NodeID> FarthestInsertionTSP(const std::vector<NodeID> & locations,
// 5. DONE!
//////////////////////////////////////////////////////////////////////////////////////////////////
const int size_of_component = locations.size();
const auto size_of_component = locations.size();
auto max_from = -1;
auto max_to = -1;
@ -163,7 +157,7 @@ std::vector<NodeID> FarthestInsertionTSP(const std::vector<NodeID> & locations,
auto max_dist = 0;
for (auto x : locations) {
for (auto y : locations) {
auto xy_dist = *(dist_table.begin() + x * number_of_locations + y);
auto xy_dist = dist_table(x, y);
if (xy_dist > max_dist) {
max_dist = xy_dist;
max_from = x;

View File

@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../data_structures/search_engine.hpp"
#include "../util/string_util.hpp"
#include "../util/simple_logger.hpp"
#include "../util/dist_table_wrapper.hpp"
#include <osrm/json_container.hpp>
@ -50,7 +51,7 @@ namespace tsp
std::vector<NodeID> NearestNeighbourTSP(const std::vector<NodeID> & locations,
const std::size_t number_of_locations,
const std::vector<EdgeWeight> & dist_table) {
const DistTableWrapper<EdgeWeight> & dist_table) {
//////////////////////////////////////////////////////////////////////////////////////////////////
// START GREEDY NEAREST NEIGHBOUR HERE
// 1. grab a random location and mark as starting point
@ -89,9 +90,10 @@ std::vector<NodeID> NearestNeighbourTSP(const std::vector<NodeID> & locations,
// 2. FIND NEAREST NEIGHBOUR
for (auto next : locations) {
auto curr_dist = dist_table(curr_node, next);
if(!visited[next] &&
*(dist_table.begin() + curr_node * number_of_locations + next) < min_dist) {
min_dist = *(dist_table.begin() + curr_node * number_of_locations + next);
curr_dist < min_dist) {
min_dist = curr_dist;
min_id = next;
}
}

View File

@ -0,0 +1,95 @@
/*
Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DIST_TABLE_WRAPPER_H
#define DIST_TABLE_WRAPPER_H
#include <vector>
#include <utility>
#include <boost/assert.hpp>
//This Wrapper provides an easier access to a distance table that is given as an linear vector
template <typename T> class DistTableWrapper {
public:
using Iterator = typename std::vector<T>::iterator;
using ConstIterator = typename std::vector<T>::const_iterator;
DistTableWrapper(std::vector<T> table, std::size_t number_of_nodes)
: table_(std::move(table)), number_of_nodes_(number_of_nodes) {
BOOST_ASSERT_MSG(table.size() == 0, "table is empty");
BOOST_ASSERT_MSG(number_of_nodes_ * number_of_nodes_ < table_, "number_of_nodes_ is invalid");
};
std::size_t GetNumberOfNodes() const {
return number_of_nodes_;
}
std::size_t size() const {
return table_.size();
}
EdgeWeight operator() (NodeID from, NodeID to) const {
BOOST_ASSERT_MSG(from < number_of_nodes_, "from ID is out of bound");
BOOST_ASSERT_MSG(to < number_of_nodes_, "to ID is out of bound");
const auto index = from * number_of_nodes_ + to;
BOOST_ASSERT_MSG(index < table_size(), "index is out of bound");
return table_[index];
}
ConstIterator begin() const{
return std::begin(table_);
}
Iterator begin() {
return std::begin(table_);
}
ConstIterator end() const{
return std::end(table_);
}
Iterator end() {
return std::end(table_);
}
NodeID GetIndexOfMaxValue() const {
return std::distance(table_.begin(), std::max_element(table_.begin(), table_.end()));
}
std::vector<T> GetTable() const {
return table_;
}
private:
std::vector<T> table_;
const std::size_t number_of_nodes_;
};
#endif // DIST_TABLE_WRAPPER_H