-
Notifications
You must be signed in to change notification settings - Fork 699
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
path expansion endpoint #1849
path expansion endpoint #1849
Conversation
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.
Any impact on performance when not tracking expansion?
src/thor/route_action.cc
Outdated
rapidjson::Pointer("/features/0/geometry/type").Set(*expansion_, "MultiLineString"); | ||
rapidjson::Pointer("/features/0/geometry/coordinates").Create(*expansion_).SetArray(); | ||
rapidjson::Pointer("/features/0/properties/edge_ids").Create(*expansion_).SetArray(); | ||
rapidjson::Pointer("/features/0/properties/statuses").Create(*expansion_).SetArray(); |
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 we fill out a template of the feature collection and the one feature that holds all the linestrings. if its a multileg route we have a problem where the last leg will win on setting which algorithm wsa used. seems like in the future we should ahve a separate feature for each leg
src/thor/route_action.cc
Outdated
// serialize it | ||
auto json = rapidjson::to_string(*expansion_, 5); | ||
// tell the path algorithms to stop tracking the expansion at all | ||
expansion_.reset(); |
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 when we do this reset the algorithms will see that their weak_ptr doesnt point to anything and so wont track
rapidjson::StringBuffer buffer; | ||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); | ||
if (decimal_places >= 0) | ||
writer.SetMaxDecimalPlaces(decimal_places); |
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 makes it easy for us to truncate all precision to a certain value, which is nice for geojson where we can just say we only care about 5 places for example
@dnesbitt61 shouldnt be any performance impact, i was very careful about that. i can do performance testing on my own but would there but a specific test suite that you would recommend to verify that? |
I always check Lancaster to San Diego as my long test route, though any long route would work. valhalla_run_route with multi-run option works best (N successive path generation times are averaged to give the result - I usually use 100). I tried to keep a running tally of where this was, but now I have a new machine. I could try before and after with this branch but I have data without hierarchies and shortcuts. |
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.
Tested performance and looks fine (just a very small drop 1-2%). Code looks good to me, but didn't test the actual generation of GeoJSON. Will leave that to others!
I noticed a little bit more of a performance penalty locally using
|
@@ -181,6 +181,10 @@ void BidirectionalAStar::ExpandForward(GraphReader& graphreader, | |||
(pred.not_thru_pruning() || !directededge->not_thru())); | |||
adjacencylist_forward_->add(idx); | |||
*es = {EdgeSet::kTemporary, idx}; | |||
|
|||
// setting this edge as reached | |||
if (expansion_callback_) |
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::function<>
has an operator bool
which lets you check if its actually assigned to something callable, this check is way faster than std::weak_ptr<>::lock
@@ -754,7 +787,7 @@ std::vector<PathInfo> BidirectionalAStar::FormPath(GraphReader& graphreader) { | |||
cost += edgelabel.cost() - edgelabels_reverse_[predidx].cost(); | |||
} | |||
cost += tc; | |||
path.emplace_back(edgelabel.mode(), cost.secs, oppedge, 0, cost.cost); | |||
path.emplace_back(edgelabel.mode(), cost.secs, edgelabel.opp_edgeid(), 0, cost.cost); |
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 was a simplification. notice above that we go fetch the opposing edge id the hard way. the edge labels for bidirectional already have the opposing edge id on them so i just used that instead. @dnesbitt61 there's not a gotcha here right?
rapidjson::Pointer("/features/0/geometry/type").Set(dom, "MultiLineString"); | ||
rapidjson::Pointer("/features/0/geometry/coordinates").Create(dom).SetArray(); | ||
rapidjson::Pointer("/features/0/properties/edge_ids").Create(dom).SetArray(); | ||
rapidjson::Pointer("/features/0/properties/statuses").Create(dom).SetArray(); |
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 we start by prepopulating the feature
.Get(dom) | ||
->GetArray() | ||
.PushBack(rapidjson::Value{}.SetString(status, a), a); | ||
}; |
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 inject this lambda into the path algorithm and it calls us back with it. here we are building geojson but we could do something else with this information if we wanted.
&bidir_astar, | ||
}) { | ||
alg->set_track_expansion(track_expansion); | ||
} |
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 where we tell all the algorithms to actually use our lambda to track stuff as the algorithm progresses
&astar, | ||
&bidir_astar, | ||
}) { | ||
alg->set_track_expansion(nullptr); |
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 where we tell all the algorithms that they no longer have a callback to call
this adds a new endpoint to valhalla called
/expansion
which takes a normal/route
style request but returns geojson. the geojson is a time-series dataset of which edges of the routing graph were touched by the path algorithm (only bidirectional a* implemented so far) in the order they were touched and what type of label was assigned to them.the geojson is a small as possible (for such a verbose format). it returns only a single feature which has a geometry of type
MultiLineString
. EachLineString
represents the beginning and end points (so only two coordinates) of each edge the algorithm touched.the properties of the feature contain two parallel arrays (which match the number of edges/linestrings in the geometry). the first array is a list of the edge_ids and the second array is a list of the statuses. the statuses can be one of
r
(reached),s
(settled) orc
(connected).this should work for multileg routes as well but there is no signifier of when one legs expansion history ends and the next one begins.
there should be little to no performance impact on the
/route
endpoint as the function that tracks this data is bothinline
d and wrapped in anif
that says don't track this if we werent called from the/expansion
action/endpont.