A closer look at the routing procedure
Before we create our first routing callback, let's take a closer look at the routing (or decision making) procedure that connects the simulator and the external routing algorithm!
Main overview
The routing procedure consists of the following steps.
- State. The external routing algorithm is provided with the current state, which describes all the information available to make a decision.
- Routing. The external routing algorithm is executed.
- Decision. The external routing algorithm returns a decision to the simulator.
sequenceDiagram
participant A as Simulator
participant B as External routing algorithm
A->>+B: state
Note right of B: routing
B->>-A: decision
Note
States and decisions do not contain objects, but are pure JSON data. The reason for this is that the implementation of the external routing algorithm is not tied to Python, but can be implemented in any programming language. In the latter case, the simulator and the external routing algorithm can communicate with each other via JSON files, for example.
States
A state describes all the information available to make a decision. By default, a state consists of the following elements:
- the current simulation time (see
time
) - the current status of the vehicles (see
vehicles
) - the current status of the orders (see
open_orders
andcanceled_orders
)
Custom states
States can also be customized by overriding the corresponding model method (get_state
).
Vehicle status
A vehicle is always in one of the following statuses (status
):
EN_ROUTE
: the vehicle is currently en route, i.e., on the way to its next location.UNDER_SERVICE
: the vehicle is currently under serviceWAITING_FOR_SERVICE
: the vehicle has arrived at a location and currently waiting for the serviceIDLE
: the vehicle is at a location and is ready to depart
When the vehicle is en route, its previous visit (previous_visit
) is given, describing where the vehicle was located (location
) and when the vehicle departed (departure_time
).
Otherwise, when the vehicle is at a location, its current visit is given (current_visit
) as follows.
The location (location
) refers to the current location, and the arrival time (arrival_time
) refers to the time when the vehicle arrived.
If the vehicle is waiting for service, the service start time is not set (None
).
When the vehicle is under service, the service start time is set, but the service finish time is not.
Finally, when the vehicle is idle, only the departure time of the visit is not set.
The list next_visits
describes the tentative route plan that the vehicle is currently following, if any.
Order status
We say that an order is open if it is not rejected, not canceled, and not delivered.
The open orders are given in the dictionary open_orders
, which maps order ids to order statuses.
The status of an order contains all the currently available information about the order.
The dictionary canceled_orders
specifies those orders that have been canceled and therefore must not be included in the vehicle routes anymore.
Decisions
The decision on orders shows whether the orders are accepted, rejected or postponed. The decision on vehicles describes the updated routes of the vehicles.
Decision on orders
Orders can be accepted or may be rejected. The decision on an order may also be postponed until a given time.
# example for decisions on orders
'orders': {
'O-1': { 'status': 'accepted' },
'O-2': { 'status': 'rejected' },
'O-3': { 'status': 'postponed', 'postponed_until': 42 }
}
Decision on vehicles
Updated vehicles must be provided in the decision.
Both the current visit (current_visit
) and the next visits (next_visits
) can be modified, if any.
For each visit, the corresponding location (location
) and the pickup and delivery lists (pickup_list
and delivery_list
) must be given.
For next visits, an earliest start time (earliest_start_time
) can also be specified.
Warning
The route of the vehicles can be modified subject to certain reasonable restrictions.
-
The current visits of a vehicle (i.e., the pickup and delivery lists), if any, cannot be modified if the service has already started.
-
The location of the next visit of an en route vehicle cannot be modified.
Moreover, canceled and rejected orders should not be included in the vehicle routes.
Some technical simplifications
-
If the entire route of a vehicle remains unchanged, the status of the vehicle need not to be provided in the decision.
-
If the current visit of a vehicle waiting for service is not changed, the current visit need not be provided.
-
If none of the next visits of a vehicle waiting for service is changed, the next visists need not be provided.
-
Empty pickup and delivery lists need not be provided.
# example for decisions on vehicles
'vehicles': {
'VEHICLE-1': None,
'VEHICLE-2': {
'next_visits': [
{
'location': 'DEPOT',
'pickup_list': ['O-1']
},
{
'location': 'CUSTOMER 1',
'delivery_list': ['O-1']
},
{
'location': 'DEPOT'
}
]
}
}
Routing callback
After routing is requested (i.e., a decision point is imposed), the routing procedure is started in a separate process, in which the method routing_callback
of the model is invoked.
Here we can do the connection between the simulator and the external routing algorithm.
Let's look at the "default" routing callback, which rejected all orders!
Default routing callback
In the case of the default routing callback, there is no external routing algorithm, but a dummy decision procedure is implemented in this callback. The procedure first gets the current state and then returns a decision that rejects all open orders.
def routing_callback(self) -> Any:
"""
This callback invokes the external routing algorithm.
"""
self.log.warning( 'routing callback is not implemented (all orders will be rejected)' )
state = self.get_state()
return {
'vehicles': {},
'orders': {
order_id: {
'status': 'rejected'
} for order_id in state['open_orders']
}
}
{
'time': 8,
'vehicles': {},
'open_orders': {
'O-1': {
'id': 'O-1',
'original_id': 'O-1',
'quantity': 0,
'release_date': 8,
'due_date': None,
'pickup_location': 'DEPOT',
'earliest_service_start_pickup': None,
'latest_service_start_pickup': None,
'delivery_location': 'CUSTOMER 1',
'earliest_service_start_delivery': None,
'latest_service_start_delivery': None,
'pickup_time': None,
'pickup_vehicle': None
}
},
'cancelled_orders': [],
'aux': {}
}