-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
Via way restrictions #4255
Via way restrictions #4255
Conversation
cf5f718
to
9dc3c15
Compare
9dc3c15
to
177f0fc
Compare
features/car/restrictions.feature
Outdated
| ef | | ||
|
||
And the relations | ||
| type | way:from | way:via | way:from | restriction | |
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.
Here and below: shouldn't it be way:to
instead of way:from
twice?
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.
Of course.
include/extractor/restriction.hpp
Outdated
from.node = SPECIAL_NODEID; | ||
to.node = SPECIAL_NODEID; | ||
return flags.way_type ? boost::get<InputWayRestriction>(node_or_way).from | ||
: boost::get<InputNodeRestriction>(node_or_way).from; |
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 don't understand this construct - above we're using a variant but we're also storing flags? The variant already contains a flag and knows what actual type it is - I think you can use a visitor or a checked get call here.
include/extractor/restriction.hpp
Outdated
using value_type = InputRestrictionContainer; | ||
bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b) const | ||
boost::variant<NodeRestriction, WayRestriction> node_or_way; | ||
restriction_details::Bits flags; |
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 question 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.
This is an open change I have to do. I was originally using the normal structs that were in the data and only then switched to a true variant to avoid reinterpreting data over multiple types. Need to update that.
58946c6
to
07459e9
Compare
Demo Server: This PR: Relation in question: https://www.openstreetmap.org/relation/6495959#map=19/37.77034/-122.51128 |
012c2f8
to
29e0cc7
Compare
Impact so far on Baden Wuerttemberg: extraction stays more or less the same speed: without: with: Contraction measurements fluctuate quite a bit but do not show a consistent slowdown over current master branch. |
27cd3c7
to
6109840
Compare
6109840
to
6f81748
Compare
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.
left some early comments, didn't make it through completely today - will follow up tomorrow
|
||
And the relations | ||
| type | way:from | node:via | way:to | restriction | | ||
| restriction | abc | c | cgh | no_right_turn | |
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 happens if the via node is placed on a node that gets compressed? This should only ever be possible on degree-two intersections and then a restriction does not really make sense, no? What would happen in this case?
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.
We should just ignore them. I would consider these a mapping error to begin with and not worry about them.
Internally
a - b - c
and ab
via b
to bc
should turn out as ac
via b
to ac
after compression and be ignored as inconsistent.
a - b - c - - - - - - - - - - - - - - - - - - - f | ||
| | \ / | ||
i - d - e - - - - - - - - - - - - - - - - - | ||
""" |
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 long geometry 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 correct turn needs to be undesirable, even without the turn restrictions. Otherwise having multiple non-working restrictions could be hidden by the fact that the non-restricted path is better, based on turn penalties alone.
When I route I should get | ||
| from | to | route | | ||
| a | j | left,first,right,right | | ||
| f | e | right,third,left,left | |
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.
nice! ✨
|
||
And the relations | ||
| type | way:from | way:via | way:to | restriction | | ||
| restriction | ab | be | ef | only_left_on | |
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 is the behavior the same when I place a only_straight_on
for the turn onto ef
?
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 am not sure whether I follow, but yes. We evaluate only_*
without checking the postfix
. Just as we did for via-nodes.
|
||
And the relations | ||
| type | way:from | way:via | way:to | restriction | | ||
| restriction | ab | be | ed | only_right_on | |
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 question here
const std::string &cnbg_ebg_mapping_path); | ||
const std::string &cnbg_ebg_mapping_path, | ||
const RestrictionMap &restriction_map, | ||
const WayRestrictionMap &way_restriction_map); |
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 we name the RestrictionMap
into NodeRestrictionMap
then?
|
||
// the number of edge-based nodes is mostly made up out of the edges in the node-based graph. | ||
// Any edge in the node-based graph represents a node in the edge-based graph. In addition, we | ||
// add a set of artificial edge-based nodes into the mix to model via-way turn restrictions. |
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.
Could you (capitalize the T
:P and) add the ticket where we scoped out the idea behind via-way restrictions please
@@ -152,14 +157,16 @@ class EdgeBasedGraphFactory | |||
|
|||
unsigned RenumberEdges(); | |||
|
|||
std::vector<NBGToEBG> GenerateEdgeExpandedNodes(); | |||
std::vector<NBGToEBG> GenerateEdgeExpandedNodes(const WayRestrictionMap &way_restriction_map); |
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 is the semantic meaning behind passing the way restriction map to GenerateEdgeExpandedNodes
? Because it has to be aware of the artificial nodes? The idea here is not clear from the interface alone.
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.
Will document here. You are correct. EdgeExpandedNodes has to generate all our duplicated nodes as well. Therefor it requires access to the way-restriction-map.
const std::string &turn_penalties_index_filename); | ||
const std::string &turn_penalties_index_filename, | ||
const RestrictionMap &restriction_map, | ||
const WayRestrictionMap &way_restriction_map); |
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 - why do we need the maps for edge expanded edge generation? Should this be refactored?
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.
Before they were stored as members and used within. We require the maps to check which turns are allowed. The intersection-generation / handling of via-way restrictions is required when looking at the edge-based-edges to find out which of the turns are valid (entry_allowed
flag).
I just moved this to a reference parameter to get rid of some pointer usage we did beforehand.
unsigned max_internal_node_id; | ||
|
||
// list of restrictions before we transform them into the output types | ||
std::vector<InputConditionalTurnRestriction> restrictions_list; |
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.
With output types you mean the turn restriction vectors below? Why do we need to store both input and output then?
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.
Input restrictions are generated during parsing and store OSM IDs. Only after we performed our re-mapping, we can assign the actual restrictions to be used later on.
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.
Most of the comments are duplicates that target the usage of lambda functions. The yoda-style (how before the what) of declaring them first and referencing them later makes it hard for me to follow the control flow, especially while reviewing, which is super frustrating. Please keep this in mind the future.
The approach is sound! I would be interested in some empirical measurements of graph size increase, just so we know what we are dealing here with. 👍
Q.A. wise I would love to see some sanity checks on California w.r.t to processing time, just to make sure we will not see unexpected results.
|
||
When I route I should get | ||
| from | to | route | | ||
| a | d | ab,be,ef,ef,de,de | |
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.
Sometimes it's helpful to include an extra comment column to explain what each row is testing. For example does not use turn ab,be,de
or something like that.
include/extractor/restriction.hpp
Outdated
@@ -5,111 +5,274 @@ | |||
#include "util/opening_hours.hpp" | |||
#include "util/typedefs.hpp" | |||
|
|||
#include <boost/variant.hpp> |
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.
Is there any particular reason why the boost
version is used here? We already bundle the mapbox/variant
, it might make sense to use it here as well.
include/extractor/restriction.hpp
Outdated
return from != SPECIAL_NODEID && to != SPECIAL_NODEID && via != SPECIAL_NODEID; | ||
}; | ||
|
||
std::string ToString() const |
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 moving this debug function outside of the class? I think we have an header for enabling pretty printers like this.
include/extractor/restriction.hpp
Outdated
} | ||
} | ||
|
||
std::string ToString() const |
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, pretty printers for debugging should be outside of the class.
// contracted move the head pointer to their respective head. Edges starting at tail move the | ||
// tail values to their respective tails. Way turn restrictions are represented by two | ||
// node-restrictions, so we can focus on them alone | ||
boost::unordered_multimap<NodeID, NodeRestriction *> heads; |
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.
std
also has a multimap, no need for boost
.
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.
https://stackoverflow.com/questions/11519648/unordered-multimapequal-range-slow
Actually, that link is a wrong one. But @daniel-j-h, you had some links indicating performance problems on std::unordered_map, care to share them 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.
I think it was https://bugs.llvm.org/show_bug.cgi?id=21275
}; | ||
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), extract_restrictions); | ||
|
||
const auto as_duplicated_node = |
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.
If this function gets inlined into by_duplicated_node
we could simply use std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from)
and avoid the copy over the tuple.
std::make_pair(std::make_pair(way.in_restriction.from, way.in_restriction.via), index)); | ||
++index; | ||
}; | ||
std::for_each(restriction_data.begin(), restriction_data.end(), prepare_way_restriction); |
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 should be a for loop for sure as it keep external state. Also as_duplicate_node
is bound but not used, and I don't see a reference to duplication_id
.
++offset; | ||
return false; // continue until the end | ||
}; | ||
std::adjacent_find(restriction_data.begin(), restriction_data.end(), add_offset_on_new_groups); |
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.
We have util::for_each_pair
for this, which makes the intend a little bit clearer.
std::size_t WayRestrictionMap::AsDuplicatedNodeID(const std::size_t restriction_id) const | ||
{ | ||
return std::distance(duplicated_node_groups.begin(), | ||
std::upper_bound(duplicated_node_groups.begin(), |
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 should be split to two expression for readability, the 1
is almost sneaking away at the end.
{ | ||
// loop over all restrictions associated with the node. Mark as restricted based on | ||
// is_only/restricted targets | ||
for (std::size_t restriction_index = duplicated_node_groups[duplicated_node]; |
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.
util::irange
can be used for this.
fdaee14
to
20ff5c5
Compare
20ff5c5
to
d024c8e
Compare
Makes turn restrictions into dedicated structures and diferentiates between them via a variant. Ensures that we do not accidentally mess up ID types within our application. In addition this improves the restriction performance by only parsing all edges once at the cost of (at the time of writing) 22MB in terms of main memory usage.
…eation of edge-based-graph initial version of handling via-way turn restrictions (this is dirty) - requires update of data structures - requires clean-up - requires optimisation
d024c8e
to
49e77ac
Compare
I've addressed the reviews. Could you re-check? |
Issue
Tasklist
Performance:
Extraction of Germany:
Contraction:
Partition
Customize
Master
Extraction
Contraction
Partition
Customize