Skip to content

Commit

Permalink
Merge branch 'enhancement/bypass-matrix-for-plan'
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoupey committed Nov 8, 2024
2 parents 60decd5 + 612b1ba commit 8df975f
Show file tree
Hide file tree
Showing 18 changed files with 361 additions and 98 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#### Internals

- Bypass matrix request in `plan` mode (#444)
- Refactor `Matrix` template class (#1089)
- Refactor to use `std::format` whenever possible (#1081)
- Reduce complexity for recreation process (#1155)
Expand Down
7 changes: 5 additions & 2 deletions src/algorithms/validation/check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ All rights reserved (see LICENSE).
#include <algorithm>
#include <mutex>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>

Expand All @@ -22,7 +21,10 @@ All rights reserved (see LICENSE).

namespace vroom::validation {

Solution check_and_set_ETA(const Input& input, unsigned nb_thread) {
Solution
check_and_set_ETA(const Input& input,
unsigned nb_thread,
std::unordered_map<Index, Index>& route_rank_to_v_rank) {
// Keep track of assigned job ranks.
std::unordered_set<Index> assigned_ranks;

Expand Down Expand Up @@ -51,6 +53,7 @@ Solution check_and_set_ETA(const Input& input, unsigned nb_thread) {

thread_ranks[actual_route_rank % nb_buckets].push_back(v);
v_rank_to_actual_route_rank.insert({v, actual_route_rank});
route_rank_to_v_rank.insert({actual_route_rank, v});
++actual_route_rank;
}

Expand Down
7 changes: 6 additions & 1 deletion src/algorithms/validation/check.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ All rights reserved (see LICENSE).
*/

#include <unordered_map>

#include "structures/vroom/input/input.h"
#include "structures/vroom/solution/solution.h"

namespace vroom::validation {

Solution check_and_set_ETA(const Input& input, unsigned nb_thread);
Solution
check_and_set_ETA(const Input& input,
unsigned nb_thread,
std::unordered_map<Index, Index>& route_rank_to_v_rank);

} // namespace vroom::validation

Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/validation/choose_ETA.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ All rights reserved (see LICENSE).
*/

#include "structures/vroom/input/input.h"
#include "structures/vroom/solution/solution.h"
#include "structures/vroom/solution/route.h"

namespace vroom::validation {

Expand Down
38 changes: 32 additions & 6 deletions src/routing/http_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,11 @@ void HttpWrapper::parse_response(rapidjson::Document& json_result,
}

Matrices HttpWrapper::get_matrices(const std::vector<Location>& locs) const {
std::string query = this->build_query(locs, _matrix_service);
std::string json_string = this->run_query(query);
const std::string query = this->build_query(locs, _matrix_service);
const std::string json_string = this->run_query(query);

// Expected matrix size.
std::size_t m_size = locs.size();
const std::size_t m_size = locs.size();

rapidjson::Document json_result;
this->parse_response(json_result, json_string);
Expand Down Expand Up @@ -200,6 +200,32 @@ Matrices HttpWrapper::get_matrices(const std::vector<Location>& locs) const {
return m;
}

void HttpWrapper::update_sparse_matrix(const std::vector<Location>& route_locs,
Matrices& m,
std::mutex& matrix_m,
std::string& vehicle_geometry) const {
const std::string query = this->build_query(route_locs, _route_service);

const std::string json_string = this->run_query(query);

rapidjson::Document json_result;
parse_response(json_result, json_string);
this->check_response(json_result, route_locs, _route_service);

const auto& legs = get_legs(json_result);
assert(legs.Size() == route_locs.size() - 1);

for (rapidjson::SizeType i = 0; i < legs.Size(); ++i) {
std::scoped_lock<std::mutex> lock(matrix_m);
m.durations[route_locs[i].index()][route_locs[i + 1].index()] =
get_leg_duration(legs[i]);
m.distances[route_locs[i].index()][route_locs[i + 1].index()] =
get_leg_distance(legs[i]);
}

vehicle_geometry = get_geometry(json_result);
};

void HttpWrapper::add_geometry(Route& route) const {
// Ordering locations for the given steps, excluding
// breaks.
Expand All @@ -214,17 +240,17 @@ void HttpWrapper::add_geometry(Route& route) const {
}
assert(!non_break_locations.empty());

std::string query = build_query(non_break_locations, _route_service);
const std::string query = build_query(non_break_locations, _route_service);

std::string json_string = this->run_query(query);
const std::string json_string = this->run_query(query);

rapidjson::Document json_result;
parse_response(json_result, json_string);
this->check_response(json_result,
non_break_locations, // not supposed to be used
_route_service);

assert(get_legs_number(json_result) == non_break_locations.size() - 1);
assert(get_legs(json_result).Size() == non_break_locations.size() - 1);

route.geometry = get_geometry(json_result);
}
Expand Down
20 changes: 19 additions & 1 deletion src/routing/http_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ class HttpWrapper : public Wrapper {

Matrices get_matrices(const std::vector<Location>& locs) const override;

void update_sparse_matrix(const std::vector<Location>& route_locs,
Matrices& m,
std::mutex& matrix_m,
std::string& vehicles_geometry) const override;

virtual bool
duration_value_is_null(const rapidjson::Value& matrix_entry) const {
// Same implementation for both OSRM and ORS.
Expand All @@ -79,7 +84,20 @@ class HttpWrapper : public Wrapper {
return utils::round<UserDistance>(matrix_entry.GetDouble());
}

virtual unsigned get_legs_number(const rapidjson::Value& result) const = 0;
virtual const rapidjson::Value&
get_legs(const rapidjson::Value& result) const = 0;

virtual UserDuration get_leg_duration(const rapidjson::Value& leg) const {
// Same implementation for both OSRM and ORS.
assert(leg.HasMember("duration"));
return utils::round<UserDuration>(leg["duration"].GetDouble());
}

virtual UserDistance get_leg_distance(const rapidjson::Value& leg) const {
// Same implementation for both OSRM and ORS.
assert(leg.HasMember("distance"));
return utils::round<UserDistance>(leg["distance"].GetDouble());
}

virtual std::string get_geometry(rapidjson::Value& result) const {
// Same implementation for both OSRM and ORS.
Expand Down
131 changes: 87 additions & 44 deletions src/routing/libosrm_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,35 @@ LibosrmWrapper::LibosrmWrapper(const std::string& profile)
: Wrapper(profile), _config(get_config(profile)), _osrm(_config) {
}

void throw_error(osrm::json::Object& result,
const std::vector<Location>& locs) {
const std::string code =
result.values["code"].get<osrm::json::String>().value;
const std::string message =
result.values["message"].get<osrm::json::String>().value;

const std::string snapping_error_base =
"Could not find a matching segment for coordinate ";
if (code == "NoSegment" && message.starts_with(snapping_error_base)) {
auto error_loc =
std::stoul(message.substr(snapping_error_base.size(),
message.size() - snapping_error_base.size()));
auto coordinates =
std::format("[{},{}]", locs[error_loc].lon(), locs[error_loc].lat());
throw RoutingException("Could not find route near location " + coordinates);
}

// Other error in response.
throw RoutingException("libOSRM: " + code + ": " + message);
}

Matrices LibosrmWrapper::get_matrices(const std::vector<Location>& locs) const {
osrm::TableParameters params;
params.annotations = osrm::engine::api::TableParameters::AnnotationsType::All;

params.coordinates.reserve(locs.size());
params.radiuses.reserve(locs.size());
for (auto const& location : locs) {
assert(location.has_coordinates());
params.coordinates
.emplace_back(osrm::util::FloatLongitude({location.lon()}),
osrm::util::FloatLatitude({location.lat()}));
Expand All @@ -53,25 +74,7 @@ Matrices LibosrmWrapper::get_matrices(const std::vector<Location>& locs) const {
osrm::Status status = _osrm.Table(params, result);

if (status == osrm::Status::Error) {
const std::string code =
result.values["code"].get<osrm::json::String>().value;
const std::string message =
result.values["message"].get<osrm::json::String>().value;

const std::string snapping_error_base =
"Could not find a matching segment for coordinate ";
if (code == "NoSegment" && message.starts_with(snapping_error_base)) {
auto error_loc =
std::stoul(message.substr(snapping_error_base.size(),
message.size() - snapping_error_base.size()));
auto coordinates = "[" + std::to_string(locs[error_loc].lon()) + "," +
std::to_string(locs[error_loc].lat()) + "]";
throw RoutingException("Could not find route near location " +
coordinates);
}

// Other error in response.
throw RoutingException("libOSRM: " + code + ": " + message);
throw_error(result, locs);
}

const auto& durations = result.values["durations"].get<osrm::json::Array>();
Expand Down Expand Up @@ -120,40 +123,80 @@ Matrices LibosrmWrapper::get_matrices(const std::vector<Location>& locs) const {
return m;
}

void LibosrmWrapper::add_geometry(Route& route) const {
// Default options for routing.
osrm::RouteParameters params(false, // steps
false, // alternatives
false, // annotations
osrm::RouteParameters::GeometriesType::Polyline,
osrm::RouteParameters::OverviewType::Full,
false // continue_straight
);
params.coordinates.reserve(route.steps.size());
osrm::json::Object LibosrmWrapper::get_route_with_coordinates(
const std::vector<Location>& locs) const {
std::vector<osrm::util::Coordinate> coords;
coords.reserve(locs.size());

// Ordering locations for the given steps, excluding
// breaks.
for (auto& step : route.steps) {
if (step.step_type != STEP_TYPE::BREAK) {
assert(step.location.has_value());
const auto& loc = step.location.value();
assert(loc.has_coordinates());
params.coordinates.emplace_back(osrm::util::FloatLongitude({loc.lon()}),
osrm::util::FloatLatitude({loc.lat()}));
}
for (const auto& loc : locs) {
coords.emplace_back(osrm::util::FloatLongitude({loc.lon()}),
osrm::util::FloatLatitude({loc.lat()}));
}

// Default options for routing.
osrm::RouteParameters
params(false, // steps
false, // alternatives
osrm::RouteParameters::GeometriesType::Polyline,
osrm::RouteParameters::OverviewType::Full,
false, // continue_straight,
std::move(coords),
std::vector<boost::optional<osrm::engine::Hint>>(),
std::vector<
boost::optional<double>>(coords.size(),
DEFAULT_LIBOSRM_SNAPPING_RADIUS));

osrm::json::Object result;
osrm::Status status = _osrm.Route(params, result);

if (status == osrm::Status::Error) {
throw RoutingException(
result.values["code"].get<osrm::json::String>().value + ": " +
result.values["message"].get<osrm::json::String>().value);
throw_error(result, locs);
}

auto& result_routes = result.values["routes"].get<osrm::json::Array>();
auto& json_route = result_routes.values.at(0).get<osrm::json::Object>();
return std::move(result_routes.values.at(0).get<osrm::json::Object>());
}

void LibosrmWrapper::update_sparse_matrix(
const std::vector<Location>& route_locs,
Matrices& m,
std::mutex& matrix_m,
std::string& vehicle_geometry) const {
auto json_route = get_route_with_coordinates(route_locs);

auto& legs = json_route.values["legs"].get<osrm::json::Array>();
assert(legs.values.size() == route_locs.size() - 1);

for (std::size_t i = 0; i < legs.values.size(); ++i) {
auto& leg = legs.values.at(i).get<osrm::json::Object>();

std::scoped_lock<std::mutex> lock(matrix_m);
m.durations[route_locs[i].index()][route_locs[i + 1].index()] =
utils::round<UserDuration>(
leg.values["duration"].get<osrm::json::Number>().value);
m.distances[route_locs[i].index()][route_locs[i + 1].index()] =
utils::round<UserDistance>(
leg.values["distance"].get<osrm::json::Number>().value);
}

vehicle_geometry =
std::move(json_route.values["geometry"].get<osrm::json::String>().value);
};

void LibosrmWrapper::add_geometry(Route& route) const {
std::vector<Location> locs;
locs.reserve(route.steps.size());

// Ordering locations for the given steps, excluding
// breaks.
for (const auto& step : route.steps) {
if (step.step_type != STEP_TYPE::BREAK) {
assert(step.location.has_value());
locs.emplace_back(step.location.value());
}
}

auto json_route = get_route_with_coordinates(locs);

// Total distance and route geometry.
route.geometry =
Expand Down
8 changes: 8 additions & 0 deletions src/routing/libosrm_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,21 @@ class LibosrmWrapper : public Wrapper {
osrm::EngineConfig _config;
const osrm::OSRM _osrm;

osrm::json::Object
get_route_with_coordinates(const std::vector<Location>& locs) const;

static osrm::EngineConfig get_config(const std::string& profile);

public:
explicit LibosrmWrapper(const std::string& profile);

Matrices get_matrices(const std::vector<Location>& locs) const override;

void update_sparse_matrix(const std::vector<Location>& route_locs,
Matrices& m,
std::mutex& matrix_m,
std::string& vehicle_geometry) const override;

void add_geometry(Route& route) const override;
};

Expand Down
10 changes: 8 additions & 2 deletions src/routing/ors_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,14 @@ void OrsWrapper::check_response(const rapidjson::Document& json_result,
}
}

unsigned OrsWrapper::get_legs_number(const rapidjson::Value& result) const {
return result["routes"][0]["segments"].Size();
const rapidjson::Value&
OrsWrapper::get_legs(const rapidjson::Value& result) const {
assert(result.HasMember("routes") && result["routes"].IsArray() &&
!result["routes"].Empty() &&
result["routes"][0].HasMember("segments") &&
result["routes"][0]["segments"].IsArray());

return result["routes"][0]["segments"];
}

} // namespace vroom::routing
3 changes: 2 additions & 1 deletion src/routing/ors_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class OrsWrapper : public HttpWrapper {
const std::vector<Location>& locs,
const std::string& service) const override;

unsigned get_legs_number(const rapidjson::Value& result) const override;
const rapidjson::Value&
get_legs(const rapidjson::Value& result) const override;

public:
OrsWrapper(const std::string& profile, const Server& server);
Expand Down
Loading

0 comments on commit 8df975f

Please sign in to comment.