-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support rectangular matrix with less sources than targets #1760
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,24 +70,34 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin | |
int HandleRequest(const RouteParameters &route_parameters, | ||
osrm::json::Object &json_result) override final | ||
{ | ||
if (!check_all_coordinates(route_parameters.coordinates)) | ||
const bool useSameTgtSrc = route_parameters.coordinates.size() ? true : false; | ||
if ((useSameTgtSrc && route_parameters.destinations.size()) || (useSameTgtSrc && route_parameters.sources.size())) | ||
{ | ||
return 400; | ||
} | ||
|
||
if ((useSameTgtSrc && !check_all_coordinates(route_parameters.coordinates)) || | ||
(!useSameTgtSrc && !check_all_coordinates(route_parameters.destinations, 2) && !check_all_coordinates(route_parameters.sources, 1))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
{ | ||
return 400; | ||
} | ||
|
||
const auto &input_bearings = route_parameters.bearings; | ||
if (input_bearings.size() > 0 && route_parameters.coordinates.size() != input_bearings.size()) | ||
unsigned nb_coordinates = useSameTgtSrc ? route_parameters.coordinates.size() : (route_parameters.destinations.size() + route_parameters.sources.size()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if (input_bearings.size() > 0 && nb_coordinates != input_bearings.size()) | ||
{ | ||
json_result.values["status"] = "Number of bearings does not match number of coordinates ."; | ||
return 400; | ||
} | ||
|
||
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); | ||
unsigned max_locations = | ||
unsigned max_locations = useSameTgtSrc ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess it would be cleaner to just return if (number_of_sources*number_of_destinations > max_locations_distance_table*max_locations_distance_table)
{
json_result.values["status_message"] = std::string("Table exceeds maximum number of entries of ") + std::to_string(max_locations_distance_table*max_locations_distance_table);
return 400;
} Where |
||
std::min(static_cast<unsigned>(max_locations_distance_table), | ||
static_cast<unsigned>(route_parameters.coordinates.size())) : | ||
std::min(static_cast<unsigned>(max_locations_distance_table), | ||
static_cast<unsigned>(route_parameters.coordinates.size())); | ||
static_cast<unsigned>(route_parameters.destinations.size())); | ||
|
||
PhantomNodeArray phantom_node_vector(max_locations); | ||
PhantomNodeArray phantom_node_target_vector(max_locations); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
for (const auto i : osrm::irange(0u, max_locations)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can move this loop to a utility function and like this: GetCoordinates(const std::vector<FixedPointCoordinate>& inputs, PhantomNodeArray& output)
{
....
} The code should then look somethings like: GetCoordinates(route_parameters.coordinates, phantom_node_vector);
std::insert(phantom_node_source_vector.end(), phantom_node_vector.begin(), phantom_node_vector.end());
std::insert(phantom_node_destination_vector.end(), phantom_node_vector.begin(), phantom_node_vector.end());
GetCoordinates(route_parameters.sources, phantom_node_source_vector);
GetCoordinates(route_parameters.destinations, phantom_node_destination_vector); |
||
{ | ||
if (checksum_OK && i < route_parameters.hints.size() && | ||
|
@@ -97,39 +107,91 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin | |
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node); | ||
if (current_phantom_node.is_valid(facade->GetNumberOfNodes())) | ||
{ | ||
phantom_node_vector[i].emplace_back(std::move(current_phantom_node)); | ||
phantom_node_target_vector[i].emplace_back(std::move(current_phantom_node)); | ||
continue; | ||
} | ||
} | ||
const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0; | ||
const int range = input_bearings.size() > 0 ? (input_bearings[i].second?*input_bearings[i].second:10) : 180; | ||
facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], | ||
phantom_node_vector[i], 1, bearing, range); | ||
facade->IncrementalFindPhantomNodeForCoordinate(useSameTgtSrc ? route_parameters.coordinates[i] : route_parameters.destinations[i], | ||
phantom_node_target_vector[i], 1, bearing, range); | ||
|
||
BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes())); | ||
BOOST_ASSERT(phantom_node_target_vector[i].front().is_valid(facade->GetNumberOfNodes())); | ||
} | ||
unsigned shift_coordinates = (useSameTgtSrc) ? 0 : route_parameters.destinations.size(); | ||
max_locations = 0; | ||
if (!useSameTgtSrc) | ||
{ | ||
max_locations = std::min(static_cast<unsigned>(max_locations_distance_table), | ||
static_cast<unsigned>(route_parameters.sources.size())); | ||
} | ||
PhantomNodeArray phantom_node_source_vector(max_locations); | ||
for (const auto i : osrm::irange(0u, max_locations)) | ||
{ | ||
if (checksum_OK && i < route_parameters.hints.size() - shift_coordinates && | ||
!route_parameters.hints[i + shift_coordinates].empty()) | ||
{ | ||
PhantomNode current_phantom_node; | ||
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i + shift_coordinates], current_phantom_node); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We sadly need to drop |
||
if (current_phantom_node.is_valid(facade->GetNumberOfNodes())) | ||
{ | ||
phantom_node_source_vector[i].emplace_back(std::move(current_phantom_node)); | ||
continue; | ||
} | ||
} | ||
const int bearing = input_bearings.size() > 0 ? input_bearings[i + shift_coordinates].first : 0; | ||
const int range = input_bearings.size() > 0 ? (input_bearings[i + shift_coordinates].second?*input_bearings[i + shift_coordinates].second:10) : 180; | ||
facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.sources[i], | ||
phantom_node_source_vector[i], 1, bearing, range); | ||
|
||
BOOST_ASSERT(phantom_node_source_vector[i].front().is_valid(facade->GetNumberOfNodes())); | ||
} | ||
|
||
// TIMER_START(distance_table); | ||
std::shared_ptr<std::vector<EdgeWeight>> result_table = | ||
search_engine_ptr->distance_table(phantom_node_vector); | ||
search_engine_ptr->distance_table(phantom_node_target_vector, phantom_node_source_vector); | ||
// TIMER_STOP(distance_table); | ||
|
||
if (!result_table) | ||
{ | ||
return 400; | ||
} | ||
|
||
osrm::json::Array json_array; | ||
const auto number_of_locations = phantom_node_vector.size(); | ||
for (const auto row : osrm::irange<std::size_t>(0, number_of_locations)) | ||
osrm::json::Array matrix_json_array; | ||
const auto number_of_targets = phantom_node_target_vector.size(); | ||
const auto number_of_sources = (phantom_node_source_vector.size()) ? phantom_node_source_vector.size() : number_of_targets; | ||
for (const auto row : osrm::irange<std::size_t>(0, number_of_sources)) | ||
{ | ||
osrm::json::Array json_row; | ||
auto row_begin_iterator = result_table->begin() + (row * number_of_locations); | ||
auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_locations); | ||
auto row_begin_iterator = result_table->begin() + (row * number_of_targets); | ||
auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_targets); | ||
json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator); | ||
json_array.values.push_back(json_row); | ||
matrix_json_array.values.push_back(json_row); | ||
} | ||
json_result.values["distance_table"] = matrix_json_array; | ||
if (route_parameters.mapped_points) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove if, since the parameters needs to be dropped. (Code in general is fine.) I would go with |
||
osrm::json::Array target_coord_json_array; | ||
for (const std::vector<PhantomNode> &phantom_node_vector : phantom_node_target_vector) | ||
{ | ||
osrm::json::Array json_coord; | ||
FixedPointCoordinate coord = phantom_node_vector[0].location; | ||
json_coord.values.push_back(coord.lat / COORDINATE_PRECISION); | ||
json_coord.values.push_back(coord.lon / COORDINATE_PRECISION); | ||
target_coord_json_array.values.push_back(json_coord); | ||
} | ||
json_result.values["target_mapped_coordinates"] = target_coord_json_array; | ||
osrm::json::Array source_coord_json_array; | ||
for (const std::vector<PhantomNode> &phantom_node_vector : phantom_node_source_vector) | ||
{ | ||
osrm::json::Array json_coord; | ||
FixedPointCoordinate coord = phantom_node_vector[0].location; | ||
json_coord.values.push_back(coord.lat / COORDINATE_PRECISION); | ||
json_coord.values.push_back(coord.lon / COORDINATE_PRECISION); | ||
source_coord_json_array.values.push_back(json_coord); | ||
} | ||
if (source_coord_json_array.values.size()) | ||
json_result.values["source_mapped_coordinates"] = source_coord_json_array; | ||
} | ||
json_result.values["distance_table"] = json_array; | ||
// osrm::json::render(reply.content, json_object); | ||
return 200; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,9 +45,9 @@ class BasePlugin | |
virtual const std::string GetDescriptor() const = 0; | ||
virtual int HandleRequest(const RouteParameters &, osrm::json::Object &) = 0; | ||
virtual bool | ||
check_all_coordinates(const std::vector<FixedPointCoordinate> &coordinates) const final | ||
check_all_coordinates(const std::vector<FixedPointCoordinate> &coordinates, const unsigned min = 2) const final | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove the min check here. Should be handled on caller side. |
||
{ | ||
if (2 > coordinates.size() || std::any_of(std::begin(coordinates), std::end(coordinates), | ||
if (min > coordinates.size() || std::any_of(std::begin(coordinates), std::end(coordinates), | ||
[](const FixedPointCoordinate &coordinate) | ||
{ | ||
return !coordinate.is_valid(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,11 +67,12 @@ class ManyToManyRouting final | |
~ManyToManyRouting() {} | ||
|
||
std::shared_ptr<std::vector<EdgeWeight>> | ||
operator()(const PhantomNodeArray &phantom_nodes_array) const | ||
operator()(const PhantomNodeArray &phantom_targets_array, const PhantomNodeArray &phantom_sources_array = PhantomNodeArray(0)) const | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't provide default values here. Parameter order should be |
||
{ | ||
const auto number_of_locations = phantom_nodes_array.size(); | ||
const auto number_of_targets = phantom_targets_array.size(); | ||
const auto number_of_sources = (phantom_sources_array.size()) ? phantom_sources_array.size() : number_of_targets; | ||
std::shared_ptr<std::vector<EdgeWeight>> result_table = | ||
std::make_shared<std::vector<EdgeWeight>>(number_of_locations * number_of_locations, | ||
std::make_shared<std::vector<EdgeWeight>>(number_of_targets * number_of_sources, | ||
std::numeric_limits<EdgeWeight>::max()); | ||
|
||
engine_working_data.InitializeOrClearFirstThreadLocalStorage( | ||
|
@@ -82,7 +83,7 @@ class ManyToManyRouting final | |
SearchSpaceWithBuckets search_space_with_buckets; | ||
|
||
unsigned target_id = 0; | ||
for (const std::vector<PhantomNode> &phantom_node_vector : phantom_nodes_array) | ||
for (const std::vector<PhantomNode> &phantom_node_vector : phantom_targets_array) | ||
{ | ||
query_heap.Clear(); | ||
// insert target(s) at distance 0 | ||
|
@@ -113,7 +114,7 @@ class ManyToManyRouting final | |
|
||
// for each source do forward search | ||
unsigned source_id = 0; | ||
for (const std::vector<PhantomNode> &phantom_node_vector : phantom_nodes_array) | ||
for (const std::vector<PhantomNode> &phantom_node_vector : (phantom_sources_array.size() ? phantom_sources_array : phantom_targets_array)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should not have a switch. Always use |
||
{ | ||
query_heap.Clear(); | ||
for (const PhantomNode &phantom_node : phantom_node_vector) | ||
|
@@ -136,13 +137,13 @@ class ManyToManyRouting final | |
// explore search space | ||
while (!query_heap.Empty()) | ||
{ | ||
ForwardRoutingStep(source_id, number_of_locations, query_heap, | ||
ForwardRoutingStep(source_id, number_of_targets, query_heap, | ||
search_space_with_buckets, result_table); | ||
} | ||
|
||
++source_id; | ||
} | ||
BOOST_ASSERT(source_id == target_id); | ||
// BOOST_ASSERT(source_id == target_id); | ||
return result_table; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove the
mapped_points
parameter entirely. It has no significant implications on size or performance. I'm only talking about the parameter for the API not the feature as such - it should just be the normal behavior and not user configurable.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This as option was made to avoid network transfer of data, if not needed by client. With huge matrix in mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For really huge matrices you should avoid going over the network (uncompressed) anyway. You can take a look at our
node-osrm
bindings. Since this is all 100% numerical values you can get a way with about 4 bytes per entry (just save the raw matrix and the size).