split algorithms in different plugins for better evaluation

split tsp brute force algorithm for better testing

refactor and clean up
This commit is contained in:
Chau Nguyen 2015-06-22 20:09:00 +02:00 committed by Huyen Chau Nguyen
parent f0d66ff0fb
commit a40b3a98dc
11 changed files with 723 additions and 74 deletions

View File

@ -42,6 +42,9 @@ class named_mutex;
#include "../plugins/nearest.hpp"
#include "../plugins/timestamp.hpp"
#include "../plugins/round_trip.hpp"
#include "../plugins/round_trip_NN.hpp"
#include "../plugins/round_trip_BF.hpp"
#include "../plugins/round_trip_FI.hpp"
#include "../plugins/viaroute.hpp"
#include "../plugins/match.hpp"
#include "../server/data_structures/datafacade_base.hpp"
@ -88,6 +91,9 @@ OSRM_impl::OSRM_impl(libosrm_config &lib_config)
RegisterPlugin(new TimestampPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new ViaRoutePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new RoundTripPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new RoundTripPluginNN<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new RoundTripPluginBF<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new RoundTripPluginFI<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
}
OSRM_impl::~OSRM_impl()

View File

@ -28,6 +28,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef OSRM_IMPL_HPP
#define OSRM_IMPL_HPP
// #if __cplusplus > 199711L
// #define register // Deprecated in C++11.
// #endif // #if __cplusplus > 199711L
class BasePlugin;
struct RouteParameters;

View File

@ -116,70 +116,83 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
}
// compute TSP round trip
InternalRouteResult min_route_nn;
InternalRouteResult min_route_fi;
InternalRouteResult min_route_bf;
std::vector<int> min_loc_permutation_nn(phantom_node_vector.size(), -1);
std::vector<int> min_loc_permutation_fi(phantom_node_vector.size(), -1);
std::vector<int> min_loc_permutation_bf(phantom_node_vector.size(), -1);
InternalRouteResult min_route;
std::vector<int> min_loc_permutation(phantom_node_vector.size(), -1);
TIMER_STOP(tsp_pre);
//######################### NEAREST NEIGHBOUR ###############################//
TIMER_START(tsp_nn);
osrm::tsp::NearestNeighbour(route_parameters, phantom_node_vector, *result_table, min_route_nn, min_loc_permutation_nn);
search_engine_ptr->shortest_path(min_route_nn.segment_end_coordinates, route_parameters.uturns, min_route_nn);
TIMER_STOP(tsp_nn);
SimpleLogger().Write() << "Distance " << min_route_nn.shortest_path_length;
SimpleLogger().Write() << "Time " << TIMER_MSEC(tsp_nn) + TIMER_MSEC(tsp_pre);
TIMER_START(tsp);
osrm::tsp::NearestNeighbour(route_parameters, phantom_node_vector, *result_table, min_route, min_loc_permutation);
search_engine_ptr->shortest_path(min_route.segment_end_coordinates, route_parameters.uturns, min_route);
TIMER_STOP(tsp);
SimpleLogger().Write() << "Distance " << min_route.shortest_path_length;
SimpleLogger().Write() << "Time " << TIMER_MSEC(tsp) + TIMER_MSEC(tsp_pre);
osrm::json::Array json_loc_permutation_nn;
json_loc_permutation_nn.values.insert(json_loc_permutation_nn.values.end(), min_loc_permutation_nn.begin(), min_loc_permutation_nn.end());
json_result.values["nn_loc_permutation"] = json_loc_permutation_nn;
json_result.values["nn_distance"] = min_route_nn.shortest_path_length;
json_result.values["nn_runtime"] = TIMER_MSEC(tsp_nn) + TIMER_MSEC(tsp_pre);
osrm::json::Array json_loc_permutation;
json_loc_permutation.values.insert(json_loc_permutation.values.end(), min_loc_permutation.begin(), min_loc_permutation.end());
json_result.values["loc_permutation"] = json_loc_permutation;
json_result.values["distance"] = min_route.shortest_path_length;
json_result.values["runtime"] = TIMER_MSEC(tsp);
//########################### BRUTE FORCE ####################################//
if (route_parameters.coordinates.size() < 12) {
TIMER_START(tsp_bf);
osrm::tsp::BruteForce(route_parameters, phantom_node_vector, *result_table, min_route_bf, min_loc_permutation_bf);
search_engine_ptr->shortest_path(min_route_bf.segment_end_coordinates, route_parameters.uturns, min_route_bf);
TIMER_STOP(tsp_bf);
SimpleLogger().Write() << "Distance " << min_route_bf.shortest_path_length;
SimpleLogger().Write() << "Time " << TIMER_MSEC(tsp_bf) + TIMER_MSEC(tsp_pre);
osrm::json::Array json_loc_permutation_bf;
json_loc_permutation_bf.values.insert(json_loc_permutation_bf.values.end(), min_loc_permutation_bf.begin(), min_loc_permutation_bf.end());
json_result.values["bf_loc_permutation"] = json_loc_permutation_bf;
json_result.values["bf_distance"] = min_route_bf.shortest_path_length;
json_result.values["bf_runtime"] = TIMER_MSEC(tsp_bf) + TIMER_MSEC(tsp_pre);
} else {
json_result.values["bf_distance"] = -1;
json_result.values["bf_runtime"] = -1;
}
// if (route_parameters.tsp_algo.compare("NN"))
// //######################### NEAREST NEIGHBOUR ###############################//
// TIMER_START(tsp);
// osrm::tsp::NearestNeighbour(route_parameters, phantom_node_vector, *result_table, min_route, min_loc_permutation);
// search_engine_ptr->shortest_path(min_route.segment_end_coordinates, route_parameters.uturns, min_route);
// TIMER_STOP(tsp);
// SimpleLogger().Write() << "Distance " << min_route.shortest_path_length;
// SimpleLogger().Write() << "Time " << TIMER_MSEC(tsp) + TIMER_MSEC(tsp_pre);
// osrm::json::Array json_loc_permutation;
// json_loc_permutation.values.insert(json_loc_permutation.values.end(), min_loc_permutation.begin(), min_loc_permutation.end());
// json_result.values["loc_permutation"] = json_loc_permutation;
// json_result.values["distance"] = min_route.shortest_path_length;
// json_result.values["runtime"] = TIMER_MSEC(tsp);
// else if (route_parameters.tsp_algo.compare("BF")
// //########################### BRUTE FORCE ####################################//
// if (route_parameters.coordinates.size() < 12) {
// TIMER_START(tsp);
// osrm::tsp::BruteForce(route_parameters, phantom_node_vector, *result_table, min_route, min_loc_permutation);
// search_engine_ptr->shortest_path(min_route.segment_end_coordinates, route_parameters.uturns, min_route);
// TIMER_STOP(tsp);
// SimpleLogger().Write() << "Distance " << min_route.shortest_path_length;
// SimpleLogger().Write() << "Time " << TIMER_MSEC(tsp);
//######################## FARTHEST INSERTION ###############################//
TIMER_START(tsp_fi);
osrm::tsp::FarthestInsertion(route_parameters, phantom_node_vector, *result_table, min_route_fi, min_loc_permutation_fi);
search_engine_ptr->shortest_path(min_route_fi.segment_end_coordinates, route_parameters.uturns, min_route_fi);
TIMER_STOP(tsp_fi);
SimpleLogger().Write() << "Distance " << min_route_fi.shortest_path_length;
SimpleLogger().Write() << "Time " << TIMER_MSEC(tsp_fi) + TIMER_MSEC(tsp_pre);
// osrm::json::Array json_loc_permutation;
// json_loc_permutation.values.insert(json_loc_permutation.values.end(), min_loc_permutation.begin(), min_loc_permutation.end());
// json_result.values["loc_permutation"] = json_loc_permutation;
// json_result.values["distance"] = min_route.shortest_path_length;
// json_result.values["runtime"] = TIMER_MSEC(tsp);
// } else {
// json_result.values["distance"] = -1;
// json_result.values["runtime"] = -1;
// }
// else
// //######################## FARTHEST INSERTION ###############################//
// TIMER_START(tsp);
// osrm::tsp::FarthestInsertion(route_parameters, phantom_node_vector, *result_table, min_route, min_loc_permutation);
// search_engine_ptr->shortest_path(min_route.segment_end_coordinates, route_parameters.uturns, min_route);
// TIMER_STOP(tsp);
// SimpleLogger().Write() << "Distance " << min_route.shortest_path_length;
// SimpleLogger().Write() << "Time " << TIMER_MSEC(tsp);
osrm::json::Array json_loc_permutation_fi;
json_loc_permutation_fi.values.insert(json_loc_permutation_fi.values.end(), min_loc_permutation_fi.begin(), min_loc_permutation_fi.end());
json_result.values["fi_loc_permutation"] = json_loc_permutation_fi;
json_result.values["fi_distance"] = min_route_fi.shortest_path_length;
json_result.values["fi_runtime"] = TIMER_MSEC(tsp_fi) + TIMER_MSEC(tsp_pre);
// osrm::json::Array json_loc_permutation;
// json_loc_permutation.values.insert(json_loc_permutation.values.end(), min_loc_permutation.begin(), min_loc_permutation.end());
// json_result.values["loc_permutation"] = json_loc_permutation;
// json_result.values["distance"] = min_route.shortest_path_length;
// json_result.values["runtime"] = TIMER_MSEC(tsp);
// return geometry result to json
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
descriptor->SetConfig(route_parameters);
descriptor->Run(min_route_fi, json_result);
descriptor->Run(min_route, json_result);

157
plugins/round_trip_BF.hpp Normal file
View File

@ -0,0 +1,157 @@
/*
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 ROUND_TRIP_BF_HPP
#define ROUND_TRIP_BF_HPP
#include "plugin_base.hpp"
#include "../algorithms/object_encoder.hpp"
#include "../routing_algorithms/tsp_nearest_neighbour.hpp"
#include "../routing_algorithms/tsp_farthest_insertion.hpp"
#include "../routing_algorithms/tsp_brute_force.hpp"
#include "../data_structures/query_edge.hpp"
#include "../data_structures/search_engine.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../descriptors/json_descriptor.hpp"
#include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp"
#include "../util/string_util.hpp"
#include "../util/timing_util.hpp"
#include "../util/simple_logger.hpp"
#include <osrm/json_container.hpp>
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <unordered_map>
#include <string>
#include <vector>
#include <limits>
template <class DataFacadeT> class RoundTripPluginBF final : public BasePlugin
{
private:
std::string descriptor_string;
DataFacadeT *facade;
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
public:
explicit RoundTripPluginBF(DataFacadeT *facade)
: descriptor_string("tripBF"), facade(facade)
{
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
}
const std::string GetDescriptor() const override final { return descriptor_string; }
int HandleRequest(const RouteParameters &route_parameters,
osrm::json::Object &json_result) override final
{
TIMER_START(tsp_pre);
// check if all inputs are coordinates
if (!check_all_coordinates(route_parameters.coordinates))
{
return 400;
}
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
// find phantom nodes for all input coords
PhantomNodeArray phantom_node_vector(route_parameters.coordinates.size());
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
{
// if client hints are helpful, encode hints
if (checksum_OK && i < route_parameters.hints.size() &&
!route_parameters.hints[i].empty())
{
PhantomNode current_phantom_node;
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
{
phantom_node_vector[i].emplace_back(std::move(current_phantom_node));
continue;
}
}
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());
}
BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes()));
}
// 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)
{
return 400;
}
// compute TSP round trip
InternalRouteResult min_route;
std::vector<int> min_loc_permutation(phantom_node_vector.size(), -1);
TIMER_STOP(tsp_pre);
//########################### BRUTE FORCE ####################################//
if (route_parameters.coordinates.size() < 11) {
TIMER_START(tsp);
osrm::tsp::BruteForceTSP(phantom_node_vector, *result_table, min_route, min_loc_permutation);
search_engine_ptr->shortest_path(min_route.segment_end_coordinates, route_parameters.uturns, min_route);
TIMER_STOP(tsp);
BOOST_ASSERT(min_route.segment_end_coordinates.size() == route_parameters.coordinates.size());
osrm::json::Array json_loc_permutation;
json_loc_permutation.values.insert(json_loc_permutation.values.end(), min_loc_permutation.begin(), min_loc_permutation.end());
json_result.values["loc_permutation"] = json_loc_permutation;
json_result.values["distance"] = min_route.shortest_path_length;
SimpleLogger().Write() << "BF GEOM DISTANCE " << min_route.shortest_path_length;
json_result.values["runtime"] = TIMER_MSEC(tsp);
} else {
json_result.values["distance"] = -1;
json_result.values["runtime"] = -1;
}
// return geometry result to json
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
descriptor->SetConfig(route_parameters);
descriptor->Run(min_route, json_result);
return 200;
}
};
#endif // ROUND_TRIP_BF_HPP

152
plugins/round_trip_FI.hpp Normal file
View File

@ -0,0 +1,152 @@
/*
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 ROUND_TRIP_FI_HPP
#define ROUND_TRIP_FI_HPP
#include "plugin_base.hpp"
#include "../algorithms/object_encoder.hpp"
#include "../routing_algorithms/tsp_nearest_neighbour.hpp"
#include "../routing_algorithms/tsp_farthest_insertion.hpp"
#include "../routing_algorithms/tsp_brute_force.hpp"
#include "../data_structures/query_edge.hpp"
#include "../data_structures/search_engine.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../descriptors/json_descriptor.hpp"
#include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp"
#include "../util/string_util.hpp"
#include "../util/timing_util.hpp"
#include "../util/simple_logger.hpp"
#include <osrm/json_container.hpp>
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <unordered_map>
#include <string>
#include <vector>
#include <limits>
template <class DataFacadeT> class RoundTripPluginFI final : public BasePlugin
{
private:
std::string descriptor_string;
DataFacadeT *facade;
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
public:
explicit RoundTripPluginFI(DataFacadeT *facade)
: descriptor_string("tripFI"), facade(facade)
{
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
}
const std::string GetDescriptor() const override final { return descriptor_string; }
int HandleRequest(const RouteParameters &route_parameters,
osrm::json::Object &json_result) override final
{
TIMER_START(tsp_pre);
// check if all inputs are coordinates
if (!check_all_coordinates(route_parameters.coordinates))
{
return 400;
}
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
// find phantom nodes for all input coords
PhantomNodeArray phantom_node_vector(route_parameters.coordinates.size());
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
{
// if client hints are helpful, encode hints
if (checksum_OK && i < route_parameters.hints.size() &&
!route_parameters.hints[i].empty())
{
PhantomNode current_phantom_node;
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
{
phantom_node_vector[i].emplace_back(std::move(current_phantom_node));
continue;
}
}
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());
}
BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes()));
}
// 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)
{
return 400;
}
// compute TSP round trip
InternalRouteResult min_route;
std::vector<int> min_loc_permutation(phantom_node_vector.size(), -1);
TIMER_STOP(tsp_pre);
//######################## FARTHEST INSERTION ###############################//
TIMER_START(tsp);
osrm::tsp::FarthestInsertionTSP(phantom_node_vector, *result_table, min_route, min_loc_permutation);
search_engine_ptr->shortest_path(min_route.segment_end_coordinates, route_parameters.uturns, min_route);
TIMER_STOP(tsp);
BOOST_ASSERT(min_route.segment_end_coordinates.size() == route_parameters.coordinates.size());
osrm::json::Array json_loc_permutation;
json_loc_permutation.values.insert(json_loc_permutation.values.end(), min_loc_permutation.begin(), min_loc_permutation.end());
json_result.values["loc_permutation"] = json_loc_permutation;
json_result.values["distance"] = min_route.shortest_path_length;
SimpleLogger().Write() << "FI GEOM DISTANCE " << min_route.shortest_path_length;
json_result.values["runtime"] = TIMER_MSEC(tsp);
// return geometry result to json
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
descriptor->SetConfig(route_parameters);
descriptor->Run(min_route, json_result);
return 200;
}
};
#endif // ROUND_TRIP_FI_HPP

150
plugins/round_trip_NN.hpp Normal file
View File

@ -0,0 +1,150 @@
/*
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 ROUND_TRIP_NN_HPP
#define ROUND_TRIP_NN_HPP
#include "plugin_base.hpp"
#include "../algorithms/object_encoder.hpp"
#include "../routing_algorithms/tsp_nearest_neighbour.hpp"
#include "../routing_algorithms/tsp_farthest_insertion.hpp"
#include "../routing_algorithms/tsp_brute_force.hpp"
#include "../data_structures/query_edge.hpp"
#include "../data_structures/search_engine.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../descriptors/json_descriptor.hpp"
#include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp"
#include "../util/string_util.hpp"
#include "../util/timing_util.hpp"
#include "../util/simple_logger.hpp"
#include <osrm/json_container.hpp>
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <unordered_map>
#include <string>
#include <vector>
#include <limits>
template <class DataFacadeT> class RoundTripPluginNN final : public BasePlugin
{
private:
std::string descriptor_string;
DataFacadeT *facade;
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
public:
explicit RoundTripPluginNN(DataFacadeT *facade)
: descriptor_string("tripNN"), facade(facade)
{
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
}
const std::string GetDescriptor() const override final { return descriptor_string; }
int HandleRequest(const RouteParameters &route_parameters,
osrm::json::Object &json_result) override final
{
TIMER_START(tsp_pre);
// check if all inputs are coordinates
if (!check_all_coordinates(route_parameters.coordinates))
{
return 400;
}
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
// find phantom nodes for all input coords
PhantomNodeArray phantom_node_vector(route_parameters.coordinates.size());
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
{
// if client hints are helpful, encode hints
if (checksum_OK && i < route_parameters.hints.size() &&
!route_parameters.hints[i].empty())
{
PhantomNode current_phantom_node;
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
{
phantom_node_vector[i].emplace_back(std::move(current_phantom_node));
continue;
}
}
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());
}
BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes()));
}
// 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)
{
return 400;
}
// compute TSP round trip
InternalRouteResult min_route;
std::vector<int> min_loc_permutation(phantom_node_vector.size(), -1);
TIMER_STOP(tsp_pre);
//######################### NEAREST NEIGHBOUR ###############################//
TIMER_START(tsp);
osrm::tsp::NearestNeighbourTSP(phantom_node_vector, *result_table, min_route, min_loc_permutation);
search_engine_ptr->shortest_path(min_route.segment_end_coordinates, route_parameters.uturns, min_route);
TIMER_STOP(tsp);
BOOST_ASSERT(min_route.segment_end_coordinates.size() == route_parameters.coordinates.size());
osrm::json::Array json_loc_permutation;
json_loc_permutation.values.insert(json_loc_permutation.values.end(), min_loc_permutation.begin(), min_loc_permutation.end());
json_result.values["loc_permutation"] = json_loc_permutation;
json_result.values["distance"] = min_route.shortest_path_length;
json_result.values["runtime"] = TIMER_MSEC(tsp);
// return geometry result to json
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
descriptor->SetConfig(route_parameters);
descriptor->Run(min_route, json_result);
return 200;
}
};
#endif // ROUND_TRIP_NN_HPP

View File

@ -40,47 +40,66 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <vector>
#include <limits>
#include <iostream>
#include "../util/simple_logger.hpp"
// HAHAHA. NICE TRY, CHAU.
namespace osrm
{
namespace tsp
{
void BruteForce(const RouteParameters & route_parameters,
const PhantomNodeArray & phantom_node_vector,
const std::vector<EdgeWeight> & dist_table,
InternalRouteResult & min_route,
std::vector<int> & min_loc_permutation) {
int ReturnDistance(const std::vector<EdgeWeight> & dist_table, const std::vector<int> location_order, const int min_route_dist, const int number_of_locations) {
int i = 0;
int route_dist = 0;
// compute length and stop if length is longer than route already found
while (i < number_of_locations - 1 && route_dist < min_route_dist) {
//get distance from location i to location i+1
route_dist += *(dist_table.begin() + (location_order[i] * number_of_locations) + location_order[i+1]);
++i;
}
//get distance from last location to first location
route_dist += *(dist_table.begin() + (location_order[number_of_locations-1] * number_of_locations) + location_order[0]);
if (route_dist < min_route_dist) {
return route_dist;
}
else {
return -1;
}
}
void BruteForceTSP(const PhantomNodeArray & phantom_node_vector,
const std::vector<EdgeWeight> & dist_table,
InternalRouteResult & min_route,
std::vector<int> & min_loc_permutation) {
const auto number_of_locations = phantom_node_vector.size();
// fill a vector with node ids
std::vector<int> location_ids(number_of_locations);
std::iota(location_ids.begin(), location_ids.end(), 0);
int min_route_dist = std::numeric_limits<int>::max();
do {
int route_dist = 0;
for (int i = 0; i < number_of_locations - 1; ++i) {
route_dist += *(dist_table.begin() + (location_ids[i] * number_of_locations) + location_ids[i+1]);
}
route_dist += *(dist_table.begin() + (location_ids[number_of_locations-1] * number_of_locations) + location_ids[0]);
if (route_dist < min_route_dist) {
min_route_dist = route_dist;
// check length of all possible permutation of the location ids
do {
int new_distance = ReturnDistance(dist_table, location_ids, min_route_dist, number_of_locations);
if (new_distance != -1) {
min_route_dist = new_distance;
//TODO: this gets copied right? fix this
min_loc_permutation = location_ids;
}
} while(std::next_permutation(location_ids.begin(), location_ids.end()));
PhantomNodes viapoint;
for (int i = 0; i < number_of_locations - 1; ++i) {
viapoint = PhantomNodes{phantom_node_vector[i][0], phantom_node_vector[i + 1][0]};
viapoint = PhantomNodes{phantom_node_vector[min_loc_permutation[i]][0], phantom_node_vector[min_loc_permutation[i + 1]][0]};
min_route.segment_end_coordinates.emplace_back(viapoint);
}
viapoint = PhantomNodes{phantom_node_vector[number_of_locations - 1][0], phantom_node_vector[0][0]};
viapoint = PhantomNodes{phantom_node_vector[min_loc_permutation[number_of_locations - 1]][0], phantom_node_vector[min_loc_permutation[0]][0]};
min_route.segment_end_coordinates.emplace_back(viapoint);
}

View File

@ -47,11 +47,10 @@ namespace osrm
namespace tsp
{
void FarthestInsertion(const RouteParameters & route_parameters,
const PhantomNodeArray & phantom_node_vector,
const std::vector<EdgeWeight> & dist_table,
InternalRouteResult & min_route,
std::vector<int> & min_loc_permutation) {
void FarthestInsertionTSP(const PhantomNodeArray & phantom_node_vector,
const std::vector<EdgeWeight> & dist_table,
InternalRouteResult & min_route,
std::vector<int> & min_loc_permutation) {
//////////////////////////////////////////////////////////////////////////////////////////////////
// START FARTHEST INSERTION HERE
// 1. start at a random round trip of 2 locations
@ -67,6 +66,8 @@ void FarthestInsertion(const RouteParameters & route_parameters,
// tracks which nodes have been already visited
std::vector<bool> visited(number_of_locations, false);
// PrintDistTable(dist_table, 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()));

View File

@ -48,11 +48,10 @@ namespace osrm
namespace tsp
{
void NearestNeighbour(const RouteParameters & route_parameters,
const PhantomNodeArray & phantom_node_vector,
const std::vector<EdgeWeight> & dist_table,
InternalRouteResult & min_route,
std::vector<int> & min_loc_permutation) {
void NearestNeighbourTSP(const PhantomNodeArray & phantom_node_vector,
const std::vector<EdgeWeight> & dist_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

103
tools/tsp_logs.hpp Normal file
View File

@ -0,0 +1,103 @@
/*
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 TSP_LOGS_HPP
#define TSP_LOGS_HPP
#include "../data_structures/search_engine.hpp"
#include "../util/string_util.hpp"
#include <osrm/json_container.hpp>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <vector>
#include <limits>
#include <iostream>
#include "../util/simple_logger.hpp"
namespace osrm
{
namespace tsp
{
inline void PrintDistTable(const std::vector<EdgeWeight> & dist_table, const int number_of_locations) {
int j = 0;
for (auto i = dist_table.begin(); i != dist_table.end(); ++i){
if (j % number_of_locations == 0) {
std::cout << std::endl;
}
std::cout << std::setw(6) << *i << " ";
++j;
}
std::cout << std::endl;
}
bool CheckSymmetricTable(const std::vector<EdgeWeight> & dist_table, const int number_of_locations) {
bool is_quadratic = true;
for (int i = 0; i < number_of_locations; ++i) {
for(int j = 0; j < number_of_locations; ++j) {
int a = *(dist_table.begin() + (i * number_of_locations) + j);
int b = *(dist_table.begin() + (j * number_of_locations) + i);
if (a !=b) {
is_quadratic = false;
}
}
}
return is_quadratic;
}
void LogRoute(std::vector<int> location_ids){
SimpleLogger().Write() << "LOC ORDER";
for (auto x : location_ids) {
SimpleLogger().Write() << x;
}
}
int ReturnDistanceFI(const std::vector<EdgeWeight> & dist_table, std::list<int> current_trip, const int number_of_locations) {
int route_dist = 0;
// compute length and stop if length is longer than route already found
for (auto i = current_trip.begin(); i != std::prev(current_trip.end()); ++i) {
//get distance from location i to location i+1
route_dist += *(dist_table.begin() + (*i * number_of_locations) + *std::next(i));
}
//get distance from last location to first location
route_dist += *(dist_table.begin() + (*std::prev(current_trip.end()) * number_of_locations) + current_trip.front());
return route_dist;
}
}
}
#endif // TSP_LOGS_HPP

View File

@ -0,0 +1,45 @@
/*
Copyright (c) 2014, 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.
*/
#include "../../routing_algorithms/tsp_brute_force.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/list.hpp>
#include <osrm/coordinate.hpp>
#include <iostream>
BOOST_AUTO_TEST_SUITE(tsp)
// BOOST_AUTO_TEST_CASE(check_distance_computation)
// {
// BOOST_CHECK_EQUAL(true, true);
// }
BOOST_AUTO_TEST_SUITE_END()