Skip to content

Commit

Permalink
Fixed a bug in the computation of time windows for delivery rounds in
Browse files Browse the repository at this point in the history
the local plan.
  • Loading branch information
ondrasej committed Oct 25, 2023
1 parent e97825e commit c417e07
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 2 deletions.
17 changes: 15 additions & 2 deletions examples/two_step_routing/two_step_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,7 @@ def _get_local_model_route_start_time_windows(
global_end_time = cfr_json.get_global_end_time(model)

route_start_time = cfr_json.parse_time_string(route["vehicleStartTime"])
shipments = cfr_json.get_shipments(model)

# The start time window for the route is computed as the intersection of
# "route start time windows" of all visits in the route. A "route start time
Expand All @@ -1441,8 +1442,20 @@ def _get_local_model_route_start_time_windows(
overall_route_start_time_intervals = ((global_start_time, global_end_time),)

for visit in visits:
visit_request = cfr_json.get_visit_request(model, visit)
time_windows = visit_request.get("timeWindows")
# NOTE(ondrasej): We can't use `visit["shipmentIndex"]` to get the shipment;
# `visit` is from the local model, while `model` is the global model. To
# get the expected results, we need to use the shipment label from the visit
# to get the shipment index in the base model.
shipment_label = visit.get("shipmentLabel")
shipment_index = _get_shipment_index_from_local_label(shipment_label)
shipment = shipments[shipment_index]
deliveries = shipment.get("deliveries", ())
if len(deliveries) != 1:
raise ValueError(
"Only shipments with one delivery request are supported."
)

time_windows = deliveries[0].get("timeWindows")
if not time_windows:
# This shipment can be delivered at any time. No refinement of the route
# delivery time interval is needed.
Expand Down
129 changes: 129 additions & 0 deletions examples/two_step_routing/two_step_routing_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3286,6 +3286,135 @@ def test_local_refinement_model(self):
)


class GetLocalModelRouteStartTimeWindowsTest(unittest.TestCase):
"""Tests for _get_local_model_route_start_time_windows."""

maxDiff = None

_MODEL: cfr_json.ShipmentModel = {
"globalStartTime": "2023-10-25T00:00:00Z",
"globalEndTime": "2023-10-25T23:59:59Z",
"shipments": [
{
"deliveries": [
{
"timeWindows": [{
"startTime": "2023-10-25T09:00:00Z",
"endTime": "2023-10-25T12:00:00Z",
}]
}
],
"label": "S001",
},
{
"deliveries": [
{
"timeWindows": [{
"startTime": "2023-10-25T09:00:00Z",
"endTime": "2023-10-25T12:00:00Z",
}]
}
],
"label": "S002",
},
{
"deliveries": [
{
"timeWindows": [{
"startTime": "2023-10-25T14:00:00Z",
"endTime": "2023-10-25T16:00:00Z",
}]
}
],
"label": "S003",
},
{
"deliveries": [
{
"timeWindows": [{
"startTime": "2023-10-25T12:00:00Z",
"endTime": "2023-10-25T15:00:00Z",
}]
}
],
"label": "S004",
},
{
"deliveries": [{}],
"label": "S005",
},
{
"deliveries": [{}],
"label": "S006",
},
],
}

def test_empty_route(self):
self.assertIsNone(
two_step_routing._get_local_model_route_start_time_windows({}, {})
)

def test_with_invalid_route(self):
local_route: cfr_json.ShipmentRoute = {
"vehicleStartTime": "2023-10-25T11:00:00Z",
"vehicleLabel": "P001 []",
"visits": [
{
"startTime": "2023-10-25T11:10:00Z",
"shipmentIndex": 3,
"shipmentLabel": "0: S001",
},
{
"startTime": "2023-10-25T11:20:00Z",
"shipmentIndex": 1,
"shipmentLabel": "2: S004",
},
],
}
with self.assertRaisesRegex(ValueError, "incompatible time windows"):
two_step_routing._get_local_model_route_start_time_windows(
self._MODEL, local_route
)

def test_with_some_shipments(self):
local_route: cfr_json.ShipmentRoute = {
"vehicleStartTime": "2023-10-25T11:00:00Z",
"vehicleLabel": "P001 []",
"visits": [
{
"startTime": "2023-10-25T11:10:00Z",
"shipmentIndex": 3,
"shipmentLabel": "0: S001",
},
{
"startTime": "2023-10-25T11:20:00Z",
"shipmentIndex": 1,
"shipmentLabel": "4: S005",
},
{
"startTime": "2023-10-25T11:45:00Z",
"shipmentIndex": 2,
"shipmentLabel": "1: S002",
},
{
"startTime": "2023-10-25T12:50:00Z",
"shipmentIndex": 0,
"shipmentLabel": "3: S004",
},
],
}
self.assertSequenceEqual(
two_step_routing._get_local_model_route_start_time_windows(
self._MODEL, local_route
),
[{
"startTime": "2023-10-25T10:10:00Z",
"endTime": "2023-10-25T11:15:00Z",
}],
)


class GetConsecutiveParkingLocationVisits(unittest.TestCase):
"""Tests for _get_consecutive_parking_location_visits."""

Expand Down

0 comments on commit c417e07

Please sign in to comment.