vrp_core/construction/enablers/
schedule_update.rs1use 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
13pub 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
24pub 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 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 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}