From 3bcaf47fa707eba960d35c9344a8264bf844e1af Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 12 Jul 2024 09:26:20 +0200 Subject: [PATCH 01/30] Move Matrices struct to dedicated header. --- src/routing/wrapper.h | 8 +------- src/structures/vroom/matrices.h | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 src/structures/vroom/matrices.h diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index e7585f404..d949d7d00 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -14,18 +14,12 @@ All rights reserved (see LICENSE). #include "structures/generic/matrix.h" #include "structures/vroom/location.h" +#include "structures/vroom/matrices.h" #include "structures/vroom/solution/route.h" #include "utils/exception.h" namespace vroom::routing { -struct Matrices { - Matrix durations; - Matrix distances; - - explicit Matrices(std::size_t n) : durations(n), distances(n){}; -}; - class Wrapper { public: diff --git a/src/structures/vroom/matrices.h b/src/structures/vroom/matrices.h new file mode 100644 index 000000000..4a9d2a7a1 --- /dev/null +++ b/src/structures/vroom/matrices.h @@ -0,0 +1,23 @@ +#ifndef MATRICES_H +#define MATRICES_H + +/* + +This file is part of VROOM. + +Copyright (c) 2015-2024, Julien Coupey. +All rights reserved (see LICENSE). + +*/ + +namespace vroom::routing { + +struct Matrices { + Matrix durations; + Matrix distances; + + explicit Matrices(std::size_t n) : durations(n), distances(n){}; +}; + +} // namespace vroom::routing +#endif From 1629aeb39b69d33f4b7d3c97fb12eda319b94e7f Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 12 Jul 2024 09:29:06 +0200 Subject: [PATCH 02/30] Refactor to pass a sparse filling flag. --- src/structures/vroom/input/input.cpp | 33 ++++++++++++++++------------ src/structures/vroom/input/input.h | 7 +++++- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index b51627321..3d5255253 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -896,7 +896,18 @@ void Input::init_missing_matrices(const std::string& profile) { } } -void Input::set_matrices(unsigned nb_thread) { +routing::Matrices Input::get_matrices_by_profile(const std::string& profile, + bool sparse_filling) { + auto rw = std::ranges::find_if(_routing_wrappers, [&](const auto& wr) { + return wr->profile == profile; + }); + assert(rw != _routing_wrappers.end()); + + return sparse_filling ? (*rw)->get_matrices(_locations) + : (*rw)->get_matrices(_locations); +} + +void Input::set_matrices(unsigned nb_thread, bool sparse_filling) { if ((!_durations_matrices.empty() || !_distances_matrices.empty() || !_costs_matrices.empty()) && !_has_custom_location_index) { @@ -942,14 +953,15 @@ void Input::set_matrices(unsigned nb_thread) { std::mutex ep_m; std::mutex cost_bound_m; - auto run_on_profiles = [&](const std::vector& profiles) { + auto run_on_profiles = [&](const std::vector& profiles, + bool sparse_filling) { try { for (const auto& profile : profiles) { auto durations_m = _durations_matrices.find(profile); auto distances_m = _distances_matrices.find(profile); // Required matrices not manually set have been defined as - // empty above. + // empty above in init_missing_matrices. assert(durations_m != _durations_matrices.end()); assert(distances_m != _distances_matrices.end()); const bool define_durations = (durations_m->second.size() == 0); @@ -961,15 +973,10 @@ void Input::set_matrices(unsigned nb_thread) { durations_m->second = Matrix(1); distances_m->second = Matrix(1); } else { - auto rw = - std::ranges::find_if(_routing_wrappers, [&](const auto& wr) { - return wr->profile == profile; - }); - assert(rw != _routing_wrappers.end()); + auto matrices = get_matrices_by_profile(profile, sparse_filling); if (!_has_custom_location_index) { // Location indices are set based on order in _locations. - auto matrices = (*rw)->get_matrices(_locations); if (define_durations) { durations_m->second = std::move(matrices.durations); } @@ -979,8 +986,6 @@ void Input::set_matrices(unsigned nb_thread) { } else { // Location indices are provided in input so we need an // indirection based on order in _locations. - auto matrices = (*rw)->get_matrices(_locations); - if (define_durations) { Matrix full_m(_max_matrices_used_index + 1); for (Index i = 0; i < _locations.size(); ++i) { @@ -1061,7 +1066,7 @@ void Input::set_matrices(unsigned nb_thread) { matrix_threads.reserve(thread_profiles.size()); for (const auto& profiles : thread_profiles) { - matrix_threads.emplace_back(run_on_profiles, profiles); + matrix_threads.emplace_back(run_on_profiles, profiles, sparse_filling); } for (auto& t : matrix_threads) { @@ -1174,8 +1179,8 @@ Solution Input::check(unsigned nb_thread) { set_vehicle_steps_ranks(); - // TODO we don't need the whole matrix here. - set_matrices(nb_thread); + constexpr bool sparse_filling = true; + set_matrices(nb_thread, sparse_filling); set_vehicles_costs(); // Fill basic skills compatibility matrix. diff --git a/src/structures/vroom/input/input.h b/src/structures/vroom/input/input.h index 287dacc7d..23e9d285a 100644 --- a/src/structures/vroom/input/input.h +++ b/src/structures/vroom/input/input.h @@ -17,6 +17,7 @@ All rights reserved (see LICENSE). #include "routing/wrapper.h" #include "structures/generic/matrix.h" #include "structures/typedefs.h" +#include "structures/vroom/matrices.h" #include "structures/vroom/solution/solution.h" #include "structures/vroom/vehicle.h" @@ -97,7 +98,11 @@ class Input { void set_jobs_vehicles_evals(); void set_vehicle_steps_ranks(); void init_missing_matrices(const std::string& profile); - void set_matrices(unsigned nb_thread); + + routing::Matrices get_matrices_by_profile(const std::string& profile, + bool sparse_filling); + + void set_matrices(unsigned nb_thread, bool sparse_filling = false); void add_routing_wrapper(const std::string& profile); From 8b8c987b32564cd097fd9a8080741cd425f69a8b Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 12 Jul 2024 16:11:32 +0200 Subject: [PATCH 03/30] Compute route infos in HttpWrapper context. --- src/routing/http_wrapper.h | 3 +++ src/routing/ors_wrapper.h | 6 ++++++ src/routing/osrm_routed_wrapper.h | 3 +++ src/routing/valhalla_wrapper.h | 6 ++++++ 4 files changed, 18 insertions(+) diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index cdbd80989..6869290ed 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -68,6 +68,9 @@ class HttpWrapper : public Wrapper { virtual unsigned get_legs_number(const rapidjson::Value& result) const = 0; + virtual std::pair, std::vector> + get_legs_info(const rapidjson::Value& result) const = 0; + virtual std::string get_geometry(rapidjson::Value& result) const = 0; void add_geometry(Route& route) const override; diff --git a/src/routing/ors_wrapper.h b/src/routing/ors_wrapper.h index a08e5e50d..d1e7f798f 100644 --- a/src/routing/ors_wrapper.h +++ b/src/routing/ors_wrapper.h @@ -37,6 +37,12 @@ class OrsWrapper : public HttpWrapper { unsigned get_legs_number(const rapidjson::Value& result) const override; + std::pair, std::vector> + get_legs_info(const rapidjson::Value& result) const override { + // TODO implement + return std::pair, std::vector>(); + } + std::string get_geometry(rapidjson::Value& result) const override; public: diff --git a/src/routing/osrm_routed_wrapper.h b/src/routing/osrm_routed_wrapper.h index e2dea1e3f..09149c102 100644 --- a/src/routing/osrm_routed_wrapper.h +++ b/src/routing/osrm_routed_wrapper.h @@ -37,6 +37,9 @@ class OsrmRoutedWrapper : public HttpWrapper { unsigned get_legs_number(const rapidjson::Value& result) const override; + std::pair, std::vector> + get_legs_info(const rapidjson::Value& result) const override; + std::string get_geometry(rapidjson::Value& result) const override; public: diff --git a/src/routing/valhalla_wrapper.h b/src/routing/valhalla_wrapper.h index a3be2b502..236ed4602 100644 --- a/src/routing/valhalla_wrapper.h +++ b/src/routing/valhalla_wrapper.h @@ -41,6 +41,12 @@ class ValhallaWrapper : public HttpWrapper { unsigned get_legs_number(const rapidjson::Value& result) const override; + std::pair, std::vector> + get_legs_info(const rapidjson::Value& result) const override { + // TODO implement + return std::pair, std::vector>(); + } + std::string get_geometry(rapidjson::Value& result) const override; public: From 0594c7c0bfd65604a3a6589710e3df30c5f0b02f Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 12 Jul 2024 16:12:20 +0200 Subject: [PATCH 04/30] Implement get_legs_info for osrm-routed wrapper. --- src/routing/osrm_routed_wrapper.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/routing/osrm_routed_wrapper.cpp b/src/routing/osrm_routed_wrapper.cpp index 7d93833ec..781eb50a5 100644 --- a/src/routing/osrm_routed_wrapper.cpp +++ b/src/routing/osrm_routed_wrapper.cpp @@ -113,6 +113,29 @@ OsrmRoutedWrapper::get_legs_number(const rapidjson::Value& result) const { return result["routes"][0]["legs"].Size(); } +std::pair, std::vector> +OsrmRoutedWrapper::get_legs_info(const rapidjson::Value& result) const { + assert(result.HasMember("routes") and result["routes"].IsArray() and + !result["routes"].Empty() and result["routes"][0].HasMember("legs") and + result["routes"][0]["legs"].IsArray()); + const auto& legs = result["routes"][0]["legs"]; + + std::vector durations; + durations.reserve(legs.Size()); + std::vector distances; + distances.reserve(legs.Size()); + + for (rapidjson::SizeType i = 0; i < legs.Size(); ++i) { + assert(legs[i].HasMember("duration")); + durations.push_back( + utils::round(legs[i]["duration"].GetDouble())); + distances.push_back( + utils::round(legs[i]["distance"].GetDouble())); + } + + return std::make_pair(std::move(durations), std::move(distances)); +} + std::string OsrmRoutedWrapper::get_geometry(rapidjson::Value& result) const { return result["routes"][0]["geometry"].GetString(); } From 20c5af048c94efa7d384943e2211fb626ead7032 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 12 Jul 2024 16:14:21 +0200 Subject: [PATCH 05/30] First sketch of HttpWrapper::get_sparse_matrices. --- src/routing/http_wrapper.cpp | 71 ++++++++++++++++++++++++++++ src/routing/http_wrapper.h | 5 ++ src/routing/libosrm_wrapper.h | 4 ++ src/routing/wrapper.h | 6 +++ src/structures/vroom/input/input.cpp | 5 +- 5 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 63847232b..89d430065 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -201,6 +201,77 @@ Matrices HttpWrapper::get_matrices(const std::vector& locs) const { return m; } +Matrices HttpWrapper::get_sparse_matrices(const std::string& profile, + const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs) const { + std::size_t m_size = locs.size(); + Matrices m(m_size); + + for (const auto& v : vehicles) { + if (v.profile != profile) { + continue; + } + + std::vector route_locs; + route_locs.reserve(v.steps.size()); + + bool has_job_steps = false; + for (const auto& step : v.steps) { + switch (step.type) { + using enum STEP_TYPE; + case START: + if (v.has_start()) { + route_locs.push_back(v.start.value()); + } + break; + case END: + if (v.has_end()) { + route_locs.push_back(v.end.value()); + } + break; + case BREAK: + break; + case JOB: + has_job_steps = true; + route_locs.push_back(jobs[step.rank].location); + break; + } + } + + if (!has_job_steps) { + // No steps provided in input for vehicle, or only breaks in + // steps. + continue; + } + assert(route_locs.size() >= 2); + + // TODO run route queries in parallel. + std::string query = build_query(route_locs, _route_service); + + 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 [durations, distances] = get_legs_info(json_result); + assert(durations.size() == route_locs.size() - 1); + assert(durations.size() == distances.size()); + + for (std::size_t i = 0; i < durations.size(); ++i) { + m.durations[route_locs[i].index()][route_locs[i + 1].index()] = + durations[i]; + m.distances[route_locs[i].index()][route_locs[i + 1].index()] = + distances[i]; + } + + // TODO get geometry and store it. + } + + return m; +} + void HttpWrapper::add_geometry(Route& route) const { // Ordering locations for the given steps, excluding // breaks. diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index 6869290ed..3ee0f04ee 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -54,6 +54,11 @@ class HttpWrapper : public Wrapper { Matrices get_matrices(const std::vector& locs) const override; + Matrices get_sparse_matrices(const std::string& profile, + const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs) const override; + virtual bool duration_value_is_null(const rapidjson::Value& matrix_entry) const = 0; diff --git a/src/routing/libosrm_wrapper.h b/src/routing/libosrm_wrapper.h index f931444d4..3192fdacc 100644 --- a/src/routing/libosrm_wrapper.h +++ b/src/routing/libosrm_wrapper.h @@ -31,6 +31,10 @@ class LibosrmWrapper : public Wrapper { Matrices get_matrices(const std::vector& locs) const override; + Matrices get_sparse_matrices(const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs) const override; + void add_geometry(Route& route) const override; }; diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index d949d7d00..69f5e8beb 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -16,6 +16,7 @@ All rights reserved (see LICENSE). #include "structures/vroom/location.h" #include "structures/vroom/matrices.h" #include "structures/vroom/solution/route.h" +#include "structures/vroom/vehicle.h" #include "utils/exception.h" namespace vroom::routing { @@ -27,6 +28,11 @@ class Wrapper { virtual Matrices get_matrices(const std::vector& locs) const = 0; + virtual Matrices get_sparse_matrices(const std::string& profile, + const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs) const = 0; + virtual void add_geometry(Route& route) const = 0; virtual ~Wrapper() = default; diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index 3d5255253..c44ca4def 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -903,7 +903,10 @@ routing::Matrices Input::get_matrices_by_profile(const std::string& profile, }); assert(rw != _routing_wrappers.end()); - return sparse_filling ? (*rw)->get_matrices(_locations) + return sparse_filling ? (*rw)->get_sparse_matrices(profile, + _locations, + this->vehicles, + this->jobs) : (*rw)->get_matrices(_locations); } From e2a02cf4a5065e0d8184703cade68ecd6a4c9595 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Mon, 15 Jul 2024 10:51:50 +0200 Subject: [PATCH 06/30] Add dummy implementation for LibosrmWrapper. --- src/routing/libosrm_wrapper.cpp | 13 +++++++++++++ src/routing/libosrm_wrapper.h | 5 +++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index 541f0082a..b422887e2 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -120,6 +120,19 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { return m; } +Matrices +LibosrmWrapper::get_sparse_matrices(const std::string& profile, + const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs) const { + std::size_t m_size = locs.size(); + Matrices m(m_size); + + // TODO implement + + return m; +} + void LibosrmWrapper::add_geometry(Route& route) const { // Default options for routing. osrm::RouteParameters params(false, // steps diff --git a/src/routing/libosrm_wrapper.h b/src/routing/libosrm_wrapper.h index 3192fdacc..85627d2ef 100644 --- a/src/routing/libosrm_wrapper.h +++ b/src/routing/libosrm_wrapper.h @@ -31,9 +31,10 @@ class LibosrmWrapper : public Wrapper { Matrices get_matrices(const std::vector& locs) const override; - Matrices get_sparse_matrices(const std::vector& locs, + Matrices get_sparse_matrices(const std::string& profile, + const std::vector& locs, const std::vector& vehicles, - const std::vector& jobs) const override; + const std::vector& jobs) const override; void add_geometry(Route& route) const override; }; From dc631cb4ea28b80faf85a9345b218e446c065dfd Mon Sep 17 00:00:00 2001 From: jcoupey Date: Mon, 15 Jul 2024 14:49:14 +0200 Subject: [PATCH 07/30] Expose route legs and leg info getter from http wrappers. --- src/routing/http_wrapper.cpp | 2 +- src/routing/http_wrapper.h | 8 +++--- src/routing/ors_wrapper.cpp | 20 +++++++++++++-- src/routing/ors_wrapper.h | 11 ++++---- src/routing/osrm_routed_wrapper.cpp | 39 ++++++++++++----------------- src/routing/osrm_routed_wrapper.h | 8 +++--- src/routing/valhalla_wrapper.cpp | 22 +++++++++++++--- src/routing/valhalla_wrapper.h | 11 ++++---- 8 files changed, 74 insertions(+), 47 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 89d430065..6c634acde 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -296,7 +296,7 @@ void HttpWrapper::add_geometry(Route& route) const { 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); } diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index 3ee0f04ee..f4d7feb20 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -71,10 +71,12 @@ class HttpWrapper : public Wrapper { virtual UserDistance get_distance_value(const rapidjson::Value& matrix_entry) const = 0; - virtual unsigned get_legs_number(const rapidjson::Value& result) const = 0; + virtual const rapidjson::Value& + get_legs(const rapidjson::Value& result) const = 0; - virtual std::pair, std::vector> - get_legs_info(const rapidjson::Value& result) const = 0; + virtual UserDuration get_leg_duration(const rapidjson::Value& leg) const = 0; + + virtual UserDistance get_leg_distance(const rapidjson::Value& leg) const = 0; virtual std::string get_geometry(rapidjson::Value& result) const = 0; diff --git a/src/routing/ors_wrapper.cpp b/src/routing/ors_wrapper.cpp index 56f1ac193..98fc91963 100644 --- a/src/routing/ors_wrapper.cpp +++ b/src/routing/ors_wrapper.cpp @@ -90,8 +90,24 @@ OrsWrapper::get_distance_value(const rapidjson::Value& matrix_entry) const { return utils::round(matrix_entry.GetDouble()); } -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"]; +} + +UserDuration OrsWrapper::get_leg_duration(const rapidjson::Value& leg) const { + assert(leg.HasMember("duration")); + return utils::round(leg["duration"].GetDouble()); +} + +UserDistance OrsWrapper::get_leg_distance(const rapidjson::Value& leg) const { + assert(leg.HasMember("distance")); + return utils::round(leg["distance"].GetDouble()); } std::string OrsWrapper::get_geometry(rapidjson::Value& result) const { diff --git a/src/routing/ors_wrapper.h b/src/routing/ors_wrapper.h index d1e7f798f..e3e8447b5 100644 --- a/src/routing/ors_wrapper.h +++ b/src/routing/ors_wrapper.h @@ -35,13 +35,12 @@ class OrsWrapper : public HttpWrapper { UserDistance get_distance_value(const rapidjson::Value& matrix_entry) const override; - unsigned get_legs_number(const rapidjson::Value& result) const override; + const rapidjson::Value& + get_legs(const rapidjson::Value& result) const override; - std::pair, std::vector> - get_legs_info(const rapidjson::Value& result) const override { - // TODO implement - return std::pair, std::vector>(); - } + UserDuration get_leg_duration(const rapidjson::Value& leg) const override; + + UserDistance get_leg_distance(const rapidjson::Value& leg) const override; std::string get_geometry(rapidjson::Value& result) const override; diff --git a/src/routing/osrm_routed_wrapper.cpp b/src/routing/osrm_routed_wrapper.cpp index 781eb50a5..78bfaba0b 100644 --- a/src/routing/osrm_routed_wrapper.cpp +++ b/src/routing/osrm_routed_wrapper.cpp @@ -108,32 +108,25 @@ UserDistance OsrmRoutedWrapper::get_distance_value( return utils::round(matrix_entry.GetDouble()); } -unsigned -OsrmRoutedWrapper::get_legs_number(const rapidjson::Value& result) const { - return result["routes"][0]["legs"].Size(); +const rapidjson::Value& +OsrmRoutedWrapper::get_legs(const rapidjson::Value& result) const { + assert(result.HasMember("routes") && result["routes"].IsArray() && + !result["routes"].Empty() && result["routes"][0].HasMember("legs") && + result["routes"][0]["legs"].IsArray()); + + return result["routes"][0]["legs"]; } -std::pair, std::vector> -OsrmRoutedWrapper::get_legs_info(const rapidjson::Value& result) const { - assert(result.HasMember("routes") and result["routes"].IsArray() and - !result["routes"].Empty() and result["routes"][0].HasMember("legs") and - result["routes"][0]["legs"].IsArray()); - const auto& legs = result["routes"][0]["legs"]; - - std::vector durations; - durations.reserve(legs.Size()); - std::vector distances; - distances.reserve(legs.Size()); - - for (rapidjson::SizeType i = 0; i < legs.Size(); ++i) { - assert(legs[i].HasMember("duration")); - durations.push_back( - utils::round(legs[i]["duration"].GetDouble())); - distances.push_back( - utils::round(legs[i]["distance"].GetDouble())); - } +UserDuration +OsrmRoutedWrapper::get_leg_duration(const rapidjson::Value& leg) const { + assert(leg.HasMember("duration")); + return utils::round(leg["duration"].GetDouble()); +} - return std::make_pair(std::move(durations), std::move(distances)); +UserDistance +OsrmRoutedWrapper::get_leg_distance(const rapidjson::Value& leg) const { + assert(leg.HasMember("distance")); + return utils::round(leg["distance"].GetDouble()); } std::string OsrmRoutedWrapper::get_geometry(rapidjson::Value& result) const { diff --git a/src/routing/osrm_routed_wrapper.h b/src/routing/osrm_routed_wrapper.h index 09149c102..e08c531a1 100644 --- a/src/routing/osrm_routed_wrapper.h +++ b/src/routing/osrm_routed_wrapper.h @@ -35,10 +35,12 @@ class OsrmRoutedWrapper : public HttpWrapper { UserDistance get_distance_value(const rapidjson::Value& matrix_entry) const override; - unsigned get_legs_number(const rapidjson::Value& result) const override; + const rapidjson::Value& + get_legs(const rapidjson::Value& result) const override; - std::pair, std::vector> - get_legs_info(const rapidjson::Value& result) const override; + UserDuration get_leg_duration(const rapidjson::Value& leg) const override; + + UserDistance get_leg_distance(const rapidjson::Value& leg) const override; std::string get_geometry(rapidjson::Value& result) const override; diff --git a/src/routing/valhalla_wrapper.cpp b/src/routing/valhalla_wrapper.cpp index 3f225bde7..787236132 100644 --- a/src/routing/valhalla_wrapper.cpp +++ b/src/routing/valhalla_wrapper.cpp @@ -146,9 +146,25 @@ UserDistance ValhallaWrapper::get_distance_value( matrix_entry["distance"].GetDouble()); } -unsigned -ValhallaWrapper::get_legs_number(const rapidjson::Value& result) const { - return result["trip"]["legs"].Size(); +const rapidjson::Value& +ValhallaWrapper::get_legs(const rapidjson::Value& result) const { + assert(result.HasMember("trip") && result["trip"].HasMember("legs") and + result["trip"]["legs"].IsArray()); + + return result["trip"]["legs"]; +} + +UserDuration +ValhallaWrapper::get_leg_duration(const rapidjson::Value& leg) const { + assert(leg.HasMember("summary") && leg["summary"].HasMember("time")); + return utils::round(leg["summary"]["time"].GetDouble()); +} + +UserDistance +ValhallaWrapper::get_leg_distance(const rapidjson::Value& leg) const { + assert(leg.HasMember("summary") && leg["summary"].HasMember("length")); + return utils::round(km_to_m * + leg["summary"]["length"].GetDouble()); } std::string ValhallaWrapper::get_geometry(rapidjson::Value& result) const { diff --git a/src/routing/valhalla_wrapper.h b/src/routing/valhalla_wrapper.h index 236ed4602..e14b60861 100644 --- a/src/routing/valhalla_wrapper.h +++ b/src/routing/valhalla_wrapper.h @@ -39,13 +39,12 @@ class ValhallaWrapper : public HttpWrapper { UserDistance get_distance_value(const rapidjson::Value& matrix_entry) const override; - unsigned get_legs_number(const rapidjson::Value& result) const override; + const rapidjson::Value& + get_legs(const rapidjson::Value& result) const override; - std::pair, std::vector> - get_legs_info(const rapidjson::Value& result) const override { - // TODO implement - return std::pair, std::vector>(); - } + UserDuration get_leg_duration(const rapidjson::Value& leg) const override; + + UserDistance get_leg_distance(const rapidjson::Value& leg) const override; std::string get_geometry(rapidjson::Value& result) const override; From 84db49b2cef3658e1774f82fa9ae0c3b91896ad8 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Mon, 15 Jul 2024 14:51:29 +0200 Subject: [PATCH 08/30] Move legs costs logic to HttpWrapper parent class. --- src/routing/http_wrapper.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 6c634acde..9f438a4b3 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -255,15 +255,14 @@ Matrices HttpWrapper::get_sparse_matrices(const std::string& profile, parse_response(json_result, json_string); this->check_response(json_result, route_locs, _route_service); - const auto [durations, distances] = get_legs_info(json_result); - assert(durations.size() == route_locs.size() - 1); - assert(durations.size() == distances.size()); + const auto& legs = get_legs(json_result); + assert(legs.Size() == route_locs.size() - 1); - for (std::size_t i = 0; i < durations.size(); ++i) { + for (rapidjson::SizeType i = 0; i < legs.Size(); ++i) { m.durations[route_locs[i].index()][route_locs[i + 1].index()] = - durations[i]; + get_leg_duration(legs[i]); m.distances[route_locs[i].index()][route_locs[i + 1].index()] = - distances[i]; + get_leg_distance(legs[i]); } // TODO get geometry and store it. From 5de1727e4c6b92d9fbf14d48cb4c8611906ef169 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Mon, 15 Jul 2024 15:32:10 +0200 Subject: [PATCH 09/30] Avoid variable shadowing. --- src/structures/vroom/input/input.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index c44ca4def..e040c0da4 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -956,8 +956,7 @@ void Input::set_matrices(unsigned nb_thread, bool sparse_filling) { std::mutex ep_m; std::mutex cost_bound_m; - auto run_on_profiles = [&](const std::vector& profiles, - bool sparse_filling) { + auto run_on_profiles = [&](const std::vector& profiles) { try { for (const auto& profile : profiles) { auto durations_m = _durations_matrices.find(profile); @@ -1069,7 +1068,7 @@ void Input::set_matrices(unsigned nb_thread, bool sparse_filling) { matrix_threads.reserve(thread_profiles.size()); for (const auto& profiles : thread_profiles) { - matrix_threads.emplace_back(run_on_profiles, profiles, sparse_filling); + matrix_threads.emplace_back(run_on_profiles, profiles); } for (auto& t : matrix_threads) { From bc797b4a9fbabff0ea92a8f0b4960c33074b26ad Mon Sep 17 00:00:00 2001 From: jcoupey Date: Mon, 15 Jul 2024 15:52:55 +0200 Subject: [PATCH 10/30] Store and re-use route geometries in plan mode. --- src/routing/http_wrapper.cpp | 12 +++++++----- src/routing/http_wrapper.h | 10 ++++++---- src/routing/libosrm_wrapper.cpp | 11 ++++++----- src/routing/libosrm_wrapper.h | 10 ++++++---- src/routing/wrapper.h | 10 ++++++---- src/structures/vroom/input/input.cpp | 14 ++++---------- src/structures/vroom/input/input.h | 4 ++++ 7 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 9f438a4b3..1f1f26c2a 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -201,10 +201,12 @@ Matrices HttpWrapper::get_matrices(const std::vector& locs) const { return m; } -Matrices HttpWrapper::get_sparse_matrices(const std::string& profile, - const std::vector& locs, - const std::vector& vehicles, - const std::vector& jobs) const { +Matrices HttpWrapper::get_sparse_matrices( + const std::string& profile, + const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs, + std::unordered_map& v_id_to_geom) const { std::size_t m_size = locs.size(); Matrices m(m_size); @@ -265,7 +267,7 @@ Matrices HttpWrapper::get_sparse_matrices(const std::string& profile, get_leg_distance(legs[i]); } - // TODO get geometry and store it. + v_id_to_geom.insert(std::make_pair(v.id, get_geometry(json_result))); } return m; diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index f4d7feb20..1abcb6438 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -54,10 +54,12 @@ class HttpWrapper : public Wrapper { Matrices get_matrices(const std::vector& locs) const override; - Matrices get_sparse_matrices(const std::string& profile, - const std::vector& locs, - const std::vector& vehicles, - const std::vector& jobs) const override; + Matrices get_sparse_matrices( + const std::string& profile, + const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs, + std::unordered_map& v_id_to_geom) const override; virtual bool duration_value_is_null(const rapidjson::Value& matrix_entry) const = 0; diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index b422887e2..4cb1884e5 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -120,11 +120,12 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { return m; } -Matrices -LibosrmWrapper::get_sparse_matrices(const std::string& profile, - const std::vector& locs, - const std::vector& vehicles, - const std::vector& jobs) const { +Matrices LibosrmWrapper::get_sparse_matrices( + const std::string& profile, + const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs, + std::unordered_map& v_id_to_geom) const { std::size_t m_size = locs.size(); Matrices m(m_size); diff --git a/src/routing/libosrm_wrapper.h b/src/routing/libosrm_wrapper.h index 85627d2ef..fa4f3272a 100644 --- a/src/routing/libosrm_wrapper.h +++ b/src/routing/libosrm_wrapper.h @@ -31,10 +31,12 @@ class LibosrmWrapper : public Wrapper { Matrices get_matrices(const std::vector& locs) const override; - Matrices get_sparse_matrices(const std::string& profile, - const std::vector& locs, - const std::vector& vehicles, - const std::vector& jobs) const override; + Matrices get_sparse_matrices( + const std::string& profile, + const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs, + std::unordered_map& v_id_to_geom) const override; void add_geometry(Route& route) const override; }; diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index 69f5e8beb..da32f2109 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -28,10 +28,12 @@ class Wrapper { virtual Matrices get_matrices(const std::vector& locs) const = 0; - virtual Matrices get_sparse_matrices(const std::string& profile, - const std::vector& locs, - const std::vector& vehicles, - const std::vector& jobs) const = 0; + virtual Matrices get_sparse_matrices( + const std::string& profile, + const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs, + std::unordered_map& v_id_to_geom) const = 0; virtual void add_geometry(Route& route) const = 0; diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index e040c0da4..36501ce13 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -906,7 +906,8 @@ routing::Matrices Input::get_matrices_by_profile(const std::string& profile, return sparse_filling ? (*rw)->get_sparse_matrices(profile, _locations, this->vehicles, - this->jobs) + this->jobs, + _vehicle_id_to_geometry) : (*rw)->get_matrices(_locations); } @@ -1208,15 +1209,8 @@ Solution Input::check(unsigned nb_thread) { if (_geometry) { for (auto& route : sol.routes) { - const auto& profile = route.profile; - auto rw = std::ranges::find_if(_routing_wrappers, [&](const auto& wr) { - return wr->profile == profile; - }); - if (rw == _routing_wrappers.end()) { - throw InputException( - "Route geometry request with non-routable profile " + profile + "."); - } - (*rw)->add_geometry(route); + assert(_vehicle_id_to_geometry.contains(route.vehicle)); + route.geometry = std::move(_vehicle_id_to_geometry.at(route.vehicle)); } _end_routing = std::chrono::high_resolution_clock::now(); diff --git a/src/structures/vroom/input/input.h b/src/structures/vroom/input/input.h index 23e9d285a..e60404ef4 100644 --- a/src/structures/vroom/input/input.h +++ b/src/structures/vroom/input/input.h @@ -78,6 +78,10 @@ class Input { bool _all_locations_have_coords{true}; std::vector> _jobs_vehicles_evals; + // Used in plan mode since we store route geometries while + // generating sparse matrices. + std::unordered_map _vehicle_id_to_geometry; + unsigned _amount_size{0}; Amount _zero{0}; From e767ba4ab64abbf4d7df7444fe6888e1f6f85caf Mon Sep 17 00:00:00 2001 From: jcoupey Date: Mon, 15 Jul 2024 17:26:50 +0200 Subject: [PATCH 11/30] Use try_emplace to store geometries. --- src/routing/http_wrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 1f1f26c2a..ec2283211 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -267,7 +267,7 @@ Matrices HttpWrapper::get_sparse_matrices( get_leg_distance(legs[i]); } - v_id_to_geom.insert(std::make_pair(v.id, get_geometry(json_result))); + v_id_to_geom.try_emplace(v.id, get_geometry(json_result)); } return m; From 03489ec6725c80696870b7990ee79b10636e03d1 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Tue, 16 Jul 2024 10:26:22 +0200 Subject: [PATCH 12/30] Run route requests in parallel across vehicles. --- src/routing/http_wrapper.cpp | 121 +++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 48 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index ec2283211..3a9006365 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -7,6 +7,7 @@ All rights reserved (see LICENSE). */ +#include #include #include @@ -210,64 +211,88 @@ Matrices HttpWrapper::get_sparse_matrices( std::size_t m_size = locs.size(); Matrices m(m_size); - for (const auto& v : vehicles) { - if (v.profile != profile) { - continue; - } - - std::vector route_locs; - route_locs.reserve(v.steps.size()); - - bool has_job_steps = false; - for (const auto& step : v.steps) { - switch (step.type) { - using enum STEP_TYPE; - case START: - if (v.has_start()) { - route_locs.push_back(v.start.value()); - } - break; - case END: - if (v.has_end()) { - route_locs.push_back(v.end.value()); + std::exception_ptr ep = nullptr; + std::mutex ep_m; + std::mutex id_to_geom_m; + std::mutex matrix_m; + + auto run_on_vehicle = [&](const Vehicle& v) { + try { + std::vector route_locs; + route_locs.reserve(v.steps.size()); + + bool has_job_steps = false; + for (const auto& step : v.steps) { + switch (step.type) { + using enum STEP_TYPE; + case START: + if (v.has_start()) { + route_locs.push_back(v.start.value()); + } + break; + case END: + if (v.has_end()) { + route_locs.push_back(v.end.value()); + } + break; + case BREAK: + break; + case JOB: + has_job_steps = true; + route_locs.push_back(jobs[step.rank].location); + break; } - break; - case BREAK: - break; - case JOB: - has_job_steps = true; - route_locs.push_back(jobs[step.rank].location); - break; } - } - if (!has_job_steps) { - // No steps provided in input for vehicle, or only breaks in - // steps. - continue; - } - assert(route_locs.size() >= 2); + if (!has_job_steps) { + // No steps provided in input for vehicle, or only breaks in + // steps. + return; + } + assert(route_locs.size() >= 2); + + std::string query = build_query(route_locs, _route_service); + + std::string json_string = this->run_query(query); - // TODO run route queries in parallel. - std::string query = build_query(route_locs, _route_service); + rapidjson::Document json_result; + parse_response(json_result, json_string); + this->check_response(json_result, route_locs, _route_service); - std::string json_string = this->run_query(query); + 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 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]); + } - rapidjson::Document json_result; - parse_response(json_result, json_string); - this->check_response(json_result, route_locs, _route_service); + std::scoped_lock lock(id_to_geom_m); + v_id_to_geom.try_emplace(v.id, get_geometry(json_result)); + } catch (...) { + std::scoped_lock lock(ep_m); + ep = std::current_exception(); + } + }; - const auto& legs = get_legs(json_result); - assert(legs.Size() == route_locs.size() - 1); + std::vector vehicles_threads; + vehicles_threads.reserve(vehicles.size()); - for (rapidjson::SizeType i = 0; i < legs.Size(); ++i) { - 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]); + for (const auto& v : vehicles) { + if (v.profile == profile) { + vehicles_threads.emplace_back(run_on_vehicle, v); } + } + + for (auto& t : vehicles_threads) { + t.join(); + } - v_id_to_geom.try_emplace(v.id, get_geometry(json_result)); + if (ep != nullptr) { + std::rethrow_exception(ep); } return m; From 389ca15f0629e7f5bdb635c8ff5bf2aacaa6f44b Mon Sep 17 00:00:00 2001 From: jcoupey Date: Tue, 16 Jul 2024 15:49:23 +0200 Subject: [PATCH 13/30] Explicitely capture variables required in run_on_vehicle lambda. --- src/routing/http_wrapper.cpp | 106 ++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 3a9006365..b6fc2e2ac 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -216,67 +216,69 @@ Matrices HttpWrapper::get_sparse_matrices( std::mutex id_to_geom_m; std::mutex matrix_m; - auto run_on_vehicle = [&](const Vehicle& v) { - try { - std::vector route_locs; - route_locs.reserve(v.steps.size()); - - bool has_job_steps = false; - for (const auto& step : v.steps) { - switch (step.type) { - using enum STEP_TYPE; - case START: - if (v.has_start()) { - route_locs.push_back(v.start.value()); + auto run_on_vehicle = + [this, &jobs, &matrix_m, &m, &id_to_geom_m, &v_id_to_geom, &ep_m, &ep]( + const Vehicle& v) { + try { + std::vector route_locs; + route_locs.reserve(v.steps.size()); + + bool has_job_steps = false; + for (const auto& step : v.steps) { + switch (step.type) { + using enum STEP_TYPE; + case START: + if (v.has_start()) { + route_locs.push_back(v.start.value()); + } + break; + case END: + if (v.has_end()) { + route_locs.push_back(v.end.value()); + } + break; + case BREAK: + break; + case JOB: + has_job_steps = true; + route_locs.push_back(jobs[step.rank].location); + break; } - break; - case END: - if (v.has_end()) { - route_locs.push_back(v.end.value()); - } - break; - case BREAK: - break; - case JOB: - has_job_steps = true; - route_locs.push_back(jobs[step.rank].location); - break; } - } - if (!has_job_steps) { - // No steps provided in input for vehicle, or only breaks in - // steps. - return; - } - assert(route_locs.size() >= 2); + if (!has_job_steps) { + // No steps provided in input for vehicle, or only breaks in + // steps. + return; + } + assert(route_locs.size() >= 2); - std::string query = build_query(route_locs, _route_service); + std::string query = this->build_query(route_locs, _route_service); - std::string json_string = this->run_query(query); + 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); + 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); + 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 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]); - } + for (rapidjson::SizeType i = 0; i < legs.Size(); ++i) { + std::scoped_lock 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]); + } - std::scoped_lock lock(id_to_geom_m); - v_id_to_geom.try_emplace(v.id, get_geometry(json_result)); - } catch (...) { - std::scoped_lock lock(ep_m); - ep = std::current_exception(); - } - }; + std::scoped_lock lock(id_to_geom_m); + v_id_to_geom.try_emplace(v.id, get_geometry(json_result)); + } catch (...) { + std::scoped_lock lock(ep_m); + ep = std::current_exception(); + } + }; std::vector vehicles_threads; vehicles_threads.reserve(vehicles.size()); From 7c4a203f6da76b2e4ce98c9c9309ff0fbf8880e5 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Tue, 16 Jul 2024 16:24:21 +0200 Subject: [PATCH 14/30] Move HttpWrapper::get_sparse_matrices implementation to parent Wrapper class. --- src/routing/http_wrapper.cpp | 115 +++++++------------------------- src/routing/http_wrapper.h | 12 ++-- src/routing/libosrm_wrapper.cpp | 14 ---- src/routing/libosrm_wrapper.h | 14 ++-- src/routing/wrapper.h | 100 +++++++++++++++++++++++++-- 5 files changed, 131 insertions(+), 124 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index b6fc2e2ac..073667086 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -7,7 +7,6 @@ All rights reserved (see LICENSE). */ -#include #include #include @@ -202,103 +201,35 @@ Matrices HttpWrapper::get_matrices(const std::vector& locs) const { return m; } -Matrices HttpWrapper::get_sparse_matrices( - const std::string& profile, - const std::vector& locs, - const std::vector& vehicles, - const std::vector& jobs, - std::unordered_map& v_id_to_geom) const { - std::size_t m_size = locs.size(); - Matrices m(m_size); - - std::exception_ptr ep = nullptr; - std::mutex ep_m; - std::mutex id_to_geom_m; - std::mutex matrix_m; - - auto run_on_vehicle = - [this, &jobs, &matrix_m, &m, &id_to_geom_m, &v_id_to_geom, &ep_m, &ep]( - const Vehicle& v) { - try { - std::vector route_locs; - route_locs.reserve(v.steps.size()); - - bool has_job_steps = false; - for (const auto& step : v.steps) { - switch (step.type) { - using enum STEP_TYPE; - case START: - if (v.has_start()) { - route_locs.push_back(v.start.value()); - } - break; - case END: - if (v.has_end()) { - route_locs.push_back(v.end.value()); - } - break; - case BREAK: - break; - case JOB: - has_job_steps = true; - route_locs.push_back(jobs[step.rank].location); - break; - } - } - - if (!has_job_steps) { - // No steps provided in input for vehicle, or only breaks in - // steps. - return; - } - assert(route_locs.size() >= 2); - - std::string query = this->build_query(route_locs, _route_service); - - 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 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]); - } - - std::scoped_lock lock(id_to_geom_m); - v_id_to_geom.try_emplace(v.id, get_geometry(json_result)); - } catch (...) { - std::scoped_lock lock(ep_m); - ep = std::current_exception(); - } - }; +void HttpWrapper::update_sparse_matrix( + const Id v_id, + const std::vector& route_locs, + Matrices& m, + std::mutex& matrix_m, + std::unordered_map& v_id_to_geom, + std::mutex& id_to_geom_m) const { + std::string query = this->build_query(route_locs, _route_service); - std::vector vehicles_threads; - vehicles_threads.reserve(vehicles.size()); + std::string json_string = this->run_query(query); - for (const auto& v : vehicles) { - if (v.profile == profile) { - vehicles_threads.emplace_back(run_on_vehicle, v); - } - } + rapidjson::Document json_result; + parse_response(json_result, json_string); + this->check_response(json_result, route_locs, _route_service); - for (auto& t : vehicles_threads) { - t.join(); - } + const auto& legs = get_legs(json_result); + assert(legs.Size() == route_locs.size() - 1); - if (ep != nullptr) { - std::rethrow_exception(ep); + for (rapidjson::SizeType i = 0; i < legs.Size(); ++i) { + std::scoped_lock 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]); } - return m; -} + std::scoped_lock lock(id_to_geom_m); + v_id_to_geom.try_emplace(v_id, get_geometry(json_result)); +}; void HttpWrapper::add_geometry(Route& route) const { // Ordering locations for the given steps, excluding diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index 1abcb6438..b3c168332 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -54,12 +54,12 @@ class HttpWrapper : public Wrapper { Matrices get_matrices(const std::vector& locs) const override; - Matrices get_sparse_matrices( - const std::string& profile, - const std::vector& locs, - const std::vector& vehicles, - const std::vector& jobs, - std::unordered_map& v_id_to_geom) const override; + void update_sparse_matrix(const Id v_id, + const std::vector& route_locs, + Matrices& m, + std::mutex& matrix_m, + std::unordered_map& v_id_to_geom, + std::mutex& id_to_geom_m) const override; virtual bool duration_value_is_null(const rapidjson::Value& matrix_entry) const = 0; diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index 4cb1884e5..541f0082a 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -120,20 +120,6 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { return m; } -Matrices LibosrmWrapper::get_sparse_matrices( - const std::string& profile, - const std::vector& locs, - const std::vector& vehicles, - const std::vector& jobs, - std::unordered_map& v_id_to_geom) const { - std::size_t m_size = locs.size(); - Matrices m(m_size); - - // TODO implement - - return m; -} - void LibosrmWrapper::add_geometry(Route& route) const { // Default options for routing. osrm::RouteParameters params(false, // steps diff --git a/src/routing/libosrm_wrapper.h b/src/routing/libosrm_wrapper.h index fa4f3272a..42b077fb2 100644 --- a/src/routing/libosrm_wrapper.h +++ b/src/routing/libosrm_wrapper.h @@ -31,12 +31,14 @@ class LibosrmWrapper : public Wrapper { Matrices get_matrices(const std::vector& locs) const override; - Matrices get_sparse_matrices( - const std::string& profile, - const std::vector& locs, - const std::vector& vehicles, - const std::vector& jobs, - std::unordered_map& v_id_to_geom) const override; + void update_sparse_matrix(const Id v_id, + const std::vector& route_locs, + Matrices& m, + std::mutex& matrix_m, + std::unordered_map& v_id_to_geom, + std::mutex& id_to_geom_m) const override { + // TODO implement + } void add_geometry(Route& route) const override; }; diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index da32f2109..2b585a7ee 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -10,6 +10,8 @@ All rights reserved (see LICENSE). */ +#include +#include #include #include "structures/generic/matrix.h" @@ -28,12 +30,98 @@ class Wrapper { virtual Matrices get_matrices(const std::vector& locs) const = 0; - virtual Matrices get_sparse_matrices( - const std::string& profile, - const std::vector& locs, - const std::vector& vehicles, - const std::vector& jobs, - std::unordered_map& v_id_to_geom) const = 0; + Matrices + get_sparse_matrices(const std::string& profile, + const std::vector& locs, + const std::vector& vehicles, + const std::vector& jobs, + std::unordered_map& v_id_to_geom) const { + std::size_t m_size = locs.size(); + Matrices m(m_size); + + std::exception_ptr ep = nullptr; + std::mutex ep_m; + std::mutex id_to_geom_m; + std::mutex matrix_m; + + auto run_on_vehicle = + [this, &jobs, &matrix_m, &m, &id_to_geom_m, &v_id_to_geom, &ep_m, &ep]( + const Vehicle& v) { + try { + std::vector route_locs; + route_locs.reserve(v.steps.size()); + + bool has_job_steps = false; + for (const auto& step : v.steps) { + switch (step.type) { + using enum STEP_TYPE; + case START: + if (v.has_start()) { + route_locs.push_back(v.start.value()); + } + break; + case END: + if (v.has_end()) { + route_locs.push_back(v.end.value()); + } + break; + case BREAK: + break; + case JOB: + has_job_steps = true; + route_locs.push_back(jobs[step.rank].location); + break; + } + } + + if (!has_job_steps) { + // No steps provided in input for vehicle, or only breaks in + // steps. + return; + } + assert(route_locs.size() >= 2); + + this->update_sparse_matrix(v.id, + route_locs, + m, + matrix_m, + v_id_to_geom, + id_to_geom_m); + } catch (...) { + std::scoped_lock lock(ep_m); + ep = std::current_exception(); + } + }; + + std::vector vehicles_threads; + vehicles_threads.reserve(vehicles.size()); + + for (const auto& v : vehicles) { + if (v.profile == profile) { + vehicles_threads.emplace_back(run_on_vehicle, v); + } + } + + for (auto& t : vehicles_threads) { + t.join(); + } + + if (ep != nullptr) { + std::rethrow_exception(ep); + } + + return m; + }; + + // Updates matrix with data from a single route request and returns + // corresponding route geometry. + virtual void + update_sparse_matrix(const Id v_id, + const std::vector& route_locs, + Matrices& m, + std::mutex& matrix_m, + std::unordered_map& v_id_to_geom, + std::mutex& id_to_geom_m) const = 0; virtual void add_geometry(Route& route) const = 0; From 8c9c788d406ae900068bf6ce7b71983719ac4867 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Tue, 16 Jul 2024 16:55:14 +0200 Subject: [PATCH 15/30] Implement LibosrmWrapper::update_sparse_matrix. --- src/routing/libosrm_wrapper.cpp | 58 ++++++++++++++++++++++++++++++++- src/routing/libosrm_wrapper.h | 4 +-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index 541f0082a..70214a56a 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -120,6 +120,62 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { return m; } +void LibosrmWrapper::update_sparse_matrix( + const Id v_id, + const std::vector& route_locs, + Matrices& m, + std::mutex& matrix_m, + std::unordered_map& v_id_to_geom, + std::mutex& id_to_geom_m) 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_locs.size()); + + for (const auto& loc : route_locs) { + assert(loc.has_coordinates()); + params.coordinates.emplace_back(osrm::util::FloatLongitude({loc.lon()}), + osrm::util::FloatLatitude({loc.lat()})); + } + + osrm::json::Object result; + osrm::Status status = _osrm.Route(params, result); + + if (status == osrm::Status::Error) { + throw RoutingException( + result.values["code"].get().value + ": " + + result.values["message"].get().value); + } + + auto& result_routes = result.values["routes"].get(); + auto& json_route = result_routes.values.at(0).get(); + auto& legs = json_route.values["legs"].get(); + 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(); + + std::scoped_lock lock(matrix_m); + m.durations[route_locs[i].index()][route_locs[i + 1].index()] = + utils::round( + leg.values["duration"].get().value); + m.distances[route_locs[i].index()][route_locs[i + 1].index()] = + utils::round( + leg.values["distance"].get().value); + } + + std::scoped_lock lock(id_to_geom_m); + v_id_to_geom.try_emplace(v_id, + std::move(json_route.values["geometry"] + .get() + .value)); +}; + void LibosrmWrapper::add_geometry(Route& route) const { // Default options for routing. osrm::RouteParameters params(false, // steps @@ -133,7 +189,7 @@ void LibosrmWrapper::add_geometry(Route& route) const { // Ordering locations for the given steps, excluding // breaks. - for (auto& step : route.steps) { + for (const auto& step : route.steps) { if (step.step_type != STEP_TYPE::BREAK) { assert(step.location.has_value()); const auto& loc = step.location.value(); diff --git a/src/routing/libosrm_wrapper.h b/src/routing/libosrm_wrapper.h index 42b077fb2..6269e99c5 100644 --- a/src/routing/libosrm_wrapper.h +++ b/src/routing/libosrm_wrapper.h @@ -36,9 +36,7 @@ class LibosrmWrapper : public Wrapper { Matrices& m, std::mutex& matrix_m, std::unordered_map& v_id_to_geom, - std::mutex& id_to_geom_m) const override { - // TODO implement - } + std::mutex& id_to_geom_m) const override; void add_geometry(Route& route) const override; }; From 6cb896d111698238f17844423d767f96ea19ff4a Mon Sep 17 00:00:00 2001 From: jcoupey Date: Tue, 16 Jul 2024 16:57:04 +0200 Subject: [PATCH 16/30] Update changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43755049f..6f68a8c34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ #### Internals +- Bypass matrix request in `plan` mode (#444) - Refactor `Matrix` template class (#1089) #### CI From 1813055741841d4bcea954a6ac3f0bc44070f1e6 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Tue, 16 Jul 2024 18:00:31 +0200 Subject: [PATCH 17/30] No need to pass profile to get_sparse_matrices. --- src/routing/wrapper.h | 5 ++--- src/structures/vroom/input/input.cpp | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index 2b585a7ee..38afa54fe 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -31,8 +31,7 @@ class Wrapper { virtual Matrices get_matrices(const std::vector& locs) const = 0; Matrices - get_sparse_matrices(const std::string& profile, - const std::vector& locs, + get_sparse_matrices(const std::vector& locs, const std::vector& vehicles, const std::vector& jobs, std::unordered_map& v_id_to_geom) const { @@ -97,7 +96,7 @@ class Wrapper { vehicles_threads.reserve(vehicles.size()); for (const auto& v : vehicles) { - if (v.profile == profile) { + if (v.profile == this->profile) { vehicles_threads.emplace_back(run_on_vehicle, v); } } diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index 36501ce13..8157c851c 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -903,8 +903,7 @@ routing::Matrices Input::get_matrices_by_profile(const std::string& profile, }); assert(rw != _routing_wrappers.end()); - return sparse_filling ? (*rw)->get_sparse_matrices(profile, - _locations, + return sparse_filling ? (*rw)->get_sparse_matrices(_locations, this->vehicles, this->jobs, _vehicle_id_to_geometry) From 6452121af006a6603d05c9452c63751908d4cd77 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Wed, 17 Jul 2024 10:13:41 +0200 Subject: [PATCH 18/30] Add LibosrmWrapper::get_route_with_coordinates to remove duplicate code. --- src/routing/libosrm_wrapper.cpp | 66 +++++++++++++++------------------ src/routing/libosrm_wrapper.h | 4 ++ 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index 70214a56a..576376248 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -9,7 +9,6 @@ All rights reserved (see LICENSE). #include -#include "osrm/coordinate.hpp" #include "osrm/json_container.hpp" #include "osrm/route_parameters.hpp" #include "osrm/status.hpp" @@ -120,13 +119,8 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { return m; } -void LibosrmWrapper::update_sparse_matrix( - const Id v_id, - const std::vector& route_locs, - Matrices& m, - std::mutex& matrix_m, - std::unordered_map& v_id_to_geom, - std::mutex& id_to_geom_m) const { +osrm::json::Object LibosrmWrapper::get_route_with_coordinates( + std::vector&& coords) const { // Default options for routing. osrm::RouteParameters params(false, // steps false, // alternatives @@ -135,13 +129,8 @@ void LibosrmWrapper::update_sparse_matrix( osrm::RouteParameters::OverviewType::Full, false // continue_straight ); - params.coordinates.reserve(route_locs.size()); - for (const auto& loc : route_locs) { - assert(loc.has_coordinates()); - params.coordinates.emplace_back(osrm::util::FloatLongitude({loc.lon()}), - osrm::util::FloatLatitude({loc.lat()})); - } + params.coordinates = std::move(coords); osrm::json::Object result; osrm::Status status = _osrm.Route(params, result); @@ -153,7 +142,27 @@ void LibosrmWrapper::update_sparse_matrix( } auto& result_routes = result.values["routes"].get(); - auto& json_route = result_routes.values.at(0).get(); + return std::move(result_routes.values.at(0).get()); +} + +void LibosrmWrapper::update_sparse_matrix( + const Id v_id, + const std::vector& route_locs, + Matrices& m, + std::mutex& matrix_m, + std::unordered_map& v_id_to_geom, + std::mutex& id_to_geom_m) const { + std::vector coords; + coords.reserve(route_locs.size()); + + for (const auto& loc : route_locs) { + assert(loc.has_coordinates()); + coords.emplace_back(osrm::util::FloatLongitude({loc.lon()}), + osrm::util::FloatLatitude({loc.lat()})); + } + + auto json_route = get_route_with_coordinates(std::move(coords)); + auto& legs = json_route.values["legs"].get(); assert(legs.values.size() == route_locs.size() - 1); @@ -177,15 +186,8 @@ void LibosrmWrapper::update_sparse_matrix( }; 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()); + std::vector coords; + coords.reserve(route.steps.size()); // Ordering locations for the given steps, excluding // breaks. @@ -194,22 +196,12 @@ void LibosrmWrapper::add_geometry(Route& route) const { 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()})); + coords.emplace_back(osrm::util::FloatLongitude({loc.lon()}), + osrm::util::FloatLatitude({loc.lat()})); } } - osrm::json::Object result; - osrm::Status status = _osrm.Route(params, result); - - if (status == osrm::Status::Error) { - throw RoutingException( - result.values["code"].get().value + ": " + - result.values["message"].get().value); - } - - auto& result_routes = result.values["routes"].get(); - auto& json_route = result_routes.values.at(0).get(); + auto json_route = get_route_with_coordinates(std::move(coords)); // Total distance and route geometry. route.geometry = diff --git a/src/routing/libosrm_wrapper.h b/src/routing/libosrm_wrapper.h index 6269e99c5..c7e8a32c6 100644 --- a/src/routing/libosrm_wrapper.h +++ b/src/routing/libosrm_wrapper.h @@ -10,6 +10,7 @@ All rights reserved (see LICENSE). */ +#include "osrm/coordinate.hpp" #include "osrm/engine_config.hpp" #include "osrm/osrm.hpp" @@ -24,6 +25,9 @@ class LibosrmWrapper : public Wrapper { osrm::EngineConfig _config; const osrm::OSRM _osrm; + osrm::json::Object get_route_with_coordinates( + std::vector&& coords) const; + static osrm::EngineConfig get_config(const std::string& profile); public: From d919455d995d9c5c71776e12b225e67d56f66b63 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 7 Nov 2024 14:43:43 +0100 Subject: [PATCH 19/30] Provide default implementations for HttpWrapper::get_leg_*. --- src/routing/http_wrapper.h | 12 ++++++++++-- src/routing/ors_wrapper.cpp | 10 ---------- src/routing/ors_wrapper.h | 4 ---- src/routing/osrm_routed_wrapper.cpp | 12 ------------ src/routing/osrm_routed_wrapper.h | 4 ---- 5 files changed, 10 insertions(+), 32 deletions(-) diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index 804dfb327..bb8689267 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -89,9 +89,17 @@ class HttpWrapper : public Wrapper { virtual const rapidjson::Value& get_legs(const rapidjson::Value& result) const = 0; - virtual UserDuration get_leg_duration(const rapidjson::Value& leg) 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(leg["duration"].GetDouble()); + } - virtual UserDistance get_leg_distance(const rapidjson::Value& leg) const = 0; + virtual UserDistance get_leg_distance(const rapidjson::Value& leg) const { + // Same implementation for both OSRM and ORS. + assert(leg.HasMember("distance")); + return utils::round(leg["distance"].GetDouble()); + } virtual std::string get_geometry(rapidjson::Value& result) const { // Same implementation for both OSRM and ORS. diff --git a/src/routing/ors_wrapper.cpp b/src/routing/ors_wrapper.cpp index d9d68ff84..f0ef7b400 100644 --- a/src/routing/ors_wrapper.cpp +++ b/src/routing/ors_wrapper.cpp @@ -93,14 +93,4 @@ OrsWrapper::get_legs(const rapidjson::Value& result) const { return result["routes"][0]["segments"]; } -UserDuration OrsWrapper::get_leg_duration(const rapidjson::Value& leg) const { - assert(leg.HasMember("duration")); - return utils::round(leg["duration"].GetDouble()); -} - -UserDistance OrsWrapper::get_leg_distance(const rapidjson::Value& leg) const { - assert(leg.HasMember("distance")); - return utils::round(leg["distance"].GetDouble()); -} - } // namespace vroom::routing diff --git a/src/routing/ors_wrapper.h b/src/routing/ors_wrapper.h index 06950f46b..c87810ed1 100644 --- a/src/routing/ors_wrapper.h +++ b/src/routing/ors_wrapper.h @@ -26,10 +26,6 @@ class OrsWrapper : public HttpWrapper { const rapidjson::Value& get_legs(const rapidjson::Value& result) const override; - UserDuration get_leg_duration(const rapidjson::Value& leg) const override; - - UserDistance get_leg_distance(const rapidjson::Value& leg) const override; - public: OrsWrapper(const std::string& profile, const Server& server); }; diff --git a/src/routing/osrm_routed_wrapper.cpp b/src/routing/osrm_routed_wrapper.cpp index df2033b81..385515287 100644 --- a/src/routing/osrm_routed_wrapper.cpp +++ b/src/routing/osrm_routed_wrapper.cpp @@ -94,16 +94,4 @@ OsrmRoutedWrapper::get_legs(const rapidjson::Value& result) const { return result["routes"][0]["legs"]; } -UserDuration -OsrmRoutedWrapper::get_leg_duration(const rapidjson::Value& leg) const { - assert(leg.HasMember("duration")); - return utils::round(leg["duration"].GetDouble()); -} - -UserDistance -OsrmRoutedWrapper::get_leg_distance(const rapidjson::Value& leg) const { - assert(leg.HasMember("distance")); - return utils::round(leg["distance"].GetDouble()); -} - } // namespace vroom::routing diff --git a/src/routing/osrm_routed_wrapper.h b/src/routing/osrm_routed_wrapper.h index de85c5ae6..5bb5fe417 100644 --- a/src/routing/osrm_routed_wrapper.h +++ b/src/routing/osrm_routed_wrapper.h @@ -26,10 +26,6 @@ class OsrmRoutedWrapper : public HttpWrapper { const rapidjson::Value& get_legs(const rapidjson::Value& result) const override; - UserDuration get_leg_duration(const rapidjson::Value& leg) const override; - - UserDistance get_leg_distance(const rapidjson::Value& leg) const override; - public: OsrmRoutedWrapper(const std::string& profile, const Server& server); }; From eaa65d5d581816e0380f03c4495bf144cd996b38 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 7 Nov 2024 15:00:25 +0100 Subject: [PATCH 20/30] Update comment. --- src/routing/wrapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index aae496ad7..5997d98aa 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -112,7 +112,7 @@ class Wrapper { return m; }; - // Updates matrix with data from a single route request and returns + // Updates matrices with data from a single route request and stores // corresponding route geometry. virtual void update_sparse_matrix(const Id v_id, From 0f928237aa1c5ca5fc8fa42c9387cea9f2873a68 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 7 Nov 2024 18:08:57 +0100 Subject: [PATCH 21/30] Add missing snapping radius to libosrm route request. --- src/routing/libosrm_wrapper.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index 576376248..f556d666f 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -122,15 +122,17 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { osrm::json::Object LibosrmWrapper::get_route_with_coordinates( std::vector&& coords) 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 = std::move(coords); + osrm::RouteParameters + params(false, // steps + false, // alternatives + osrm::RouteParameters::GeometriesType::Polyline, + osrm::RouteParameters::OverviewType::Full, + false, // continue_straight, + std::move(coords), + std::vector>(), + std::vector< + boost::optional>(coords.size(), + DEFAULT_LIBOSRM_SNAPPING_RADIUS)); osrm::json::Object result; osrm::Status status = _osrm.Route(params, result); From a6e3cc3507cc614b9feea501a8a6f473a934ce5b Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 7 Nov 2024 18:27:57 +0100 Subject: [PATCH 22/30] Improve error throwing in libosrm wrapper. --- src/routing/libosrm_wrapper.cpp | 54 +++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index f556d666f..9394afd09 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -34,6 +34,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& coordinates) { + const std::string code = + result.values["code"].get().value; + const std::string message = + result.values["message"].get().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_str = + "[" + + std::to_string( + static_cast(toFloating(coordinates[error_loc].lon))) + + "," + + std::to_string( + static_cast(toFloating(coordinates[error_loc].lat))) + + "]"; + throw RoutingException("Could not find route near location " + + coordinates_str); + } + + // Other error in response. + throw RoutingException("libOSRM: " + code + ": " + message); +} + Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { osrm::TableParameters params; params.annotations = osrm::engine::api::TableParameters::AnnotationsType::All; @@ -41,7 +70,6 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { 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()})); @@ -52,25 +80,7 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { osrm::Status status = _osrm.Table(params, result); if (status == osrm::Status::Error) { - const std::string code = - result.values["code"].get().value; - const std::string message = - result.values["message"].get().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, params.coordinates); } const auto& durations = result.values["durations"].get(); @@ -138,9 +148,7 @@ osrm::json::Object LibosrmWrapper::get_route_with_coordinates( osrm::Status status = _osrm.Route(params, result); if (status == osrm::Status::Error) { - throw RoutingException( - result.values["code"].get().value + ": " + - result.values["message"].get().value); + throw_error(result, params.coordinates); } auto& result_routes = result.values["routes"].get(); From 92ba7973fdda16f334336df41ab814e010c4d9e8 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 8 Nov 2024 09:40:45 +0100 Subject: [PATCH 23/30] Only generate OSRM coordinates in get_route_with_coordinates. --- src/routing/libosrm_wrapper.cpp | 51 +++++++++++++-------------------- src/routing/libosrm_wrapper.h | 4 +-- 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index 9394afd09..5baff7877 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -35,7 +35,7 @@ LibosrmWrapper::LibosrmWrapper(const std::string& profile) } void throw_error(osrm::json::Object& result, - const std::vector& coordinates) { + const std::vector& locs) { const std::string code = result.values["code"].get().value; const std::string message = @@ -47,16 +47,9 @@ void throw_error(osrm::json::Object& result, auto error_loc = std::stoul(message.substr(snapping_error_base.size(), message.size() - snapping_error_base.size())); - auto coordinates_str = - "[" + - std::to_string( - static_cast(toFloating(coordinates[error_loc].lon))) + - "," + - std::to_string( - static_cast(toFloating(coordinates[error_loc].lat))) + - "]"; - throw RoutingException("Could not find route near location " + - coordinates_str); + 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. @@ -80,7 +73,7 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { osrm::Status status = _osrm.Table(params, result); if (status == osrm::Status::Error) { - throw_error(result, params.coordinates); + throw_error(result, locs); } const auto& durations = result.values["durations"].get(); @@ -130,7 +123,15 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { } osrm::json::Object LibosrmWrapper::get_route_with_coordinates( - std::vector&& coords) const { + const std::vector& locs) const { + std::vector coords; + coords.reserve(locs.size()); + + 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 @@ -148,7 +149,7 @@ osrm::json::Object LibosrmWrapper::get_route_with_coordinates( osrm::Status status = _osrm.Route(params, result); if (status == osrm::Status::Error) { - throw_error(result, params.coordinates); + throw_error(result, locs); } auto& result_routes = result.values["routes"].get(); @@ -162,16 +163,7 @@ void LibosrmWrapper::update_sparse_matrix( std::mutex& matrix_m, std::unordered_map& v_id_to_geom, std::mutex& id_to_geom_m) const { - std::vector coords; - coords.reserve(route_locs.size()); - - for (const auto& loc : route_locs) { - assert(loc.has_coordinates()); - coords.emplace_back(osrm::util::FloatLongitude({loc.lon()}), - osrm::util::FloatLatitude({loc.lat()})); - } - - auto json_route = get_route_with_coordinates(std::move(coords)); + auto json_route = get_route_with_coordinates(route_locs); auto& legs = json_route.values["legs"].get(); assert(legs.values.size() == route_locs.size() - 1); @@ -196,22 +188,19 @@ void LibosrmWrapper::update_sparse_matrix( }; void LibosrmWrapper::add_geometry(Route& route) const { - std::vector coords; - coords.reserve(route.steps.size()); + std::vector 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()); - const auto& loc = step.location.value(); - assert(loc.has_coordinates()); - coords.emplace_back(osrm::util::FloatLongitude({loc.lon()}), - osrm::util::FloatLatitude({loc.lat()})); + locs.emplace_back(step.location.value()); } } - auto json_route = get_route_with_coordinates(std::move(coords)); + auto json_route = get_route_with_coordinates(locs); // Total distance and route geometry. route.geometry = diff --git a/src/routing/libosrm_wrapper.h b/src/routing/libosrm_wrapper.h index c7e8a32c6..d22233411 100644 --- a/src/routing/libosrm_wrapper.h +++ b/src/routing/libosrm_wrapper.h @@ -25,8 +25,8 @@ class LibosrmWrapper : public Wrapper { osrm::EngineConfig _config; const osrm::OSRM _osrm; - osrm::json::Object get_route_with_coordinates( - std::vector&& coords) const; + osrm::json::Object + get_route_with_coordinates(const std::vector& locs) const; static osrm::EngineConfig get_config(const std::string& profile); From e181f35d3681b33f41dad0eb6855d133caa00cdd Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 8 Nov 2024 10:11:20 +0100 Subject: [PATCH 24/30] Consistent formatting on profile error. --- src/structures/vroom/input/input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index 9e7c83121..b371f5892 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -69,7 +69,7 @@ void Input::add_routing_wrapper(const std::string& profile) { try { routing_wrapper = std::make_unique(profile); } catch (const osrm::exception& e) { - throw InputException("Invalid profile: " + profile); + throw InputException("Invalid profile: " + profile + "."); } break; #else From 342d129c180c11e04cbdade3feb33ebce1f2991c Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 8 Nov 2024 11:50:43 +0100 Subject: [PATCH 25/30] Revert include move. --- src/routing/libosrm_wrapper.cpp | 1 + src/routing/libosrm_wrapper.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index 5baff7877..f1261a4fe 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -9,6 +9,7 @@ All rights reserved (see LICENSE). #include +#include "osrm/coordinate.hpp" #include "osrm/json_container.hpp" #include "osrm/route_parameters.hpp" #include "osrm/status.hpp" diff --git a/src/routing/libosrm_wrapper.h b/src/routing/libosrm_wrapper.h index d22233411..c96a40d3e 100644 --- a/src/routing/libosrm_wrapper.h +++ b/src/routing/libosrm_wrapper.h @@ -10,7 +10,6 @@ All rights reserved (see LICENSE). */ -#include "osrm/coordinate.hpp" #include "osrm/engine_config.hpp" #include "osrm/osrm.hpp" From 1a8e6e2cc963c919813b87ad310dc2572e6ede99 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 8 Nov 2024 11:50:57 +0100 Subject: [PATCH 26/30] Add some constness. --- src/routing/http_wrapper.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 1c8889d3d..049d2d15d 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -148,11 +148,11 @@ void HttpWrapper::parse_response(rapidjson::Document& json_result, } Matrices HttpWrapper::get_matrices(const std::vector& 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); @@ -207,9 +207,9 @@ void HttpWrapper::update_sparse_matrix( std::mutex& matrix_m, std::unordered_map& v_id_to_geom, std::mutex& id_to_geom_m) const { - std::string query = this->build_query(route_locs, _route_service); + const std::string query = this->build_query(route_locs, _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); @@ -244,9 +244,9 @@ 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); From bcf16847c2c34ffd4fd3e5a849393d467ddb88bd Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 8 Nov 2024 14:03:31 +0100 Subject: [PATCH 27/30] Store matching between route rank and vehicle rank in check_and_set_ETA. --- src/algorithms/validation/check.cpp | 7 +++++-- src/algorithms/validation/check.h | 7 ++++++- src/algorithms/validation/choose_ETA.h | 2 +- src/structures/vroom/input/input.cpp | 11 +++++++++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/algorithms/validation/check.cpp b/src/algorithms/validation/check.cpp index 64e0a8560..1e086e575 100644 --- a/src/algorithms/validation/check.cpp +++ b/src/algorithms/validation/check.cpp @@ -10,7 +10,6 @@ All rights reserved (see LICENSE). #include #include #include -#include #include #include @@ -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& route_rank_to_v_rank) { // Keep track of assigned job ranks. std::unordered_set assigned_ranks; @@ -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; } diff --git a/src/algorithms/validation/check.h b/src/algorithms/validation/check.h index e86d7a83f..2ca6f15cb 100644 --- a/src/algorithms/validation/check.h +++ b/src/algorithms/validation/check.h @@ -10,12 +10,17 @@ All rights reserved (see LICENSE). */ +#include + #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& route_rank_to_v_rank); } // namespace vroom::validation diff --git a/src/algorithms/validation/choose_ETA.h b/src/algorithms/validation/choose_ETA.h index 468c7809e..b46fe5046 100644 --- a/src/algorithms/validation/choose_ETA.h +++ b/src/algorithms/validation/choose_ETA.h @@ -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 { diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index b371f5892..0cf88c23a 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -1204,7 +1204,9 @@ Solution Input::check(unsigned nb_thread) { .count(); // Check. - auto sol = validation::check_and_set_ETA(*this, nb_thread); + std::unordered_map route_rank_to_v_rank; + auto sol = + validation::check_and_set_ETA(*this, nb_thread, route_rank_to_v_rank); // Update timing info. sol.summary.computing_times.loading = loading; @@ -1216,7 +1218,12 @@ Solution Input::check(unsigned nb_thread) { .count(); if (_geometry) { - for (auto& route : sol.routes) { + for (std::size_t i = 0; i < sol.routes.size(); ++i) { + auto& route = sol.routes[i]; + + auto search = route_rank_to_v_rank.find(i); + assert(search != route_rank_to_v_rank.end()); + assert(_vehicle_id_to_geometry.contains(route.vehicle)); route.geometry = std::move(_vehicle_id_to_geometry.at(route.vehicle)); } From 7ab2fd9eb8b85639f1c4dd013980445478942b8a Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 8 Nov 2024 14:39:42 +0100 Subject: [PATCH 28/30] Store vehicle geometries in a vector in Input. --- src/structures/vroom/input/input.cpp | 9 +++++---- src/structures/vroom/input/input.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index 0cf88c23a..bdfc42d3c 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -910,10 +910,12 @@ routing::Matrices Input::get_matrices_by_profile(const std::string& profile, }); assert(rw != _routing_wrappers.end()); + // Note: get_sparse_matrices relies on getting in input *all* + // vehicles as it refers to vehicle ranks to store geometries. return sparse_filling ? (*rw)->get_sparse_matrices(_locations, this->vehicles, this->jobs, - _vehicle_id_to_geometry) + _vehicles_geometry) : (*rw)->get_matrices(_locations); } @@ -1223,9 +1225,8 @@ Solution Input::check(unsigned nb_thread) { auto search = route_rank_to_v_rank.find(i); assert(search != route_rank_to_v_rank.end()); - - assert(_vehicle_id_to_geometry.contains(route.vehicle)); - route.geometry = std::move(_vehicle_id_to_geometry.at(route.vehicle)); + const auto v_rank = search->second; + route.geometry = std::move(_vehicles_geometry[v_rank]); } _end_routing = std::chrono::high_resolution_clock::now(); diff --git a/src/structures/vroom/input/input.h b/src/structures/vroom/input/input.h index dc8cf626d..a5bde472c 100644 --- a/src/structures/vroom/input/input.h +++ b/src/structures/vroom/input/input.h @@ -81,7 +81,7 @@ class Input { // Used in plan mode since we store route geometries while // generating sparse matrices. - std::unordered_map _vehicle_id_to_geometry; + std::vector _vehicles_geometry; std::optional _amount_size; Amount _zero; From 7534bf284ac8772106bc458b85dac365c4302102 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 8 Nov 2024 14:41:31 +0100 Subject: [PATCH 29/30] Adjust update_sparse_matrix to take a string& for geometry storage. --- src/routing/http_wrapper.cpp | 14 +++++--------- src/routing/http_wrapper.h | 6 ++---- src/routing/libosrm_wrapper.cpp | 11 +++-------- src/routing/libosrm_wrapper.h | 6 ++---- src/routing/wrapper.h | 11 ++++------- 5 files changed, 16 insertions(+), 32 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 049d2d15d..e0bccb2c7 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -200,13 +200,10 @@ Matrices HttpWrapper::get_matrices(const std::vector& locs) const { return m; } -void HttpWrapper::update_sparse_matrix( - const Id v_id, - const std::vector& route_locs, - Matrices& m, - std::mutex& matrix_m, - std::unordered_map& v_id_to_geom, - std::mutex& id_to_geom_m) const { +void HttpWrapper::update_sparse_matrix(const std::vector& 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); @@ -226,8 +223,7 @@ void HttpWrapper::update_sparse_matrix( get_leg_distance(legs[i]); } - std::scoped_lock lock(id_to_geom_m); - v_id_to_geom.try_emplace(v_id, get_geometry(json_result)); + vehicle_geometry = get_geometry(json_result); }; void HttpWrapper::add_geometry(Route& route) const { diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index bb8689267..18deefea1 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -55,12 +55,10 @@ class HttpWrapper : public Wrapper { Matrices get_matrices(const std::vector& locs) const override; - void update_sparse_matrix(const Id v_id, - const std::vector& route_locs, + void update_sparse_matrix(const std::vector& route_locs, Matrices& m, std::mutex& matrix_m, - std::unordered_map& v_id_to_geom, - std::mutex& id_to_geom_m) const override; + std::string& vehicles_geometry) const override; virtual bool duration_value_is_null(const rapidjson::Value& matrix_entry) const { diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index f1261a4fe..dede4c8fa 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -158,12 +158,10 @@ osrm::json::Object LibosrmWrapper::get_route_with_coordinates( } void LibosrmWrapper::update_sparse_matrix( - const Id v_id, const std::vector& route_locs, Matrices& m, std::mutex& matrix_m, - std::unordered_map& v_id_to_geom, - std::mutex& id_to_geom_m) const { + std::string& vehicle_geometry) const { auto json_route = get_route_with_coordinates(route_locs); auto& legs = json_route.values["legs"].get(); @@ -181,11 +179,8 @@ void LibosrmWrapper::update_sparse_matrix( leg.values["distance"].get().value); } - std::scoped_lock lock(id_to_geom_m); - v_id_to_geom.try_emplace(v_id, - std::move(json_route.values["geometry"] - .get() - .value)); + vehicle_geometry = + std::move(json_route.values["geometry"].get().value); }; void LibosrmWrapper::add_geometry(Route& route) const { diff --git a/src/routing/libosrm_wrapper.h b/src/routing/libosrm_wrapper.h index c96a40d3e..5a0e7deb9 100644 --- a/src/routing/libosrm_wrapper.h +++ b/src/routing/libosrm_wrapper.h @@ -34,12 +34,10 @@ class LibosrmWrapper : public Wrapper { Matrices get_matrices(const std::vector& locs) const override; - void update_sparse_matrix(const Id v_id, - const std::vector& route_locs, + void update_sparse_matrix(const std::vector& route_locs, Matrices& m, std::mutex& matrix_m, - std::unordered_map& v_id_to_geom, - std::mutex& id_to_geom_m) const override; + std::string& vehicle_geometry) const override; void add_geometry(Route& route) const override; }; diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index 5997d98aa..233efb2b4 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -114,13 +114,10 @@ class Wrapper { // Updates matrices with data from a single route request and stores // corresponding route geometry. - virtual void - update_sparse_matrix(const Id v_id, - const std::vector& route_locs, - Matrices& m, - std::mutex& matrix_m, - std::unordered_map& v_id_to_geom, - std::mutex& id_to_geom_m) const = 0; + virtual void update_sparse_matrix(const std::vector& route_locs, + Matrices& m, + std::mutex& matrix_m, + std::string& vehicle_geometry) const = 0; virtual void add_geometry(Route& route) const = 0; From 612b1ba33ad7514ac607fbd179befd69b383c3a6 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 8 Nov 2024 14:42:08 +0100 Subject: [PATCH 30/30] Adjust get_sparse_matrices for geometry storage. --- src/routing/wrapper.h | 36 +++++++++++++--------------- src/structures/vroom/input/input.cpp | 4 ++++ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index 233efb2b4..014621e57 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -34,19 +34,20 @@ class Wrapper { get_sparse_matrices(const std::vector& locs, const std::vector& vehicles, const std::vector& jobs, - std::unordered_map& v_id_to_geom) const { + std::vector& vehicles_geometry) const { std::size_t m_size = locs.size(); Matrices m(m_size); std::exception_ptr ep = nullptr; std::mutex ep_m; - std::mutex id_to_geom_m; std::mutex matrix_m; - auto run_on_vehicle = - [this, &jobs, &matrix_m, &m, &id_to_geom_m, &v_id_to_geom, &ep_m, &ep]( - const Vehicle& v) { + auto run_on_vehicle_at_rank = + [this, &vehicles, &jobs, &matrix_m, &m, &vehicles_geometry, &ep_m, &ep]( + Index v_rank) { try { + const Vehicle& v = vehicles[v_rank]; + std::vector route_locs; route_locs.reserve(v.steps.size()); @@ -73,19 +74,14 @@ class Wrapper { } } - if (!has_job_steps) { - // No steps provided in input for vehicle, or only breaks in - // steps. - return; + if (has_job_steps) { + assert(route_locs.size() >= 2); + + this->update_sparse_matrix(route_locs, + m, + matrix_m, + vehicles_geometry[v_rank]); } - assert(route_locs.size() >= 2); - - this->update_sparse_matrix(v.id, - route_locs, - m, - matrix_m, - v_id_to_geom, - id_to_geom_m); } catch (...) { std::scoped_lock lock(ep_m); ep = std::current_exception(); @@ -95,9 +91,9 @@ class Wrapper { std::vector vehicles_threads; vehicles_threads.reserve(vehicles.size()); - for (const auto& v : vehicles) { - if (v.profile == this->profile) { - vehicles_threads.emplace_back(run_on_vehicle, v); + for (Index v_rank = 0; v_rank < vehicles.size(); ++v_rank) { + if (vehicles[v_rank].profile == this->profile) { + vehicles_threads.emplace_back(run_on_vehicle_at_rank, v_rank); } } diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index bdfc42d3c..f5c9757ff 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -910,6 +910,10 @@ routing::Matrices Input::get_matrices_by_profile(const std::string& profile, }); assert(rw != _routing_wrappers.end()); + if (sparse_filling) { + _vehicles_geometry.resize(vehicles.size()); + } + // Note: get_sparse_matrices relies on getting in input *all* // vehicles as it refers to vehicle ranks to store geometries. return sparse_filling ? (*rw)->get_sparse_matrices(_locations,