-
Notifications
You must be signed in to change notification settings - Fork 38
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
Move LS route cost evaluation to CostEvaluator #417
base: main
Are you sure you want to change the base?
Conversation
* Use it for Relocate
* timeWarp | ||
* Time warp for the route. | ||
*/ | ||
struct RouteData |
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: RouteData
doesn't implement CostEvaluatable
concept as it does not have uncollectedPrizes
, fixedVehicleCost
, loadExcess
. While we could change that (or change the concept) I think it is cleaner this way: the concept is about the cost structure for a solution whereas this object is for a route. We could consider moving away from the concept (as we use it only once now) and also implement computing the 'solution level cost' based on a similar SolutionData
(or properties or better name) that tracks KPI's of a solution.
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.
Like pyvrp.search.Route
now does, I think this new object could also implement the member functions related to the concept. Then no further specialisation is necessary.
* timeWarp | ||
* Time warp for the route. | ||
*/ | ||
struct RouteData |
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.
Like pyvrp.search.Route
now does, I think this new object could also implement the member functions related to the concept. Then no further specialisation is necessary.
* RouteData( | ||
* size: int, | ||
* distance: Distance, | ||
* load: Load, | ||
* timeWarp: Duration | ||
* ) |
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 about the name.
We use this exclusively in pyvrp.search
, so putting this in CostEvaluator
feels like the wrong place. Perhaps a new file in pyvrp/cpp/search
?
Since this "route data" object essentially just holds the properties related to cost that a route will have after a proposed move is applied, a name like MoveProperties
seems clearer.
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.
One thing to check remains performance. The previous attempt at decoupling delta cost computations from changes in route properties was not all that fast. This might be better, but I have no real feeling for where we lost those 20-30% iterations when going in this direction previously.
I think it'll be important to do something like this to also support e.g. duration in the objective, but I am not sure how to get there without the performance regression we identified in a previous PR. I also have some comments about the naming/interface and stuff, but those are not as much of a show-stopper as "make this work about as fast as what we currently do". |
@wouterkool now that we have moved (almost all) cost evaluations to the |
Sorry, I have not been able to catch up lately but it looks like a lot of nice work which indeed replaces this PR. I will find some time beginning of april to review things and see if everything is there or if there are still some remaining ideas to consider. Thanks! |
This PR:
This is an exploratory implementation that moves the logic to compute the costs for a route inside the
Exchange
operator from the operator to theCostEvaluator
. The idea is that the same logic can then be used for other operators (in a follow up PR).By moving the cost evaluation logic to a central place, it is easier to implement different objectives and (soft) constraints such as duration in the objective, max duration, other vehicle cost structure, max distance etc. Additionally, this makes it easier to implement 'early prechecks' based on bounds on the route costs in a consistent way, also when changing objectives (this PR also has a stronger bounding mechanism than current main).
The downside is that the evaluation logic becomes more general and thereby less efficient. For example, we can no longer just compute delta distance (and delta cost from that) but we need to compute the new route distance and compare against the old route distance. Also, additional function calls introduce extra overhead.
In theory, the compiler could inline the calls and then deduce some logic that some computations kan be skipped, however this seems not to be happening as this code is significantly slower than the original. Despite the stronger bounding mechanism, the code is slower overall (TODO run some benchmarks).
@N-Wouda I remember we had a discussion and maybe you had some thoughts on how we can further optimize this?
Notes:
This keeps the code coverage level up, and helps ensure the changes work as intended.