Skip to content
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

Refactor CostMatrix #4372

Merged
merged 37 commits into from
Dec 5, 2023
Merged

Refactor CostMatrix #4372

merged 37 commits into from
Dec 5, 2023

Conversation

nilsnolde
Copy link
Member

@nilsnolde nilsnolde commented Oct 31, 2023

fixes #4371

Alright, now this should be good to go.. I'm (kinda) sorry to say this is a bit more than just a refactor. Since it touches the entirety of CostMatrix and we'd have to review it from the ground up, I decided to take the chance to fix a few more things:

There's still quite a few things to do:

NOTE, I'm still owing a proper performance test with master, though following #4362 , I'm quite optimistic:)

@nilsnolde nilsnolde marked this pull request as draft October 31, 2023 02:33
@nilsnolde nilsnolde changed the title make costmatrix handle uturns Refactor CostMatrix Nov 12, 2023
@nilsnolde nilsnolde marked this pull request as ready for review November 13, 2023 17:28
CHANGELOG.md Outdated
@@ -16,6 +16,7 @@
* FIXED: recover proper shortest path to ferry connections (make sure correct label index is used) [#4378](https://github.com/valhalla/valhalla/pull/4378)
* FIXED: Allow all roads for motorcycles [#4348](https://github.com/valhalla/valhalla/pull/4348)
* FIXED: motorcar:conditional should not apply to motorcycle and moped [#4359](https://github.com/valhalla/valhalla/pull/4359)
* FIXED: lots of issues with CostMatrix (primarily deadend logic) with a complete refactor modeling things very close to bidir A*, also to prepare for a unification of the two [#4372](https://github.com/valhalla/valhalla/pull/4372)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: need to move this down one

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saw that too, wonder why there wasn’t a the usual conflict when master merged

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we actually need a separate script for this, the only thing that should really differ is the parsing of the response? the other script i think can let you run any file of requests so it shoudl work for the input part. and the output can be handled pretty easily by simply looking at the url to find which endpoint was hit route/sources_to_targets whatever and calling appropriate handler to parse the resulting json

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont feel strongly about it though, but it feels to me like tech debt

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh, the vast majority of python in this repo feels like tech debt (except for most installable scripts)😄 I should’ve done the work to clean this all up a bit more and not just copy paste. I’ll do that at some point I’m sure. If you want I can keep this locally instead of committing until I find the motivation to do that:)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah its ok, i trust you to keep it on your list 😄

parser = argparse.ArgumentParser(description="Runs payloads generated by gen_requests_matrix.py against a Valhalla server and writes the results to a single file for diffing purposes. Also prints out the total time.")
parser.add_argument('--test-file', type=Path, help='The file with the test requests', required=True)
parser.add_argument('--url', type=str, help='The url to which you want to POST the request bodies',
default='http://localhost:8002/route')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

case in point haha

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Na the other script is doing one file per request, for matrix that’s not cool

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was focused on this part

default='http://localhost:8002/**route**'

Comment on lines -291 to 286
// Abort if max label count is exceeded
if (total_labels > max_label_count_) {
return {};
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but dont we still want this? as i was saying there are two types of aborting, using the interrupt which is telling us the client said hey i dont care about this request anymore, and then the other kind where we say ok we searched hard enough that we now give up

Copy link
Member Author

@nilsnolde nilsnolde Dec 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned it somewhere: it’s not used at all. We still do what you’re saying, but it’s not done with this variable, it's this nc a bit further up (same for most other algos).

{opp_edge, opp_edge_id,
edgestatus.GetPtr(opp_edge_id, tile)},
shortcuts, tile, offset_time);
if (opp_edge) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it pains me to see this if but i guess its equivalent to logical and anyway

Comment on lines 46 to 48
mode_ = travel_mode_t::kPedestrian;
travel_type_ = 0;
max_walking_dist_ = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why move them out of the initializer list? if it was a warning, just reorder them to shut the warning up

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was more of a preference call, but I can revert. I find it more legible. My eyes have a hard time seeing all variables in long initializer lists

@@ -78,7 +78,7 @@ void Dijkstras::Initialize(label_container_t& labels,
uint32_t edge_label_reservation;
uint32_t bucket_count;
GetExpansionHints(bucket_count, edge_label_reservation);
labels.reserve(std::min(max_reserved_labels_count_, edge_label_reservation));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this used have the effect of capping the reservation at kInitialEdgeLabelCountDijkstras now you can configure to allow for more. i guess thats ok, but the diff isnt enough to understand thats happening

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can confirm that is what's happening:)

std::vector<baldr::DoubleBucketQueue<sif::BDEdgeLabel>> target_adjacency_;
std::vector<std::vector<sif::BDEdgeLabel>> target_edgelabel_;
std::vector<EdgeStatus> target_edgestatus_;
std::array<std::vector<LocationStatus>, 2> locs_status_;
Copy link
Member

@kevinkreiser kevinkreiser Dec 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this type of refactor makes the diff basically impossible to read. i wonder if it would have been better to maybe do this change last or maybe at the top of each method that uses one of these to do something like:

// alias with the old name so we dont see everything as a diff
auto& source_adjacency_ = adjacency_[MATRIX_FORW];

and let the names unchanged in the rest of the source. that way we could at least see what changed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, this wasn't a linear (rather a dirty) process to get here. probably I should have re-written the history before review. however, my hope was that we'll do this review in person (did that with dave though), since 90% of the lines changed and it'd be VERY hard to re-write history to make this better reviewable only looking at diffs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all good no worries

// when doing timezone differencing a timezone cache speeds up the computation
baldr::DateTime::tz_sys_info_cache_t tz_cache_;

// for tracking the expansion of the Dijkstra
expansion_callback_t expansion_callback_;

const std::function<void()>* interrupt_ = nullptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i appreciate you doing that. its not so hard to add so there is no good excuse why i havent done this for so long..

kInitialEdgeLabelCountBidirDijkstra)),
clear_reserved_memory_(config.get<bool>("clear_reserved_memory", false)), targets_{
new TargetMap} {
// Note, most things are being initialized in Initialize() or before
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah but there is no gaurantee someone doesnt call a different function that may rely on these before calling sourcestotargets which calls initialize. to avoid any future problems its best to at least initialize these to something other than random values even if we dont intend them to be used (plus it doesnt save anythign to leave them uninitialized)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I'll do that. fwiw, IIRC most algorithms have this problem, not even half the stuff is usually initialized. I'll change it for costmatrix, but will not touch the others for now, the PR is big enough as it stands:)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree. its like many things. over time we improve, when we touch stuff good to improve it in ways we have found deficient thus far

// anymore
if (targets.empty() && locs_status_[MATRIX_FORW][source].threshold > 0) {
// TODO(nils): shouldn't we extend the search here similar to bidir A*
// i.e. if pruning was disabled we extend the search in the other direction
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes intuitive sense

if (locs_status_[MATRIX_REV][i].threshold == 0) {
for (uint32_t source = 0; source < locs_count_[MATRIX_FORW]; source++) {
// update the target for each source's remaining targets, if it still exists
auto& targets = locs_status_[MATRIX_FORW][source].unfound_connections;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha cool yeah there you did do the alias thing i was suggesting and it indeed saved some small diffs haha. i still cant really read this without manually comparing each line though

while (true) {
// Iterate all target locations in a backwards search
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove things like this comment? i know its clear to you and me but its nice to have headings on code for newcomers

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok..

// in any case make sure this was the last time we looked at this source
locs_status_[MATRIX_FORW][i].threshold = -1;
if (locs_remaining_[MATRIX_FORW] > 0) {
locs_remaining_[MATRIX_FORW]--;
}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok i got to here, am i correct that nothing really changed in either of these loops, was just renaming and comments

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct. the whole costmatrix was 95% pure refactor, the remaining 5% the deadend logic, which is also the only thing I wrote additional tests for. I'd like to add some tests comparing the algos too, making sure they report the same duration/distance (+/- some minor threshold)

}
};
// TODO(nils): what if there is a shortcut that supersedes our u-turn? can that even be?
// We then need to decide if we should expand the shortcut or the non-shortcut edge...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a good question. yes we can make a uturn where a shortcut begins/ends. however, isnt it always safe to expand on the non shortcut? the worst scenario is that we were slightly less efficient in finding a solution because there as a shortcut that we didnt use. maybe thats all you're really saying here: "to be fully optimial we shoudl favor a shortcut uturn (when using shortcuts) as opposed to a superseded edge"

@kevinkreiser
Copy link
Member

ok im done looking it over! i had a lot of little nitpicks so i'll let you choose which ones you want to do, if you dont feel like doing them but also dont care that much let me know and i can do them.

but the only major thing i would say is we have to do the same perf test/diff for bidir a* since it got some refactoring and edge status changes (which you said you'd already look at).

let me know when done and ill put a ship!

@nilsnolde
Copy link
Member Author

Nitpicks are mostly relevant, I'll do them. And check perf/diff on bidir A* next week.

@nilsnolde
Copy link
Member Author

@kevinkreiser I addressed your review in 94af58b

@nilsnolde
Copy link
Member Author

I diff'd de_benchmark_routes.txt and no difference in either performance or narrative compared to master @kevinkreiser .

Also there were some warnings as errors creeping in again, fixed that too.

@kevinkreiser kevinkreiser merged commit 32a09fd into master Dec 5, 2023
6 of 7 checks passed
@kevinkreiser kevinkreiser deleted the nn-matrix-uturns branch December 5, 2023 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants