Our process of finding a solution for the dynamic CARP can be divided into three main components: deciding when to update the solution, determining the current state of the problem at each update, and amending the solution subject to the current state of the problem. We now consider these in turn.
4.2.1
Solution Update Schedules
Here we shall focus on a regular update schedule: that is, the solution is updated at regular intervals. More precisely, let T be the length of the planning horizon and N the number of updates, which is to be specified. Without loss of generality, let the planning horizon start at time 0 and end at time T . Solution updates then take place at time kTN for k = 1, . . . , N . Intuitively, fewer updates mean more time to collect information about new tasks that appear in the interval prior to each update, while more updates means new tasks can be dealt with more promptly. A regular update schedule has been used in dynamic vehicle routing (Montemanni et al., 2005; Chen and Xu, 2006). In particular, computational results given by Montemanni et al. (2005) showed that the best solution (with respect to total distance) could be achieved when the number of updates was neither too high nor too low, although it was not explicitly investigated how (or whether) such “promising” number of updates would vary with the rate at which new tasks appear. Later in this chapter (Section 4.4), several numbers of updates will be tested on dynamic CARP instances with a range of rates at which new tasks appear.
4.2.2
Determining the Current State of the Problem
Before each solution update, the current state of the problem needs to be determined. This involves updating the set of tasks to be serviced, the vehicles’ positions, and their remaining capacities. The current state of the problem depends on both changes in the problem itself (new tasks appear) and solutions from previous updates (vehicles travel around to service tasks). Also, notice that parts of the routes that have been traversed cannot be amended, so those parts should be clearly identified to ensure that changes made to the solution are feasible. For clarity, this section describes how the current state of the problem and the (non-)amendable parts of the routes are determined.
a1 a2 a3
Time at which
the vehicle leaves the depot
T(1)
T(2)
T(3)
Traversal without service Traversal with service
Figure 4.1: The time T (i) at which a vehicle reaches the ith task in its route.
Given the time at which the solution is updated, each route R = (vs, a1, . . . , an, v0) is divided into two parts, for some index ˜i and some vertex ˜vs:
(vs, a1, . . . , a˜i, ˜vs); (˜vs, a˜i+1, . . . , an, v0) (4.1) Here the first part cannot be amended (i.e. it is fixed), whereas the second part can still be amended. The task fixing index ˜i is the largest index i such that ai has been reached by the vehicle corresponding to the route R. More precisely, let c(a) denote the cost of an arc a, and D(a, b) the shortest distance from the head of an arc a to the tail of another arc b. For ease of notation, let a0 = (vs, vs) and c(a0) = 0. The task fixing index can be determined by finding the largest index i such that
T (i) = 1 ν i X k=1 [c(ak−1) + D(ak−1, ak)] ≤ tu− ts(R), (4.2)
where T (i) is the time at which task ai is reached (with T (0) = 0 by convention), tu is the time of the update, ts(R) the start time of the route R (not all routes need to leave the depot at time 0; see Section 4.2.3), and ν the vehicle speed (distance per unit time); here it is assumed that ν is a constant given as part of the problem and that all vehicles travel at the same constant speed. Inequality (4.2) ensures that a˜i is included in the fixed part not only when it has been serviced but also when it is being serviced at the time of the update; see Figure 4.1 for the illustration. This agrees with the assumption that partial service is not allowed (see Section 2.3), from which it follows that if a vehicle is currently servicing a˜i, it must continue the service until completion, and therefore it is certain that a˜i is serviced by this vehicle at its current order in the route.
The starting vertex ˜vs in the expression (4.1) is the first vertex to be visited in the
route after the given update. The way in which ˜vs is determined depends on the
current position of the vehicle: (i) if the vehicle is precisely at some vertex at the time of the update, then ˜vs is simply that vertex; (ii) if the vehicle is in the middle of an edge, then ˜vs is the endpoint of that edge which the vehicle is heading towards. That edge may be either a task that is being serviced by the vehicle or an edge in the middle of a deadheading path between two consecutive tasks ai and ai+1 for some i (in fact, the index i here is the task fixing index ˜i).
Once the task fixing index and the starting vertex of each route are determined, its remaining capacity can be updated accordingly by simply subtracting the total demand of tasks in the fixed part from the remaining capacity at the previous update. After that, its fixed part is archived (so at the end of the planning horizon, a complete journey of each vehicle is a concatenation of fixed parts of the corresponding route that are archived in all updates). The next step is to combine the amendable parts of the routes and the set of new tasks that have appeared since the previous update. It should be noted that even though initially (at time 0) all vehicles have the same capacity and their routes start at the same vertex (the depot), they can service different amounts of demands and be at different locations at later time t > 0. This means that when updating the solution within the planning horizon, it is possible that a route planner encounters a more general version of the CARP, namely an open CARP with heterogeneous vehicles. Here, “open” refers to an open route, i.e. a vehicle’s starting and ending vertices are not necessarily the same (it could be away from the depot at the time of the update), and “heterogeneous” means that different vehicles can have different (remaining) capacities.
4.2.3
Integrating New Tasks into the Solution
Once the current state of the problem is determined, new tasks need to be integrated into the solution to form a feasible solution subject to the current state of the problem. One way to do so is to reconstruct the solution from scratch. More precisely, all existing tasks are removed from the routes so the routes only contain their starting and ending vertices. Then, those tasks together with new tasks are added back to the routes using the Path Scanning algorithm (described in Section 2.5). Although the Path Scanning algorithm was originally designed for the standard CARP (where all vehicles have the same capacity and start their routes from the same vertex), it can be easily adapted for an open CARP with heterogeneous vehicles. Each
route is reconstructed by adding one task at a time to the end of the route. The task to be added is the one that is nearest to the end vertex of the last task (or nearest to the starting vertex of the route if it is the first task). When there is more than one nearest task, one of them is chosen according to a given tie-breaking rule. Golden et al. (1983) proposed 5 tie-breaking rules: (i) maximise the distance from the endpoint to the depot; (ii) minimise the distance from the endpoint to the depot; (iii) use rule (i) if the vehicle’s remaining capacity is at least half the whole capacity, and use rule (ii) otherwise; (iv) maximise the ratio demand/cost; and (v) minimise the ratio demand/cost. Tasks are iteratively added to the routes until no more tasks can be added due to the capacity. The other routes are constructed in the same way until all tasks are added to the routes. If the existing routes are not sufficient to service all the tasks, then a new route is constructed with the starting vertex being the depot (so this route leaves the depot after time 0). Each tie-breaking rule gives one solution, and the best among those solutions is chosen as the output of the algorithm. If there is more than one best solution, one of them is chosen randomly. Obviously, reconstructing the solution from scratch is not the only way to integrate new tasks into the solution. Later on in this chapter (Section 4.5), an alternative way of integrating new tasks will be considered.
After new tasks are integrated into the solution, an attempt is then made to improve the solution by means of a variant of the tabu search algorithm from Chapter 3, namely the one in which the definition of tabu moves is based on the 2-task attribute. A pseudocode for the whole dynamic CARP solver is given in Algorithm 4.