From ef36202d848b961867943d071c2444445e5456a6 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 09:53:42 +0200 Subject: [PATCH 01/22] Add Input member for distance matrices storage. --- src/structures/typedefs.h | 1 + src/structures/vroom/input/input.cpp | 8 ++++++++ src/structures/vroom/input/input.h | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/src/structures/typedefs.h b/src/structures/typedefs.h index 002b2d6f8..d52f9b58b 100644 --- a/src/structures/typedefs.h +++ b/src/structures/typedefs.h @@ -35,6 +35,7 @@ using Cost = int64_t; using Distance = uint32_t; using UserDuration = uint32_t; using Duration = int64_t; +using UserDistance = uint32_t; using Coordinate = double; using Capacity = int64_t; using Skill = uint32_t; diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index 483647995..d4da6b1e1 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -386,6 +386,14 @@ void Input::set_durations_matrix(const std::string& profile, _durations_matrices.insert_or_assign(profile, m); } +void Input::set_distances_matrix(const std::string& profile, + Matrix&& m) { + if (m.size() == 0) { + throw InputException("Empty distances matrix for " + profile + " profile."); + } + _distances_matrices.insert_or_assign(profile, m); +} + void Input::set_costs_matrix(const std::string& profile, Matrix&& m) { if (m.size() == 0) { throw InputException("Empty costs matrix for " + profile + " profile."); diff --git a/src/structures/vroom/input/input.h b/src/structures/vroom/input/input.h index 249143301..705dbebd0 100644 --- a/src/structures/vroom/input/input.h +++ b/src/structures/vroom/input/input.h @@ -50,6 +50,7 @@ class Input { bool _has_jobs{false}; bool _has_shipments{false}; std::unordered_map> _durations_matrices; + std::unordered_map> _distances_matrices; std::unordered_map> _costs_matrices; Cost _cost_upper_bound{0}; std::vector _locations; @@ -110,6 +111,10 @@ class Input { void set_durations_matrix(const std::string& profile, Matrix&& m); + + void set_distances_matrix(const std::string& profile, + Matrix&& m); + void set_costs_matrix(const std::string& profile, Matrix&& m); const Amount& zero_amount() const { From cfde79a3fd2944235fe0c0f59ff34340681925b2 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 09:55:38 +0200 Subject: [PATCH 02/22] For ongoing dev only: log existing matrices after call to set_matrices and exit. --- src/structures/vroom/input/input.cpp | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index d4da6b1e1..82899204c 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -7,6 +7,8 @@ All rights reserved (see LICENSE). */ +#include + #include #include @@ -952,6 +954,47 @@ Solution Input::solve(unsigned exploration_level, set_matrices(nb_thread); set_vehicles_costs(); + for (const auto& profile : _profiles) { + std::cout << "* Durations matrix for profile " << profile << std::endl; + assert(_durations_matrices.find(profile) != _durations_matrices.end()); + const auto& duration_m = _durations_matrices.find(profile)->second; + + for (std::size_t i = 0; i < duration_m.size(); ++i) { + for (std::size_t j = 0; j < duration_m.size(); ++j) { + std::cout << duration_m[i][j] << "\t"; + } + std::cout << std::endl; + } + + if (_distances_matrices.find(profile) != _distances_matrices.end()) { + std::cout << "* Distances matrix for profile " << profile << std::endl; + + const auto& distance_m = _distances_matrices.find(profile)->second; + + for (std::size_t i = 0; i < distance_m.size(); ++i) { + for (std::size_t j = 0; j < distance_m.size(); ++j) { + std::cout << distance_m[i][j] << "\t"; + } + std::cout << std::endl; + } + } + + if (_costs_matrices.find(profile) != _costs_matrices.end()) { + std::cout << "* Costs matrix for profile " << profile << std::endl; + + const auto& distance_m = _costs_matrices.find(profile)->second; + + for (std::size_t i = 0; i < distance_m.size(); ++i) { + for (std::size_t j = 0; j < distance_m.size(); ++j) { + std::cout << distance_m[i][j] << "\t"; + } + std::cout << std::endl; + } + } + } + + exit(0); + // Fill vehicle/job compatibility matrices. set_skills_compatibility(); set_extra_compatibility(); From a1b914374dda2cba2689e288f79df44f389ffa26 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 09:56:31 +0200 Subject: [PATCH 03/22] Parse custom distances if present in json input. --- docs/API.md | 5 +++-- src/utils/input_parser.cpp | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/API.md b/docs/API.md index 0c5f0ebdd..dcbe0c9ee 100644 --- a/docs/API.md +++ b/docs/API.md @@ -281,11 +281,12 @@ integers filed under the `profile` key, then under: - `durations` for a custom travel-time matrix that will be used for all checks against timing constraints; +- `distances` for a custom distance matrix; - `costs` for a custom cost matrix that will be used within all route cost evaluations. -If only the `durations` value is provided, it's implied that it should -also be used for costs evaluations. +If only the `durations` matrix is provided, internal costs are derived from +durations based on vehicles `costs` properties. Example of describing different matrices for different vehicle profiles: diff --git a/src/utils/input_parser.cpp b/src/utils/input_parser.cpp index db216e6a5..8d2b752bc 100644 --- a/src/utils/input_parser.cpp +++ b/src/utils/input_parser.cpp @@ -603,6 +603,11 @@ void parse(Input& input, const std::string& input_str, bool geometry) { get_matrix( profile_entry.value["durations"])); } + if (profile_entry.value.HasMember("distances")) { + input.set_distances_matrix(profile_entry.name.GetString(), + get_matrix( + profile_entry.value["distances"])); + } if (profile_entry.value.HasMember("costs")) { input.set_costs_matrix(profile_entry.name.GetString(), get_matrix( From 4cd0a4a17d479b5884e8e74cf3eb917127dface0 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 10:31:54 +0200 Subject: [PATCH 04/22] Create empty distances matrix if not manually set. --- src/structures/vroom/input/input.cpp | 44 ++++++++++++++++------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index 82899204c..226acaafd 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -818,18 +818,26 @@ void Input::set_matrices(unsigned nb_thread) { for (const auto& profile : _profiles) { thread_profiles[t_rank % nb_buckets].push_back(profile); ++t_rank; + + // Even with custom matrices, we still need routing after + // optimization if geometry is requested. + bool create_routing_wrapper = _geometry; + if (_durations_matrices.find(profile) == _durations_matrices.end()) { - // Durations matrix has not been manually set, create routing - // wrapper and empty matrix to allow for concurrent modification - // later on. - add_routing_wrapper(profile); + // Durations matrix has not been manually set, create empty + // matrix to allow for concurrent modification later on. + create_routing_wrapper = true; _durations_matrices.emplace(profile, Matrix()); - } else { - if (_geometry) { - // Even with a custom matrix, we still want routing after - // optimization. - add_routing_wrapper(profile); - } + } + if (_distances_matrices.find(profile) == _distances_matrices.end()) { + // Distances matrix has not been manually set, create empty + // matrix to allow for concurrent modification later on. + create_routing_wrapper = true; + _distances_matrices.emplace(profile, Matrix()); + } + + if (create_routing_wrapper) { + add_routing_wrapper(profile); } } @@ -840,14 +848,14 @@ void Input::set_matrices(unsigned nb_thread) { auto run_on_profiles = [&](const std::vector& profiles) { try { for (const auto& profile : profiles) { - auto d_m = _durations_matrices.find(profile); - assert(d_m != _durations_matrices.end()); + auto durations_m = _durations_matrices.find(profile); + assert(durations_m != _durations_matrices.end()); - if (d_m->second.size() == 0) { + if (durations_m->second.size() == 0) { // Durations matrix not manually set so defined as empty // above. if (_locations.size() == 1) { - d_m->second = Matrix(1); + durations_m->second = Matrix(1); } else { auto rw = std::find_if(_routing_wrappers.begin(), _routing_wrappers.end(), @@ -858,7 +866,7 @@ void Input::set_matrices(unsigned nb_thread) { if (!_has_custom_location_index) { // Location indices are set based on order in _locations. - d_m->second = (*rw)->get_matrix(_locations); + durations_m->second = (*rw)->get_matrix(_locations); } else { // Location indices are provided in input so we need an // indirection based on order in _locations. @@ -872,12 +880,12 @@ void Input::set_matrices(unsigned nb_thread) { } } - d_m->second = std::move(full_m); + durations_m->second = std::move(full_m); } } } - if (d_m->second.size() <= _max_matrices_used_index) { + if (durations_m->second.size() <= _max_matrices_used_index) { throw InputException("location_index exceeding matrix size for " + profile + " profile."); } @@ -899,7 +907,7 @@ void Input::set_matrices(unsigned nb_thread) { cost_bound_m.unlock(); } else { // Durations matrix will be used for costs. - const UserCost current_bound = check_cost_bound(d_m->second); + const UserCost current_bound = check_cost_bound(durations_m->second); cost_bound_m.lock(); _cost_upper_bound = std::max(_cost_upper_bound, From 8ca9003244bd1e381e48c87f3df07388b51501a7 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 11:22:37 +0200 Subject: [PATCH 05/22] Add wrapper struct to return both durations and distances matrices in one object. --- src/routing/wrapper.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index 754d973c2..9b928c0cf 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -19,6 +19,14 @@ All rights reserved (see LICENSE). namespace vroom::routing { +struct Matrices { + Matrix durations; + Matrix distances; + + Matrices(std::size_t n) : durations(n), distances(n) { + }; +}; + class Wrapper { public: From dcb92533b0d02eea7fb6950cf9a1c76b59522936 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 11:24:08 +0200 Subject: [PATCH 06/22] Switch Wrapper::get_matrix to get_matrices. --- src/routing/http_wrapper.cpp | 7 +++---- src/routing/http_wrapper.h | 2 +- src/routing/libosrm_wrapper.cpp | 7 +++---- src/routing/libosrm_wrapper.h | 4 ++-- src/routing/wrapper.h | 6 ++---- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index d79798e4d..54f8d1acc 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -144,8 +144,7 @@ void HttpWrapper::parse_response(rapidjson::Document& json_result, #endif } -Matrix -HttpWrapper::get_matrix(const std::vector& locs) const { +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); @@ -163,7 +162,7 @@ HttpWrapper::get_matrix(const std::vector& locs) const { // Build matrix while checking for unfound routes ('null' values) to // avoid unexpected behavior. - Matrix m(m_size); + Matrices m(m_size); std::vector nb_unfound_from_loc(m_size, 0); std::vector nb_unfound_to_loc(m_size, 0); @@ -179,7 +178,7 @@ HttpWrapper::get_matrix(const std::vector& locs) const { ++nb_unfound_from_loc[i]; ++nb_unfound_to_loc[j]; } else { - m[i][j] = get_duration_value(line[j]); + m.durations[i][j] = get_duration_value(line[j]); } } } diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index 183cddcca..ac40aa426 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -50,7 +50,7 @@ class HttpWrapper : public Wrapper { virtual void check_response(const rapidjson::Document& json_result, const std::string& service) const = 0; - Matrix get_matrix(const std::vector& locs) const override; + Matrices get_matrices(const std::vector& locs) 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 cb8bbf551..59357e1dc 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -32,8 +32,7 @@ LibosrmWrapper::LibosrmWrapper(const std::string& profile) : Wrapper(profile), _config(get_config(profile)), _osrm(_config) { } -Matrix -LibosrmWrapper::get_matrix(const std::vector& locs) const { +Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { osrm::TableParameters params; for (auto const& location : locs) { assert(location.has_coordinates()); @@ -59,7 +58,7 @@ LibosrmWrapper::get_matrix(const std::vector& locs) const { // Build matrix while checking for unfound routes to avoid // unexpected behavior (OSRM raises 'null'). - Matrix m(m_size); + Matrices m(m_size); std::vector nb_unfound_from_loc(m_size, 0); std::vector nb_unfound_to_loc(m_size, 0); @@ -78,7 +77,7 @@ LibosrmWrapper::get_matrix(const std::vector& locs) const { ++nb_unfound_to_loc[j]; } else { auto cost = round_cost(el.get().value); - m[i][j] = cost; + m.durations[i][j] = cost; } } } diff --git a/src/routing/libosrm_wrapper.h b/src/routing/libosrm_wrapper.h index d0797064d..8c031c4d0 100644 --- a/src/routing/libosrm_wrapper.h +++ b/src/routing/libosrm_wrapper.h @@ -29,8 +29,8 @@ class LibosrmWrapper : public Wrapper { public: LibosrmWrapper(const std::string& profile); - virtual Matrix - get_matrix(const std::vector& locs) const override; + virtual Matrices + get_matrices(const std::vector& locs) const override; virtual void add_route_info(Route& route) const override; }; diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index 9b928c0cf..a20c1a36d 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -23,8 +23,7 @@ struct Matrices { Matrix durations; Matrix distances; - Matrices(std::size_t n) : durations(n), distances(n) { - }; + Matrices(std::size_t n) : durations(n), distances(n){}; }; class Wrapper { @@ -32,8 +31,7 @@ class Wrapper { public: std::string profile; - virtual Matrix - get_matrix(const std::vector& locs) const = 0; + virtual Matrices get_matrices(const std::vector& locs) const = 0; virtual void add_route_info(Route& route) const = 0; From 40505b8b4f972fa25ee4b73b7b09778265ece60f Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 11:25:55 +0200 Subject: [PATCH 07/22] Adjust client code in Input to store distances from get_matrices. --- src/structures/vroom/input/input.cpp | 64 +++++++++++++++++++--------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index 226acaafd..98b4f960d 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -828,12 +828,12 @@ void Input::set_matrices(unsigned nb_thread) { // matrix to allow for concurrent modification later on. create_routing_wrapper = true; _durations_matrices.emplace(profile, Matrix()); - } - if (_distances_matrices.find(profile) == _distances_matrices.end()) { - // Distances matrix has not been manually set, create empty - // matrix to allow for concurrent modification later on. - create_routing_wrapper = true; - _distances_matrices.emplace(profile, Matrix()); + + if (_distances_matrices.find(profile) == _distances_matrices.end()) { + // Distances matrix has not been manually set, create empty + // matrix to allow for concurrent modification later on. + _distances_matrices.emplace(profile, Matrix()); + } } if (create_routing_wrapper) { @@ -849,13 +849,18 @@ void Input::set_matrices(unsigned nb_thread) { try { for (const auto& profile : profiles) { auto durations_m = _durations_matrices.find(profile); - assert(durations_m != _durations_matrices.end()); + auto distances_m = _distances_matrices.find(profile); - if (durations_m->second.size() == 0) { - // Durations matrix not manually set so defined as empty - // above. + // Required matrices not manually set have been defined as + // empty above. + assert(durations_m != _durations_matrices.end()); + bool define_durations = (durations_m->second.size() == 0); + bool define_distances = (distances_m != _distances_matrices.end()) and + (distances_m->second.size() == 0); + if (define_durations or define_distances) { if (_locations.size() == 1) { durations_m->second = Matrix(1); + distances_m->second = Matrix(1); } else { auto rw = std::find_if(_routing_wrappers.begin(), _routing_wrappers.end(), @@ -866,21 +871,42 @@ void Input::set_matrices(unsigned nb_thread) { if (!_has_custom_location_index) { // Location indices are set based on order in _locations. - durations_m->second = (*rw)->get_matrix(_locations); + auto matrices = (*rw)->get_matrices(_locations); + if (define_durations) { + durations_m->second = std::move(matrices.durations); + } + if (define_distances) { + distances_m->second = std::move(matrices.distances); + } } else { // Location indices are provided in input so we need an // indirection based on order in _locations. - auto m = (*rw)->get_matrix(_locations); - - Matrix full_m(_max_matrices_used_index + 1); - for (Index i = 0; i < _locations.size(); ++i) { - const auto& loc_i = _locations[i]; - for (Index j = 0; j < _locations.size(); ++j) { - full_m[loc_i.index()][_locations[j].index()] = m[i][j]; + 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) { + const auto& loc_i = _locations[i]; + for (Index j = 0; j < _locations.size(); ++j) { + full_m[loc_i.index()][_locations[j].index()] = + matrices.durations[i][j]; + } } + + durations_m->second = std::move(full_m); } + if (define_distances) { + Matrix full_m(_max_matrices_used_index + 1); + for (Index i = 0; i < _locations.size(); ++i) { + const auto& loc_i = _locations[i]; + for (Index j = 0; j < _locations.size(); ++j) { + full_m[loc_i.index()][_locations[j].index()] = + matrices.distances[i][j]; + } + } - durations_m->second = std::move(full_m); + distances_m->second = std::move(full_m); + } } } } From 203c76bf4351b6d206255e51bb0f0313bbd6c5cb Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 15:08:03 +0200 Subject: [PATCH 08/22] Consistently replace previous Distance type with UserDistance. --- src/structures/typedefs.h | 1 - src/structures/vroom/solution/route.h | 2 +- src/structures/vroom/solution/step.h | 2 +- src/structures/vroom/solution/summary.h | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/structures/typedefs.h b/src/structures/typedefs.h index d52f9b58b..15e0e3e5d 100644 --- a/src/structures/typedefs.h +++ b/src/structures/typedefs.h @@ -32,7 +32,6 @@ using Id = uint64_t; using Index = uint16_t; using UserCost = uint32_t; using Cost = int64_t; -using Distance = uint32_t; using UserDuration = uint32_t; using Duration = int64_t; using UserDistance = uint32_t; diff --git a/src/structures/vroom/solution/route.h b/src/structures/vroom/solution/route.h index 3c25f4553..3c93cc420 100644 --- a/src/structures/vroom/solution/route.h +++ b/src/structures/vroom/solution/route.h @@ -33,7 +33,7 @@ struct Route { Violations violations; std::string geometry; - Distance distance; + UserDistance distance; Route(); diff --git a/src/structures/vroom/solution/step.h b/src/structures/vroom/solution/step.h index 048332707..47c8010b9 100644 --- a/src/structures/vroom/solution/step.h +++ b/src/structures/vroom/solution/step.h @@ -32,7 +32,7 @@ struct Step { UserDuration arrival; UserDuration duration; UserDuration waiting_time; - Distance distance; + UserDistance distance; Violations violations; diff --git a/src/structures/vroom/solution/summary.h b/src/structures/vroom/solution/summary.h index 8a8ef363d..6466ec37e 100644 --- a/src/structures/vroom/solution/summary.h +++ b/src/structures/vroom/solution/summary.h @@ -29,7 +29,7 @@ struct Summary { UserDuration duration; UserDuration waiting_time; - Distance distance; + UserDistance distance; ComputingTimes computing_times; Violations violations; From d49cdab9ae02f6f8c678c68efadf57580fcd6b82 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 15:09:33 +0200 Subject: [PATCH 09/22] Template Wrapper::round_cost static function. --- src/routing/http_wrapper.cpp | 14 +++++++------- src/routing/libosrm_wrapper.cpp | 11 ++++++----- src/routing/ors_wrapper.cpp | 2 +- src/routing/osrm_routed_wrapper.cpp | 2 +- src/routing/wrapper.h | 4 ++-- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 54f8d1acc..af76df2f2 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -217,7 +217,7 @@ void HttpWrapper::add_route_info(Route& route) const { this->check_response(json_result, _route_service); // Total distance and route geometry. - route.distance = round_cost(get_total_distance(json_result)); + route.distance = round_cost(get_total_distance(json_result)); route.geometry = get_geometry(json_result); auto nb_legs = get_legs_number(json_result); @@ -244,17 +244,17 @@ void HttpWrapper::add_route_info(Route& route) const { for (unsigned b = 1; b <= number_breaks_after[i]; ++b) { auto& break_step = route.steps[steps_rank + b]; if (next_duration == 0) { - break_step.distance = round_cost(sum_distance); + break_step.distance = round_cost(sum_distance); } else { - break_step.distance = - round_cost(sum_distance + - ((break_step.duration - step.duration) * next_distance) / - next_duration); + break_step.distance = round_cost( + sum_distance + + ((break_step.duration - step.duration) * next_distance) / + next_duration); } } sum_distance += next_distance; - next_step.distance = round_cost(sum_distance); + next_step.distance = round_cost(sum_distance); steps_rank += number_breaks_after[i] + 1; } diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index 59357e1dc..dce3ab857 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -76,7 +76,8 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { ++nb_unfound_from_loc[i]; ++nb_unfound_to_loc[j]; } else { - auto cost = round_cost(el.get().value); + auto cost = + round_cost(duration_el.get().value); m.durations[i][j] = cost; } } @@ -129,8 +130,8 @@ void LibosrmWrapper::add_route_info(Route& route) const { auto& json_route = result_routes.values.at(0).get(); // Total distance and route geometry. - route.distance = - round_cost(json_route.values["distance"].get().value); + route.distance = round_cost( + json_route.values["distance"].get().value); route.geometry = std::move(json_route.values["geometry"].get().value); @@ -169,13 +170,13 @@ void LibosrmWrapper::add_route_info(Route& route) const { // non-breaks steps. for (unsigned b = 1; b <= number_breaks_after[i]; ++b) { auto& break_step = route.steps[steps_rank + b]; - break_step.distance = round_cost( + break_step.distance = round_cost( sum_distance + ((break_step.duration - step.duration) * next_distance) / next_duration); } sum_distance += next_distance; - next_step.distance = round_cost(sum_distance); + next_step.distance = round_cost(sum_distance); steps_rank += number_breaks_after[i] + 1; } diff --git a/src/routing/ors_wrapper.cpp b/src/routing/ors_wrapper.cpp index 16282890e..a6ee9ca5e 100644 --- a/src/routing/ors_wrapper.cpp +++ b/src/routing/ors_wrapper.cpp @@ -72,7 +72,7 @@ bool OrsWrapper::duration_value_is_null( UserDuration OrsWrapper::get_duration_value(const rapidjson::Value& matrix_entry) const { - return round_cost(matrix_entry.GetDouble()); + return round_cost(matrix_entry.GetDouble()); } double OrsWrapper::get_total_distance(const rapidjson::Value& result) const { diff --git a/src/routing/osrm_routed_wrapper.cpp b/src/routing/osrm_routed_wrapper.cpp index b20fd2ca3..e1704c783 100644 --- a/src/routing/osrm_routed_wrapper.cpp +++ b/src/routing/osrm_routed_wrapper.cpp @@ -65,7 +65,7 @@ bool OsrmRoutedWrapper::duration_value_is_null( UserDuration OsrmRoutedWrapper::get_duration_value( const rapidjson::Value& matrix_entry) const { - return round_cost(matrix_entry.GetDouble()); + return round_cost(matrix_entry.GetDouble()); } double diff --git a/src/routing/wrapper.h b/src/routing/wrapper.h index a20c1a36d..1024a9b81 100644 --- a/src/routing/wrapper.h +++ b/src/routing/wrapper.h @@ -41,9 +41,9 @@ class Wrapper { Wrapper(std::string profile) : profile(std::move(profile)) { } - static UserCost round_cost(double value) { + template static T round_cost(double value) { constexpr double round_increment = 0.5; - return static_cast(value + round_increment); + return static_cast(value + round_increment); } static inline void From adbfe7e04600a2fc26896bc05f706e407905fd74 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 15:13:51 +0200 Subject: [PATCH 10/22] Retrieve distances from libosrm. --- src/routing/libosrm_wrapper.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/routing/libosrm_wrapper.cpp b/src/routing/libosrm_wrapper.cpp index dce3ab857..0a0669024 100644 --- a/src/routing/libosrm_wrapper.cpp +++ b/src/routing/libosrm_wrapper.cpp @@ -34,6 +34,8 @@ LibosrmWrapper::LibosrmWrapper(const std::string& profile) Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { osrm::TableParameters params; + params.annotations = osrm::engine::api::TableParameters::AnnotationsType::All; + for (auto const& location : locs) { assert(location.has_coordinates()); params.coordinates @@ -50,11 +52,13 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { ": " + result.values["message"].get().value); } - auto& table = result.values["durations"].get(); + const auto& durations = result.values["durations"].get(); + const auto& distances = result.values["distances"].get(); // Expected matrix size. std::size_t m_size = locs.size(); - assert(table.values.size() == m_size); + assert(durations.values.size() == m_size); + assert(distances.values.size() == m_size); // Build matrix while checking for unfound routes to avoid // unexpected behavior (OSRM raises 'null'). @@ -65,20 +69,26 @@ Matrices LibosrmWrapper::get_matrices(const std::vector& locs) const { std::string reason; for (std::size_t i = 0; i < m_size; ++i) { - const auto& line = table.values.at(i).get(); - assert(line.values.size() == m_size); + const auto& duration_line = durations.values.at(i).get(); + const auto& distance_line = distances.values.at(i).get(); + assert(duration_line.values.size() == m_size); + assert(distance_line.values.size() == m_size); + for (std::size_t j = 0; j < m_size; ++j) { - const auto& el = line.values.at(j); - if (el.is()) { + const auto& duration_el = duration_line.values.at(j); + const auto& distance_el = distance_line.values.at(j); + if (duration_el.is() or + distance_el.is()) { // No route found between i and j. Just storing info as we // don't know yet which location is responsible between i // and j. ++nb_unfound_from_loc[i]; ++nb_unfound_to_loc[j]; } else { - auto cost = + m.durations[i][j] = round_cost(duration_el.get().value); - m.durations[i][j] = cost; + m.distances[i][j] = + round_cost(distance_el.get().value); } } } From 9125ce531d2e61c4e6d61ff5534e67888bd98172 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 15:14:56 +0200 Subject: [PATCH 11/22] Comment out the debug logging to please CI. --- src/structures/vroom/input/input.cpp | 80 ++++++++++++++-------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index 98b4f960d..248a35921 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -988,46 +988,46 @@ Solution Input::solve(unsigned exploration_level, set_matrices(nb_thread); set_vehicles_costs(); - for (const auto& profile : _profiles) { - std::cout << "* Durations matrix for profile " << profile << std::endl; - assert(_durations_matrices.find(profile) != _durations_matrices.end()); - const auto& duration_m = _durations_matrices.find(profile)->second; - - for (std::size_t i = 0; i < duration_m.size(); ++i) { - for (std::size_t j = 0; j < duration_m.size(); ++j) { - std::cout << duration_m[i][j] << "\t"; - } - std::cout << std::endl; - } - - if (_distances_matrices.find(profile) != _distances_matrices.end()) { - std::cout << "* Distances matrix for profile " << profile << std::endl; - - const auto& distance_m = _distances_matrices.find(profile)->second; - - for (std::size_t i = 0; i < distance_m.size(); ++i) { - for (std::size_t j = 0; j < distance_m.size(); ++j) { - std::cout << distance_m[i][j] << "\t"; - } - std::cout << std::endl; - } - } - - if (_costs_matrices.find(profile) != _costs_matrices.end()) { - std::cout << "* Costs matrix for profile " << profile << std::endl; - - const auto& distance_m = _costs_matrices.find(profile)->second; - - for (std::size_t i = 0; i < distance_m.size(); ++i) { - for (std::size_t j = 0; j < distance_m.size(); ++j) { - std::cout << distance_m[i][j] << "\t"; - } - std::cout << std::endl; - } - } - } - - exit(0); + // for (const auto& profile : _profiles) { + // std::cout << "* Durations matrix for profile " << profile << std::endl; + // assert(_durations_matrices.find(profile) != _durations_matrices.end()); + // const auto& duration_m = _durations_matrices.find(profile)->second; + + // for (std::size_t i = 0; i < duration_m.size(); ++i) { + // for (std::size_t j = 0; j < duration_m.size(); ++j) { + // std::cout << duration_m[i][j] << "\t"; + // } + // std::cout << std::endl; + // } + + // if (_distances_matrices.find(profile) != _distances_matrices.end()) { + // std::cout << "* Distances matrix for profile " << profile << std::endl; + + // const auto& distance_m = _distances_matrices.find(profile)->second; + + // for (std::size_t i = 0; i < distance_m.size(); ++i) { + // for (std::size_t j = 0; j < distance_m.size(); ++j) { + // std::cout << distance_m[i][j] << "\t"; + // } + // std::cout << std::endl; + // } + // } + + // if (_costs_matrices.find(profile) != _costs_matrices.end()) { + // std::cout << "* Costs matrix for profile " << profile << std::endl; + + // const auto& distance_m = _costs_matrices.find(profile)->second; + + // for (std::size_t i = 0; i < distance_m.size(); ++i) { + // for (std::size_t j = 0; j < distance_m.size(); ++j) { + // std::cout << distance_m[i][j] << "\t"; + // } + // std::cout << std::endl; + // } + // } + // } + + // exit(0); // Fill vehicle/job compatibility matrices. set_skills_compatibility(); From 3e7d850376cefb52e1b890423438d01b6c415190 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 16:53:35 +0200 Subject: [PATCH 12/22] Rename extra_args to routing_args and simpligy build_query. --- src/routing/http_wrapper.cpp | 7 +++---- src/routing/http_wrapper.h | 7 +++---- src/routing/ors_wrapper.cpp | 9 +++++---- src/routing/ors_wrapper.h | 3 +-- src/routing/osrm_routed_wrapper.cpp | 9 +++++---- src/routing/osrm_routed_wrapper.h | 3 +-- src/routing/valhalla_wrapper.cpp | 12 ++++-------- src/routing/valhalla_wrapper.h | 6 ++---- 8 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index af76df2f2..1a871dc84 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -23,13 +23,13 @@ HttpWrapper::HttpWrapper(const std::string& profile, std::string matrix_service, std::string matrix_durations_key, std::string route_service, - std::string extra_args) + std::string routing_args) : Wrapper(profile), _server(std::move(server)), _matrix_service(std::move(matrix_service)), _matrix_durations_key(std::move(matrix_durations_key)), _route_service(std::move(route_service)), - _extra_args(std::move(extra_args)) { + _routing_args(std::move(routing_args)) { } std::string HttpWrapper::send_then_receive(const std::string& query) const { @@ -207,8 +207,7 @@ void HttpWrapper::add_route_info(Route& route) const { } assert(!non_break_locations.empty()); - std::string query = - build_query(non_break_locations, _route_service, _extra_args); + std::string query = build_query(non_break_locations, _route_service); std::string json_string = this->run_query(query); diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index ac40aa426..94a164865 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -29,14 +29,14 @@ class HttpWrapper : public Wrapper { const std::string _matrix_service; const std::string _matrix_durations_key; const std::string _route_service; - const std::string _extra_args; + const std::string _routing_args; HttpWrapper(const std::string& profile, Server server, std::string matrix_service, std::string matrix_durations_key, std::string route_service, - std::string extra_args); + std::string routing_args); std::string run_query(const std::string& query) const; @@ -44,8 +44,7 @@ class HttpWrapper : public Wrapper { const std::string& json_content); virtual std::string build_query(const std::vector& locations, - const std::string& service, - const std::string& extra_args = "") const = 0; + const std::string& service) const = 0; virtual void check_response(const rapidjson::Document& json_result, const std::string& service) const = 0; diff --git a/src/routing/ors_wrapper.cpp b/src/routing/ors_wrapper.cpp index a6ee9ca5e..234b751c8 100644 --- a/src/routing/ors_wrapper.cpp +++ b/src/routing/ors_wrapper.cpp @@ -22,8 +22,7 @@ OrsWrapper::OrsWrapper(const std::string& profile, const Server& server) } std::string OrsWrapper::build_query(const std::vector& locations, - const std::string& service, - const std::string& extra_args) const { + const std::string& service) const { // Adding locations. std::string body = "{\""; if (service == "directions") { @@ -38,8 +37,10 @@ std::string OrsWrapper::build_query(const std::vector& locations, } body.pop_back(); // Remove trailing ','. body += "]"; - if (!extra_args.empty()) { - body += "," + extra_args; + if (service == _route_service) { + body += "," + _routing_args; + } else { + assert(service == _matrix_service); } body += "}"; diff --git a/src/routing/ors_wrapper.h b/src/routing/ors_wrapper.h index 923072eca..426a2a390 100644 --- a/src/routing/ors_wrapper.h +++ b/src/routing/ors_wrapper.h @@ -17,8 +17,7 @@ namespace vroom::routing { class OrsWrapper : public HttpWrapper { private: std::string build_query(const std::vector& locations, - const std::string& service, - const std::string& extra_args) const override; + const std::string& service) const override; void check_response(const rapidjson::Document& json_result, const std::string& service) const override; diff --git a/src/routing/osrm_routed_wrapper.cpp b/src/routing/osrm_routed_wrapper.cpp index e1704c783..9f38d8056 100644 --- a/src/routing/osrm_routed_wrapper.cpp +++ b/src/routing/osrm_routed_wrapper.cpp @@ -24,8 +24,7 @@ OsrmRoutedWrapper::OsrmRoutedWrapper(const std::string& profile, std::string OsrmRoutedWrapper::build_query(const std::vector& locations, - const std::string& service, - const std::string& extra_args) const { + const std::string& service) const { // Building query for osrm-routed std::string query = "GET /" + service; @@ -38,8 +37,10 @@ OsrmRoutedWrapper::build_query(const std::vector& locations, } query.pop_back(); // Remove trailing ';'. - if (!extra_args.empty()) { - query += "?" + extra_args; + if (service == _route_service) { + query += "?" + _routing_args; + } else { + assert(service == _matrix_service); } query += " HTTP/1.1\r\n"; diff --git a/src/routing/osrm_routed_wrapper.h b/src/routing/osrm_routed_wrapper.h index 86f33795a..7c7a37de9 100644 --- a/src/routing/osrm_routed_wrapper.h +++ b/src/routing/osrm_routed_wrapper.h @@ -17,8 +17,7 @@ namespace vroom::routing { class OsrmRoutedWrapper : public HttpWrapper { private: std::string build_query(const std::vector& locations, - const std::string& service, - const std::string& extra_args) const override; + const std::string& service) const override; void check_response(const rapidjson::Document& json_result, const std::string& service) const override; diff --git a/src/routing/valhalla_wrapper.cpp b/src/routing/valhalla_wrapper.cpp index a82977e96..efa3432f1 100644 --- a/src/routing/valhalla_wrapper.cpp +++ b/src/routing/valhalla_wrapper.cpp @@ -53,8 +53,7 @@ std::string ValhallaWrapper::get_matrix_query( } std::string -ValhallaWrapper::get_route_query(const std::vector& locations, - const std::string& extra_args) const { +ValhallaWrapper::get_route_query(const std::vector& locations) const { // Building matrix query for Valhalla. std::string query = "GET /" + _route_service + "?json={\"locations\":["; @@ -66,9 +65,7 @@ ValhallaWrapper::get_route_query(const std::vector& locations, query.pop_back(); // Remove trailing ','. query += R"(],"costing":")" + profile + "\""; - if (!extra_args.empty()) { - query += "," + extra_args; - } + query += "," + _routing_args; query += "}"; query += " HTTP/1.1\r\n"; @@ -80,12 +77,11 @@ ValhallaWrapper::get_route_query(const std::vector& locations, } std::string ValhallaWrapper::build_query(const std::vector& locations, - const std::string& service, - const std::string& extra_args) const { + const std::string& service) const { assert(service == _matrix_service or service == _route_service); return (service == _matrix_service) ? get_matrix_query(locations) - : get_route_query(locations, extra_args); + : get_route_query(locations); } void ValhallaWrapper::check_response(const rapidjson::Document& json_result, diff --git a/src/routing/valhalla_wrapper.h b/src/routing/valhalla_wrapper.h index 186347e46..06fa9a5be 100644 --- a/src/routing/valhalla_wrapper.h +++ b/src/routing/valhalla_wrapper.h @@ -18,12 +18,10 @@ class ValhallaWrapper : public HttpWrapper { private: std::string get_matrix_query(const std::vector& locations) const; - std::string get_route_query(const std::vector& locations, - const std::string& extra_args = "") const; + std::string get_route_query(const std::vector& locations) const; std::string build_query(const std::vector& locations, - const std::string& service, - const std::string& extra_args) const override; + const std::string& service) const override; void check_response(const rapidjson::Document& json_result, const std::string& service) const override; From d377dbf3d36ab0c512681ce8e536f312e411c66e Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 16:58:58 +0200 Subject: [PATCH 13/22] Add HttpWrapper member for distance key in output. --- src/routing/http_wrapper.cpp | 7 +++++++ src/routing/http_wrapper.h | 2 ++ src/routing/ors_wrapper.cpp | 1 + src/routing/osrm_routed_wrapper.cpp | 1 + src/routing/valhalla_wrapper.cpp | 1 + 5 files changed, 12 insertions(+) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 1a871dc84..8aa30ea3a 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -22,12 +22,14 @@ HttpWrapper::HttpWrapper(const std::string& profile, Server server, std::string matrix_service, std::string matrix_durations_key, + std::string matrix_distances_key, std::string route_service, std::string routing_args) : Wrapper(profile), _server(std::move(server)), _matrix_service(std::move(matrix_service)), _matrix_durations_key(std::move(matrix_durations_key)), + _matrix_distances_key(std::move(matrix_distances_key)), _route_service(std::move(route_service)), _routing_args(std::move(routing_args)) { } @@ -160,6 +162,11 @@ Matrices HttpWrapper::get_matrices(const std::vector& locs) const { } assert(json_result[_matrix_durations_key.c_str()].Size() == m_size); + if (!json_result.HasMember(_matrix_distances_key.c_str())) { + throw RoutingException("Missing " + _matrix_distances_key + "."); + } + assert(json_result[_matrix_distances_key.c_str()].Size() == m_size); + // Build matrix while checking for unfound routes ('null' values) to // avoid unexpected behavior. Matrices m(m_size); diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index 94a164865..91f668512 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -28,6 +28,7 @@ class HttpWrapper : public Wrapper { const Server _server; const std::string _matrix_service; const std::string _matrix_durations_key; + const std::string _matrix_distances_key; const std::string _route_service; const std::string _routing_args; @@ -35,6 +36,7 @@ class HttpWrapper : public Wrapper { Server server, std::string matrix_service, std::string matrix_durations_key, + std::string matrix_distances_key, std::string route_service, std::string routing_args); diff --git a/src/routing/ors_wrapper.cpp b/src/routing/ors_wrapper.cpp index 234b751c8..b13b84cdd 100644 --- a/src/routing/ors_wrapper.cpp +++ b/src/routing/ors_wrapper.cpp @@ -16,6 +16,7 @@ OrsWrapper::OrsWrapper(const std::string& profile, const Server& server) server, "matrix", "durations", + "distances", "directions", "\"geometry_simplify\":\"false\",\"continue_straight\":" "\"false\"") { diff --git a/src/routing/osrm_routed_wrapper.cpp b/src/routing/osrm_routed_wrapper.cpp index 9f38d8056..98d901d18 100644 --- a/src/routing/osrm_routed_wrapper.cpp +++ b/src/routing/osrm_routed_wrapper.cpp @@ -17,6 +17,7 @@ OsrmRoutedWrapper::OsrmRoutedWrapper(const std::string& profile, server, "table", "durations", + "distances", "route", "alternatives=false&steps=false&overview=full&continue_" "straight=false") { diff --git a/src/routing/valhalla_wrapper.cpp b/src/routing/valhalla_wrapper.cpp index efa3432f1..c8e3f83fe 100644 --- a/src/routing/valhalla_wrapper.cpp +++ b/src/routing/valhalla_wrapper.cpp @@ -23,6 +23,7 @@ ValhallaWrapper::ValhallaWrapper(const std::string& profile, server, "sources_to_targets", "sources_to_targets", + "sources_to_targets", "route", R"("directions_type":"none")") { } From 38f1dda466c7caabd916a8d70a1c8bc00feaf9cf Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 17:03:08 +0200 Subject: [PATCH 14/22] Add generic distances handling in HttpWrapper::get_matrices. --- src/routing/http_wrapper.cpp | 14 +++++++++----- src/routing/http_wrapper.h | 6 ++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 8aa30ea3a..52c3397f0 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -175,17 +175,21 @@ Matrices HttpWrapper::get_matrices(const std::vector& locs) const { std::vector nb_unfound_to_loc(m_size, 0); for (rapidjson::SizeType i = 0; i < m_size; ++i) { - const auto& line = json_result[_matrix_durations_key.c_str()][i]; - assert(line.Size() == m_size); - for (rapidjson::SizeType j = 0; j < line.Size(); ++j) { - if (duration_value_is_null(line[j])) { + const auto& duration_line = json_result[_matrix_durations_key.c_str()][i]; + const auto& distance_line = json_result[_matrix_distances_key.c_str()][i]; + assert(duration_line.Size() == m_size); + assert(distance_line.Size() == m_size); + for (rapidjson::SizeType j = 0; j < m_size; ++j) { + if (duration_value_is_null(duration_line[j]) or + distance_value_is_null(distance_line[j])) { // No route found between i and j. Just storing info as we // don't know yet which location is responsible between i // and j. ++nb_unfound_from_loc[i]; ++nb_unfound_to_loc[j]; } else { - m.durations[i][j] = get_duration_value(line[j]); + m.durations[i][j] = get_duration_value(duration_line[j]); + m.distances[i][j] = get_distance_value(distance_line[j]); } } } diff --git a/src/routing/http_wrapper.h b/src/routing/http_wrapper.h index 91f668512..f6177ca95 100644 --- a/src/routing/http_wrapper.h +++ b/src/routing/http_wrapper.h @@ -56,9 +56,15 @@ class HttpWrapper : public Wrapper { virtual bool duration_value_is_null(const rapidjson::Value& matrix_entry) const = 0; + virtual bool + distance_value_is_null(const rapidjson::Value& matrix_entry) const = 0; + virtual UserDuration get_duration_value(const rapidjson::Value& matrix_entry) const = 0; + virtual UserDistance + get_distance_value(const rapidjson::Value& matrix_entry) const = 0; + virtual double get_total_distance(const rapidjson::Value& result) const = 0; virtual unsigned get_legs_number(const rapidjson::Value& result) const = 0; From 8609224af6ff33060a7a0f9030c5f82e7cb00ae6 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 17:05:46 +0200 Subject: [PATCH 15/22] Adjust osrm-routed wrapper for distances handling. --- src/routing/osrm_routed_wrapper.cpp | 11 +++++++++++ src/routing/osrm_routed_wrapper.h | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/src/routing/osrm_routed_wrapper.cpp b/src/routing/osrm_routed_wrapper.cpp index 98d901d18..4dc0a08f9 100644 --- a/src/routing/osrm_routed_wrapper.cpp +++ b/src/routing/osrm_routed_wrapper.cpp @@ -42,6 +42,7 @@ OsrmRoutedWrapper::build_query(const std::vector& locations, query += "?" + _routing_args; } else { assert(service == _matrix_service); + query += "?annotations=duration,distance"; } query += " HTTP/1.1\r\n"; @@ -65,11 +66,21 @@ bool OsrmRoutedWrapper::duration_value_is_null( return matrix_entry.IsNull(); } +bool OsrmRoutedWrapper::distance_value_is_null( + const rapidjson::Value& matrix_entry) const { + return matrix_entry.IsNull(); +} + UserDuration OsrmRoutedWrapper::get_duration_value( const rapidjson::Value& matrix_entry) const { return round_cost(matrix_entry.GetDouble()); } +UserDistance OsrmRoutedWrapper::get_distance_value( + const rapidjson::Value& matrix_entry) const { + return round_cost(matrix_entry.GetDouble()); +} + double OsrmRoutedWrapper::get_total_distance(const rapidjson::Value& result) const { return result["routes"][0]["distance"].GetDouble(); diff --git a/src/routing/osrm_routed_wrapper.h b/src/routing/osrm_routed_wrapper.h index 7c7a37de9..f57cd159a 100644 --- a/src/routing/osrm_routed_wrapper.h +++ b/src/routing/osrm_routed_wrapper.h @@ -25,9 +25,15 @@ class OsrmRoutedWrapper : public HttpWrapper { bool duration_value_is_null(const rapidjson::Value& matrix_entry) const override; + bool + distance_value_is_null(const rapidjson::Value& matrix_entry) const override; + UserDuration get_duration_value(const rapidjson::Value& matrix_entry) const override; + UserDistance + get_distance_value(const rapidjson::Value& matrix_entry) const override; + double get_total_distance(const rapidjson::Value& result) const override; unsigned get_legs_number(const rapidjson::Value& result) const override; From 640700247b1758c1326c70da5f7fbb75cfd83b33 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 17:07:47 +0200 Subject: [PATCH 16/22] Adjust ORS wrapper for distances handling. --- src/routing/ors_wrapper.cpp | 11 +++++++++++ src/routing/ors_wrapper.h | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/src/routing/ors_wrapper.cpp b/src/routing/ors_wrapper.cpp index b13b84cdd..e0f653d10 100644 --- a/src/routing/ors_wrapper.cpp +++ b/src/routing/ors_wrapper.cpp @@ -42,6 +42,7 @@ std::string OrsWrapper::build_query(const std::vector& locations, body += "," + _routing_args; } else { assert(service == _matrix_service); + body += ",\"metrics\":[\"duration\",\"distance\"]"; } body += "}"; @@ -72,11 +73,21 @@ bool OrsWrapper::duration_value_is_null( return matrix_entry.IsNull(); } +bool OrsWrapper::distance_value_is_null( + const rapidjson::Value& matrix_entry) const { + return matrix_entry.IsNull(); +} + UserDuration OrsWrapper::get_duration_value(const rapidjson::Value& matrix_entry) const { return round_cost(matrix_entry.GetDouble()); } +UserDistance +OrsWrapper::get_distance_value(const rapidjson::Value& matrix_entry) const { + return round_cost(matrix_entry.GetDouble()); +} + double OrsWrapper::get_total_distance(const rapidjson::Value& result) const { return result["routes"][0]["summary"]["distance"].GetDouble(); } diff --git a/src/routing/ors_wrapper.h b/src/routing/ors_wrapper.h index 426a2a390..ae6656e8a 100644 --- a/src/routing/ors_wrapper.h +++ b/src/routing/ors_wrapper.h @@ -25,9 +25,15 @@ class OrsWrapper : public HttpWrapper { bool duration_value_is_null(const rapidjson::Value& matrix_entry) const override; + bool + distance_value_is_null(const rapidjson::Value& matrix_entry) const override; + UserDuration get_duration_value(const rapidjson::Value& matrix_entry) const override; + UserDistance + get_distance_value(const rapidjson::Value& matrix_entry) const override; + double get_total_distance(const rapidjson::Value& result) const override; unsigned get_legs_number(const rapidjson::Value& result) const override; From 7f3a68e394545518c2fe3996c8c8eb42e2048536 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 17:14:22 +0200 Subject: [PATCH 17/22] Adjust Valhalla wrapper for distances handling. --- src/routing/valhalla_wrapper.cpp | 13 +++++++++++++ src/routing/valhalla_wrapper.h | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/src/routing/valhalla_wrapper.cpp b/src/routing/valhalla_wrapper.cpp index c8e3f83fe..335820375 100644 --- a/src/routing/valhalla_wrapper.cpp +++ b/src/routing/valhalla_wrapper.cpp @@ -124,12 +124,25 @@ bool ValhallaWrapper::duration_value_is_null( return matrix_entry["time"].IsNull(); } +bool ValhallaWrapper::distance_value_is_null( + const rapidjson::Value& matrix_entry) const { + assert(matrix_entry.HasMember("distance")); + return matrix_entry["distance"].IsNull(); +} + UserDuration ValhallaWrapper::get_duration_value( const rapidjson::Value& matrix_entry) const { assert(matrix_entry["time"].IsUint()); return matrix_entry["time"].GetUint(); } +UserDistance ValhallaWrapper::get_distance_value( + const rapidjson::Value& matrix_entry) const { + assert(matrix_entry["distance"].IsDouble()); + return round_cost(km_to_m * + matrix_entry["distance"].GetDouble()); +} + double ValhallaWrapper::get_total_distance(const rapidjson::Value& result) const { return km_to_m * result["trip"]["summary"]["length"].GetDouble(); diff --git a/src/routing/valhalla_wrapper.h b/src/routing/valhalla_wrapper.h index 06fa9a5be..4644b072b 100644 --- a/src/routing/valhalla_wrapper.h +++ b/src/routing/valhalla_wrapper.h @@ -29,9 +29,15 @@ class ValhallaWrapper : public HttpWrapper { bool duration_value_is_null(const rapidjson::Value& matrix_entry) const override; + bool + distance_value_is_null(const rapidjson::Value& matrix_entry) const override; + UserDuration get_duration_value(const rapidjson::Value& matrix_entry) const override; + UserDistance + get_distance_value(const rapidjson::Value& matrix_entry) const override; + double get_total_distance(const rapidjson::Value& result) const override; unsigned get_legs_number(const rapidjson::Value& result) const override; From 894551b05bbc4746d347b6c1f8286ff99d00ff55 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 17:18:51 +0200 Subject: [PATCH 18/22] Remove logging matrices. --- src/structures/vroom/input/input.cpp | 41 ---------------------------- 1 file changed, 41 deletions(-) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index 248a35921..11c38ad23 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -988,47 +988,6 @@ Solution Input::solve(unsigned exploration_level, set_matrices(nb_thread); set_vehicles_costs(); - // for (const auto& profile : _profiles) { - // std::cout << "* Durations matrix for profile " << profile << std::endl; - // assert(_durations_matrices.find(profile) != _durations_matrices.end()); - // const auto& duration_m = _durations_matrices.find(profile)->second; - - // for (std::size_t i = 0; i < duration_m.size(); ++i) { - // for (std::size_t j = 0; j < duration_m.size(); ++j) { - // std::cout << duration_m[i][j] << "\t"; - // } - // std::cout << std::endl; - // } - - // if (_distances_matrices.find(profile) != _distances_matrices.end()) { - // std::cout << "* Distances matrix for profile " << profile << std::endl; - - // const auto& distance_m = _distances_matrices.find(profile)->second; - - // for (std::size_t i = 0; i < distance_m.size(); ++i) { - // for (std::size_t j = 0; j < distance_m.size(); ++j) { - // std::cout << distance_m[i][j] << "\t"; - // } - // std::cout << std::endl; - // } - // } - - // if (_costs_matrices.find(profile) != _costs_matrices.end()) { - // std::cout << "* Costs matrix for profile " << profile << std::endl; - - // const auto& distance_m = _costs_matrices.find(profile)->second; - - // for (std::size_t i = 0; i < distance_m.size(); ++i) { - // for (std::size_t j = 0; j < distance_m.size(); ++j) { - // std::cout << distance_m[i][j] << "\t"; - // } - // std::cout << std::endl; - // } - // } - // } - - // exit(0); - // Fill vehicle/job compatibility matrices. set_skills_compatibility(); set_extra_compatibility(); From b8921346b668d9a7fac35feb124fe6ae05a36205 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Thu, 3 Aug 2023 17:20:23 +0200 Subject: [PATCH 19/22] Mention storing distances matrices in changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28d3dcc6e..164a07279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added - Recommendation on how to cite in publications (#943) +- Store distance matrices (#956) ### Changed From 3fa74e073629e65aaa555440c92a5203d14a2dd1 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Sat, 12 Aug 2023 11:27:05 +0200 Subject: [PATCH 20/22] Update comment in HttpWrapper::get_matrices. --- src/routing/http_wrapper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routing/http_wrapper.cpp b/src/routing/http_wrapper.cpp index 52c3397f0..99a87f06a 100644 --- a/src/routing/http_wrapper.cpp +++ b/src/routing/http_wrapper.cpp @@ -167,8 +167,8 @@ Matrices HttpWrapper::get_matrices(const std::vector& locs) const { } assert(json_result[_matrix_distances_key.c_str()].Size() == m_size); - // Build matrix while checking for unfound routes ('null' values) to - // avoid unexpected behavior. + // Build matrices while checking for unfound routes ('null' values) + // to avoid unexpected behavior. Matrices m(m_size); std::vector nb_unfound_from_loc(m_size, 0); From 1d1e0d41780f81e7326fdfcc9be79b3b83b03959 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Sat, 12 Aug 2023 11:27:55 +0200 Subject: [PATCH 21/22] Remove unused include. --- src/structures/vroom/input/input.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index 11c38ad23..c01826561 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -7,8 +7,6 @@ All rights reserved (see LICENSE). */ -#include - #include #include From 249a468ce69a499bbe1967df6e0d49c4c866f2df Mon Sep 17 00:00:00 2001 From: jcoupey Date: Sat, 12 Aug 2023 11:48:04 +0200 Subject: [PATCH 22/22] Add missing error for location_index over distances matrix size. --- src/structures/vroom/input/input.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index c01826561..bcfda1b25 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -852,9 +852,11 @@ void Input::set_matrices(unsigned nb_thread) { // Required matrices not manually set have been defined as // empty above. assert(durations_m != _durations_matrices.end()); - bool define_durations = (durations_m->second.size() == 0); - bool define_distances = (distances_m != _distances_matrices.end()) and - (distances_m->second.size() == 0); + const bool define_durations = (durations_m->second.size() == 0); + const bool has_distance_matrix = + (distances_m != _distances_matrices.end()); + const bool define_distances = + has_distance_matrix and (distances_m->second.size() == 0); if (define_durations or define_distances) { if (_locations.size() == 1) { durations_m->second = Matrix(1); @@ -910,16 +912,25 @@ void Input::set_matrices(unsigned nb_thread) { } if (durations_m->second.size() <= _max_matrices_used_index) { - throw InputException("location_index exceeding matrix size for " + - profile + " profile."); + throw InputException( + "location_index exceeding durations matrix size for " + profile + + " profile."); + } + + if (has_distance_matrix and + distances_m->second.size() <= _max_matrices_used_index) { + throw InputException( + "location_index exceeding distances matrix size for " + profile + + " profile."); } const auto c_m = _costs_matrices.find(profile); if (c_m != _costs_matrices.end()) { if (c_m->second.size() <= _max_matrices_used_index) { - throw InputException("location_index exceeding matrix size for " + - profile + " profile."); + throw InputException( + "location_index exceeding costs matrix size for " + profile + + " profile."); } // Check for potential overflow in solution cost.