Skip to main content

vrp_core/construction/enablers/
schedule_update.rs

1use crate::construction::heuristics::{RouteContext, RouteState};
2use crate::models::common::{Distance, Duration, Schedule, Timestamp};
3use crate::models::problem::{ActivityCost, TransportCost, TravelTime};
4use crate::models::OP_START_MSG;
5use rosomaxa::prelude::Float;
6
7custom_activity_state!(LatestArrival typeof Timestamp);
8custom_activity_state!(WaitingTime typeof Timestamp);
9custom_tour_state!(TotalDistance typeof Distance);
10custom_tour_state!(TotalDuration typeof Duration);
11custom_tour_state!(LimitDuration typeof Duration);
12
13/// Updates route schedule data.
14pub fn update_route_schedule(
15    route_ctx: &mut RouteContext,
16    activity: &(dyn ActivityCost),
17    transport: &(dyn TransportCost),
18) {
19    update_schedules(route_ctx, activity, transport);
20    update_states(route_ctx, activity, transport);
21    update_statistics(route_ctx, transport);
22}
23
24/// Updates route departure to the new one.
25pub fn update_route_departure(
26    route_ctx: &mut RouteContext,
27    activity: &(dyn ActivityCost),
28    transport: &(dyn TransportCost),
29    new_departure_time: Timestamp,
30) {
31    let start = route_ctx.route_mut().tour.get_mut(0).unwrap();
32    start.schedule.departure = new_departure_time;
33
34    update_route_schedule(route_ctx, activity, transport);
35}
36
37fn update_schedules(route_ctx: &mut RouteContext, activity: &(dyn ActivityCost), transport: &(dyn TransportCost)) {
38    let init = {
39        let start = route_ctx.route().tour.start().unwrap();
40        (start.place.location, start.schedule.departure)
41    };
42
43    (1..route_ctx.route().tour.total()).fold(init, |(loc, dep), activity_idx| {
44        let (location, arrival, departure) = {
45            let a = route_ctx.route().tour.get(activity_idx).unwrap();
46            let location = a.place.location;
47            let arrival = dep + transport.duration(route_ctx.route(), loc, location, TravelTime::Departure(dep));
48            let departure = activity.estimate_departure(route_ctx.route(), a, arrival);
49
50            (location, arrival, departure)
51        };
52
53        route_ctx.route_mut().tour.get_mut(activity_idx).unwrap().schedule = Schedule::new(arrival, departure);
54
55        (location, departure)
56    });
57}
58
59fn update_states(route_ctx: &mut RouteContext, activity: &(dyn ActivityCost), transport: &(dyn TransportCost)) {
60    // update latest arrival and waiting states of non-terminate (jobs) activities
61    let actor = route_ctx.route().actor.clone();
62    let init = (
63        actor.detail.time.end,
64        actor
65            .detail
66            .end
67            .as_ref()
68            .unwrap_or_else(|| actor.detail.start.as_ref().unwrap_or_else(|| panic!("{}", OP_START_MSG)))
69            .location,
70        Float::default(),
71    );
72
73    let route = route_ctx.route();
74    let mut latest_arrivals = Vec::with_capacity(route.tour.total());
75    let mut waiting_times = Vec::with_capacity(route.tour.total());
76
77    route.tour.all_activities().rev().fold(init, |acc, act| {
78        if act.job.is_none() {
79            latest_arrivals.push(Default::default());
80            waiting_times.push(Default::default());
81            return acc;
82        }
83
84        let (end_time, prev_loc, waiting) = acc;
85        let latest_arrival_time = if end_time == Float::MAX {
86            act.place.time.end
87        } else {
88            let latest_departure =
89                end_time - transport.duration(route, act.place.location, prev_loc, TravelTime::Arrival(end_time));
90            activity.estimate_arrival(route, act, latest_departure)
91        };
92        let future_waiting = waiting + (act.place.time.start - act.schedule.arrival).max(0.);
93
94        latest_arrivals.push(latest_arrival_time);
95        waiting_times.push(future_waiting);
96
97        (latest_arrival_time, act.place.location, future_waiting)
98    });
99
100    latest_arrivals.reverse();
101    waiting_times.reverse();
102
103    // NOTE: pop out state for arrival
104    if route.tour.end().map_or(false, |end| end.job.is_none()) {
105        latest_arrivals.pop();
106        waiting_times.pop();
107    }
108
109    route_ctx.state_mut().set_latest_arrival_states(latest_arrivals);
110    route_ctx.state_mut().set_waiting_time_states(waiting_times);
111}
112
113fn update_statistics(route_ctx: &mut RouteContext, transport: &(dyn TransportCost)) {
114    let (route, state) = route_ctx.as_mut();
115
116    let start = route.tour.start().unwrap();
117    let end = route.tour.end().unwrap();
118    let total_dur = end.schedule.departure - start.schedule.departure;
119
120    let init = (start.place.location, start.schedule.departure, Distance::default());
121    let (_, _, total_dist) = route.tour.all_activities().skip(1).fold(init, |(loc, dep, total_dist), a| {
122        let total_dist = total_dist + transport.distance(route, loc, a.place.location, TravelTime::Departure(dep));
123
124        (a.place.location, a.schedule.departure, total_dist)
125    });
126
127    state.set_total_distance(total_dist);
128    state.set_total_duration(total_dur);
129}