Fix unplanning bug for plan one of plan unit #91
+116
−23
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Context
I spoke to @nmisek earlier this week about a bug we discovered when implementing a custom routing model. I thought it would be easiest to show you the issue with a failing test + a potential fix that we have been using internally.
The easiest way to understand what I'm talking about is to paste my updated unit tests into the develop branch and see them fail. I might have misunderstood the intent of the code but hopefully you will agree with the tests.
Problem description
While using PlanOneOfPlanUnits to implement a disjunctive constraint on (pickup, dropoff) stop pairs, we found that the solver was giving very weird solutions. I debugged the issue and found out that the solver was unable to correctly unplan stops that were part of disjunctive constraints.
I found the cause of this issue in
bestMovePlanOneOfUnit. The original implementation was:The function returns a move associated with a StopPlanUnit (assuming no nesting of PlanOneOfPlanUnits) instead of the PlanOneOfPlanUnit that is passed to the function. When the move is executed, stops are attached to the solution but the bookkeeping of planned / unplanned PlanUnits is not done correctly. Hence you end up with stops attached to solutions, but the disjunctive plan unit is marked as unplanned (see test "TestPlanUnitsUnit/PlanOneOfPlanUnits"). This explains why we observed that the solver was unable to unplan the stops.
When I was writing up this PR and the tests for this problem, I also discovered that the same bookkeeping is wrong for nested PlanOneOfPlanUnit (see test: "TestModel_NewPlanOneOfPlanUnits"). I discovered this because the existing tests include these nested structures but they didn't catch the unplanned/planned weirdness. We don't use nested disjunctive constraints, but I wanted to point this out to you here as well.
Fix
The solution to our core problem was to return a corrected move in
bestMovePlanOneOfUnitand removing a constraint inside
newSolutionMoveUnits()The rest of the code is related to fixing the planned / unplanned bookkeeping of nested PlanOneOfPlanUnits.