-
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
Trip with Fixed Start and End points (TFSE) #3408
Conversation
dd8b537
to
0e76783
Compare
cccaf3b
to
3b296fe
Compare
3b296fe
to
653fc54
Compare
0138488
to
de7f762
Compare
de7f762
to
038fc66
Compare
038fc66
to
b3410ee
Compare
Capturing from chat today: The complexity seems quite high with the approach of creating the An alternative could be just to munge certain values in the Of course, with any heuristic, it's possible that we'd calculate a result that includes an @chaupow Thoughts on the above? The creation of the |
If I'm not wrong, this should work as well and result in the same effect of forcing a round trip that visits A after D. Also, Julien from vroom does the same #1623 (comment) I'm 👍 |
This is the table that @danpat and I came up with from our conversation. Putting it here for the record as I work through the cucumber test scenarios that use this and so that everyone is on the same page about new table. source: a. destination: c. original table:
manipulated table:
|
0abc87f
to
f45d9b3
Compare
d38a71d
to
a2364bd
Compare
src/engine/plugins/trip.cpp
Outdated
// parameters.source column | ||
if (f_counter % result_table.GetNumberOfNodes() == (unsigned long)parameters.source) | ||
{ | ||
tfse_table_[f_counter] = std::numeric_limits<EdgeWeight>::max(); |
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.
Given that the FI and BruteForce searches are looking for INVALID_EDGE_WEIGHT
, that's what you should set here, not ::max()
. Practically, they're the same thing, but if the INvALID_EDGE_WEIGHT
value changes for some reason, the if()
logic later on will break.
src/engine/plugins/trip.cpp
Outdated
f_counter < result_table.GetNumberOfNodes() * parameters.destination + | ||
result_table.GetNumberOfNodes()) | ||
{ | ||
tfse_table_[f_counter] = std::numeric_limits<EdgeWeight>::max(); |
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.
Same here.
src/engine/plugins/trip.cpp
Outdated
tfse_table_[parameters.destination * result_table.GetNumberOfNodes() + | ||
parameters.destination] = 0; | ||
tfse_table_[parameters.source * result_table.GetNumberOfNodes() + parameters.destination] = | ||
std::numeric_limits<EdgeWeight>::max(); |
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.
And here.
@ghoshkaj For routes >10 waypoints, we will need to make the same logic change to the FarthestInsertion algorithm that got made to BruteForce. A test for that scenario would be great too. |
e8c6c9b
to
adc5e22
Compare
docs/http.md
Outdated
@@ -329,6 +330,30 @@ In addition to the [general options](#general-options) the following options are | |||
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) | | |||
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.| | |||
|
|||
A second feature of the trip plugin returns the optimal route from a source to a destination while visiting all the other input locations in the middle. | |||
As with the roundtrip service, for locations 10 nodes of less, the brute force algorithm is used, while for more than 10 nodes, the farthest insertion heuristic is used. |
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 fewer than 10 waypoints, the brute force algorithm is used, while for more than 10 waypoints ..."
docs/http.md
Outdated
|
||
|Element |Values | | ||
|------------|-----------------------------| | ||
|index |`0 <= integer < #locations` | |
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.
either coordinates
or waypoints
, not locations
features/testbot/trip.feature
Outdated
|
||
Scenario: Testbot - Trip planning with illegal source | ||
Given the query options | ||
| source | 10 | |
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.
source
and destination
should be columns in the "When I plan a trip I should get" columns, not a separate "Given", allowing per-query adjustment. This will allow some consolidation of these test cases.
3d96909
to
dd174c4
Compare
docs/http.md
Outdated
@@ -311,7 +311,7 @@ All other properties might be undefined. | |||
|
|||
### Trip service | |||
|
|||
The trip plugin solves the Traveling Salesman Problem using a greedy heuristic (farthest-insertion algorithm). | |||
The trip plugin solves the Traveling Salesman Problem using a greedy heuristic (farthest-insertion algorithm) for more than ten nodes and uses brute force for 10 nodes or less. |
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.
That's not true: < 10 is brute force
osrm-backend/src/engine/plugins/trip.cpp
Line 209 in b3ef27d
if (component_size < BF_MAX_FEASABLE) |
docs/http.md
Outdated
@@ -329,6 +329,30 @@ In addition to the [general options](#general-options) the following options are | |||
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) | | |||
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.| | |||
|
|||
A second feature of the trip plugin returns the route from a source to a destination while visiting all the other waypoints in the middle. | |||
As with the roundtrip service, for fewer than 10 waypoints, the brute force algorithm is used, while for more than 10 waypoints the farthest insertion heuristic is used. |
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.
Same here:
- < 10 brute force
- >= 10 farthest insertion
docs/http.md
Outdated
|
||
|Option |Values |Description | | ||
|------------|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| | ||
|source |`{index of coordinate in coordinates provided}` |Will error if destionation is not provided as well. Returns trip from source to destination routing through all other locations provided.| |
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.
destination - grammar
@@ -35,11 +34,12 @@ module.exports = function () { | |||
} | |||
|
|||
if (headers.has('status')) { | |||
got.status = json.status.toString(); | |||
got.status = json.code; |
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.
Why the change from the status message to the error code here?
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.
The status.toString() code was copy pasted from another cucumber test but wasn't really being used in the trip context (it was broken code essentially with no way to trigger it to check), so I changed it so that it does work.
features/testbot/trip.feature
Outdated
|
||
When I plan a trip I should get | ||
| waypoints | status | message | | ||
| a,b,c | InvalidInputs | Source or destination indices are greater number of coordinates provided. | |
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.
All these tests should be unit tests - check the unit tests dir and the library tests there, e.g. for route.
include/util/dist_table_wrapper.hpp
Outdated
@@ -46,6 +46,30 @@ template <typename T> class DistTableWrapper | |||
return table_[index]; | |||
} | |||
|
|||
void InvalidateRoute(NodeID from, NodeID to) |
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.
The wrapper holds T
s so you probably should accept T
s to index the vector.
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.
The DistTableWrapper is a wrapper around a vector that holds , in the trip case the is an EdgeWeight. This method here simply accepts NodeIDs to access the correct position of the necessary EdgeWeight in the table vector of EdgeWeights. So keeping the function as-is should be fine in this case.
src/engine/plugins/trip.cpp
Outdated
if (parameters.source >= static_cast<int>(parameters.coordinates.size()) || | ||
parameters.destination >= static_cast<int>(parameters.coordinates.size())) | ||
{ | ||
return Error("InvalidInputs", |
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.
Not a documented v5 error code.
src/engine/plugins/trip.cpp
Outdated
// b 10000 0 25 30 34 | ||
// c 0 10000 0 10000 10000 | ||
// d 10000 30 18 0 15 | ||
// e 10000 34 32 15 0 |
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.
So what does it do?
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.
also, replace the 10000
with MAX_DISTANCE
or something in that manner :)
src/engine/plugins/trip.cpp
Outdated
{ | ||
// parameters.source column | ||
for (NodeID i = 0; i < result_table.GetNumberOfNodes(); i++) { | ||
if (i == (NodeID)parameters.source) continue; |
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.
format all files you're touching
BOOST_CHECK_EQUAL(reference_2.source, result_2->source); | ||
BOOST_CHECK_EQUAL(reference_2.destination, result_2->destination); | ||
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses); | ||
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates); |
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.
More tests please. For parsing but also library tests for responses.
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.
other unit tests we should have and cover for:
source == destination
source == -1 && destination != -1
source != -1 && destination == -1
dd174c4
to
dda3ba3
Compare
CHANGELOG.md
Outdated
@@ -27,6 +27,8 @@ | |||
- libOSRM now creates an own watcher thread then used in shared memory mode to listen for data updates | |||
- Tools: | |||
- Added osrm-extract-conditionals tool for checking conditional values in OSM data | |||
- Trip Plugin | |||
- Added a new feature that finds the optimal route given a list of location, a start and destination locations. This does not return a roundtrip, but instead gives the optimal route given fixed start and end points |
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.
given a list of locations, a start and a destination
or something like that? looks like a typo :D
src/engine/plugins/trip.cpp
Outdated
{ | ||
// trip comes out to be something like 0 1 4 3 2, so the sizes don't | ||
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size() - 1); | ||
} |
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.
better write this such that there are no if/else
checks when in release mode:
A statement a -> b
can be checked with !a || b
instead, so do
BOOST_ASSERT(!roundtrip || min_route.segment_end_coordinates.size() == trip.size());
BOOST_ASSERT(roundtrip || min_route.segment_end_coordinates.size() == trip.size() - 1);
or something like that
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.
I did this, but it got a bit confusing for &&
/ ||
noobs like me to keep the logic straight. So I reverted back to the if statements for clarity and simplicity's sake.
src/engine/plugins/trip.cpp
Outdated
// b 10000 0 25 30 34 | ||
// c 0 10000 0 10000 10000 | ||
// d 10000 30 18 0 15 | ||
// e 10000 34 32 15 0 |
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.
also, replace the 10000
with MAX_DISTANCE
or something in that manner :)
BOOST_CHECK_EQUAL(reference_2.source, result_2->source); | ||
BOOST_CHECK_EQUAL(reference_2.destination, result_2->destination); | ||
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses); | ||
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates); |
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.
other unit tests we should have and cover for:
source == destination
source == -1 && destination != -1
source != -1 && destination == -1
include/util/dist_table_wrapper.hpp
Outdated
table_[index] = INVALID_EDGE_WEIGHT; | ||
} | ||
|
||
void ShortcutRoute(NodeID from, NodeID to) |
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.
I'm not totally convinced that ShortcutRoute
and InvalidateRoute
are good names. If you want to keep them more general as they are now, can you add a comment why we do this here? so something like
force the roundtrip to start at source and end at destination by virtually squashing them together
or you can maybe name them squashSourceAndDestination
and separateDestination
src/engine/plugins/trip.cpp
Outdated
SCC_Component scc = SplitUnaccessibleLocations(number_of_locations, result_table); | ||
SCC_Component scc = SplitUnaccessibleLocations(result_table.GetNumberOfNodes(), result_table); | ||
|
||
if (parameters.source > -1 && parameters.destination > -1) // check if fixed start and end |
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.
later you're checking this to set bool roundtrip
. you could also set the boolean already here and use it.
Tasks for |
53ef7ed
to
ab5965b
Compare
012a362
to
a9ee2e3
Compare
To Do (@chaupow if you want to get started on any of these)
|
ef27628
to
213423e
Compare
All the comments have been addressed
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.
Some minor naming and style adjustment. Otherwise 💯
docs/http.md
Outdated
|
||
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes. | ||
It is possible to explicitely set the start or end point of the trip. Depending on whether `source` or `destination` is set to `any|first` or `any|last` the resulting output will start/end at the first/last coordinate. |
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.
What about making it a little bit more explicit:
When
source
is set tofirst
the first coordinate is used as source of the trip. Whendestination
is set tolast
the last coordinate will be used as destination of the trip. If you specifyany
, any of the coordinates can be used.
docs/http.md
Outdated
|
||
However, if `source=any&destination=any` the returned round-trip will still start at the first coordinate by default. | ||
|
||
Currently, not all combinations of roundtrip, source and destination are supported. |
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.
source
, roudtrip
and destination
should be put in code blocks.
features/testbot/trip.feature
Outdated
| la | | ||
|
||
When I plan a trip I should get | ||
| waypoints | trips | source | |
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.
Why is source
a result column? This should be a query parameter like in https://github.com/Project-OSRM/osrm-backend/pull/3408/files#diff-19534b2b92b1d620a3a6390c0f0b378dR100 no?
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.
@TheMarex I asked @ghoshkaj to move source
and desttinaion
into the I should get
table - they're query parameters in the same way that waypoints
are.
Having these in the When
table allows multiple combinations for the same scenario - putting them in the Given the query options
clause limits us to one set per scenario.
We should put them on the left-hand-side though, next to the waypoints.
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.
Note that there is precedence for this style in the testbot/matching.feature
where we supply timestamps.
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.
|
||
When I plan a trip I should get | ||
| waypoints | source | destination | roundtrip | status | message | | ||
| a,b,c,d | first | last | false | NoTrips | No trip visiting all destinations possible. | |
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.
Same here: source
and destination
should be query parameters not part of the 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.
Leaving this as is due to comment above.
| waypoints | trips | | ||
| a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p | defghijklabcd,mnopm | | ||
| waypoints | source | destination |roundtrip | trips | durations | distance | | ||
| a,b,d,e,c | first | last | false | abedc | 8.200000000000001 | 81.6 | |
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.
Same here.
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.
Leaving this as is due to comment above.
include/util/dist_table_wrapper.hpp
Outdated
@@ -46,6 +46,30 @@ template <typename T> class DistTableWrapper | |||
return table_[index]; | |||
} | |||
|
|||
void InvalidateRoute(NodeID from, NodeID to) |
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.
Should these functions be part of the DistTableWrapper
? This class seems very generic and the functions are only relevant in the context of the trip
plugin.
Another way to do it would be to have two functions invalidateRoute(DistanceTableWrapper &dist, NodeID from, NodeID to)
and shortcutRoute(DistanceTableWrapper &dist, NodeID from, NodeID to)
in the trip plugin.
include/util/typedefs.hpp
Outdated
@@ -60,6 +60,8 @@ using NameID = std::uint32_t; | |||
using EdgeWeight = std::int32_t; | |||
using TurnPenalty = std::int16_t; // turn penalty in 100ms units | |||
|
|||
static const std::size_t INVALID_SIZE_T = std::numeric_limits<std::size_t>::max(); |
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.
INVALID_INDEX
would probably be a more fitting name, since that is what it is used to denote in the using code.
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.
HAHAHA. True. Thanks. invalid_size_t is wrong indeed
src/engine/plugins/trip.cpp
Outdated
} | ||
bool fixed_start = (source_id == 0); | ||
bool fixed_end = (destination_id == number_of_locations - 1); | ||
bool fixed_start_and_end = fixed_start && fixed_end; |
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.
It might be less confusing to not pre-compute fixed_start_and_end
, because in the code below it was not clear if this is somehow different then fixed_start && fixed_end
.
src/engine/plugins/trip.cpp
Outdated
routes.reserve(trips.size()); | ||
for (const auto &trip : trips) | ||
// rotate result such that roundtrip starts at node with index 0 | ||
if (!(fixed_end && !fixed_start_and_end)) |
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.
Same as !fixed_end || fixed_start_and_end
== !fixed_end && fixed_start || !fixed_end && fixed_end
== fixed_start && !fixed_end
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.
!(fixed_end && !fixed_start_and_end)
== !fixed_end || fixed_start_and_end
== !fixed_end || (fixed_start && fixed_end)
== (!fixed_end || fixed_start) && (!fixed_end || fixed_end)
== !fixed_end || fixed_start
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.
No !fixed_end || fixed_start_and_end == !fixed_end || (fixed_start && fixed_end)
is wrong from my comment above. Ugh it's so late, I can't keep the logic straight :/
In any case, using fixed_start && !fixed_end
from Patrick's comment makes a test fail :/
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.
While using !fixed_end || fixed_start
lets them all pass.
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.
hm, can it be simplified? There are only 16 2-variable boolean functions
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.
Okay no matter how many times I work it out, I always get to !fixed_end || fixed_start
and this lets the tests pass happily so this is what I'll keep it as.
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.
Realistically, what this case is taking care of are the following scenarios:
!fixed_end
OR
fixed_start
OR
fixed_start && fixed_end
so I'll either write all these cases out or comment with this.
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.
!fixed_end || fixed_start
is the same as !fixed_end OR fixed_start OR fixed_start && fixed_end
, because fixed_start OR fixed_start && fixed_end
is equal to fixed_start
src/engine/plugins/trip.cpp
Outdated
} | ||
else if (fixed_end && !fixed_start_and_end && parameters.roundtrip) |
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.
Same as fixed_end && !fixed_start && parameters.roundtrip
25e2451
to
fb85f93
Compare
34d676b
to
8971b5c
Compare
Issue
#1623
Tasklist
(We're going to implement @chaupow's algorithm described here)
(@chaupow and @TheMarex and I have settled on:
coordinates
: list of coordinatessource
: the index of the start coordinatedestination
: the index of the end coordinate )Code Review Checklist - author check these when done, reviewer verify
scripts/format.sh
If something doesn't apply, please
cross it outRequirements / Relations
Link any requirements here. Other pull requests this PR is based on?