39 const absl::Span<VehicleBreak> vehicle_breaks =
42 const absl::Span<Interval> cumuls = dimension_values.
MutableCumuls(path);
43 const int num_cumuls = cumuls.size();
44 const absl::Span<const int64_t> travels = dimension_values.
Travels(path);
45 const absl::Span<const int64_t> travel_sums =
47 const absl::Span<const int64_t> pre_visits = visits.
PreVisits(path);
48 const absl::Span<const int64_t> post_visits = visits.
PostVisits(path);
49 const auto visit_start_max = [cumuls, pre_visits](
int c) -> int64_t {
50 return CapSub(cumuls[c].max, pre_visits[c]);
52 const auto visit_end_min = [cumuls, post_visits](
int c) -> int64_t {
53 return CapAdd(cumuls[c].min, post_visits[c]);
55 const auto travel_slack = [cumuls, travels](
int c) -> int64_t {
57 CapSub(
CapSub(cumuls[c + 1].max, cumuls[c].min), travels[c]);
63 delayed_propagations_.clear();
66 int breaks_window_min = num_cumuls;
67 int breaks_window_max = -1;
68 int64_t breaks_total_duration = 0;
69 break_duration_on_transition_.Revert();
70 const int num_breaks = vehicle_breaks.size();
71 for (VehicleBreak& br : vehicle_breaks) {
72 if (br.is_performed.min == 0)
continue;
73 if (!IncreaseMin(
CapSub(br.end.min, br.start.max), &br.duration, &result)) {
80 -1, num_cumuls, [&visit_start_max, break_end_min = br.end.min](
int c) {
81 return visit_start_max(c) < break_end_min;
84 while (c_min < num_cumuls - 1 && travel_slack(c_min) < br.duration.min) {
87 if (!IncreaseMin(visit_end_min(c_min), &br.start, &result) ||
88 !IncreaseMin(
CapAdd(br.start.min, br.duration.min), &br.end,
102 if (c_min < num_cumuls - 1 &&
103 !IncreaseMin(
CapSub(br.end.min, travel_slack(c_min)), &br.start,
108 const int64_t cumul_ub =
CapSub(br.start.max, post_visits[c_min]);
109 if (cumuls[c_min].min > cumul_ub)
return kInfeasible;
110 delayed_propagations_.push_back(
111 {.value = cumul_ub, .index = c_min, .is_min =
false});
118 [&visit_end_min, break_start_max = br.start.max](
int c) {
119 return break_start_max < visit_end_min(c);
121 if (c_max < num_cumuls) {
122 while (c_max > 0 && travel_slack(c_max - 1) < br.duration.min) --c_max;
123 if (!DecreaseMax(visit_start_max(c_max), &br.end, &result) ||
124 !DecreaseMax(
CapSub(br.end.max, br.duration.min), &br.start,
130 !DecreaseMax(
CapAdd(br.start.max, travel_slack(c_max - 1)), &br.end,
135 const int64_t cumul_lb =
CapAdd(br.end.min, pre_visits[c_max]);
136 if (cumuls[c_max].max < cumul_lb)
return kInfeasible;
137 delayed_propagations_.push_back(
138 {.value = cumul_lb, .index = c_max, .is_min =
true});
145 if (0 <= c_min && c_max < num_cumuls) {
146 const int64_t transit =
CapAdd(
147 br.duration.min,
CapSub(travel_sums[c_max], travel_sums[c_min]));
148 if (
CapAdd(cumuls[c_min].min, transit) > cumuls[c_max].max) {
151 delayed_propagations_.push_back(
152 {.value =
CapAdd(cumuls[c_min].min, transit),
155 delayed_propagations_.push_back(
156 {.value =
CapSub(cumuls[c_max].max, transit),
159 breaks_window_min = std::min(breaks_window_min, c_min);
160 breaks_window_max = std::max(breaks_window_max, c_max);
161 CapAddTo(br.duration.min, &breaks_total_duration);
164 if (num_breaks > 1 && c_min + 1 == c_max) {
165 const int64_t total_duration = break_duration_on_transition_.Get(c_min);
166 break_duration_on_transition_.Set(
167 c_min,
CapAdd(total_duration, br.duration.min));
175 for (
const int t : break_duration_on_transition_.ChangedIndices()) {
176 const int64_t total =
177 CapAdd(travels[t], break_duration_on_transition_.Get(t));
178 if (!IncreaseMin(
CapAdd(cumuls[t].min, total), &cumuls[t + 1], &result) ||
179 !DecreaseMax(
CapSub(cumuls[t + 1].max, total), &cumuls[t], &result)) {
184 if (breaks_total_duration > 0) {
185 const int64_t window_transit =
CapAdd(
186 breaks_total_duration,
187 CapSub(travel_sums[breaks_window_max], travel_sums[breaks_window_min]));
188 if (!IncreaseMin(
CapAdd(cumuls[breaks_window_min].min, window_transit),
189 &cumuls[breaks_window_max], &result) ||
190 !DecreaseMax(
CapSub(cumuls[breaks_window_max].max, window_transit),
191 &cumuls[breaks_window_min], &result)) {
195 for (
const auto& [value, index, is_min] : delayed_propagations_) {
196 if (is_min && !IncreaseMin(value, &cumuls[index], &result)) {
199 if (!is_min && !DecreaseMax(value, &cumuls[index], &result)) {
209 absl::Span<
const std::pair<int64_t, int64_t>> interbreaks) {
212 std::vector<VehicleBreak>& vehicle_breaks =
217 const int64_t
kint64min = std::numeric_limits<int64_t>::min();
218 const int64_t
kint64max = std::numeric_limits<int64_t>::max();
220 .end = cumuls.front(),
222 .is_performed = {1, 1}});
223 vehicle_breaks.push_back({.start = cumuls.back(),
226 .is_performed = {1, 1}});
227 const int num_breaks = vehicle_breaks.size();
228 for (
const auto [limit, min_break_duration] : interbreaks) {
231 usage_events_.clear();
232 for (
int i = 0; i < num_breaks; ++i) {
233 const auto& br = vehicle_breaks[i];
234 if (br.is_performed.max == 0 || br.duration.max < min_break_duration) {
237 usage_events_.push_back(
238 {.time = br.start.min, .index = i, .is_start =
true});
239 usage_events_.push_back(
240 {.time =
CapAdd(br.end.max, limit), .index = i, .is_start =
false});
242 std::sort(usage_events_.begin(), usage_events_.end());
249 int num_active_breaks = 0;
250 int xor_active_breaks = 0;
252 for (
const UsageEvent& event : usage_events_) {
253 if (event.time != previous_time) {
254 DCHECK_GT(event.time, previous_time);
257 if (num_active_breaks == 1) {
258 VehicleBreak& br = vehicle_breaks[xor_active_breaks];
259 const int64_t new_start_max =
260 std::min(previous_time,
CapSub(br.
end.
max, min_break_duration));
261 const int64_t new_end_min =
262 std::max(
CapSub(event.time, limit),
264 if (!DecreaseMax(new_start_max, &br.
start, &result) ||
265 !IncreaseMin(new_end_min, &br.
end, &result)) {
268 if (xor_active_breaks < num_breaks - 2) {
269 const int64_t new_duration_min = std::max(
270 min_break_duration,
CapSub(new_end_min, new_start_max));
272 !IncreaseMin(new_duration_min, &br.
duration, &result)) {
279 num_active_breaks +=
event.is_start ? 1 : -1;
280 xor_active_breaks ^=
event.index;
281 previous_time =
event.time;
284 const Interval& new_start = vehicle_breaks[num_breaks - 2].end;
285 const Interval& new_end = vehicle_breaks[num_breaks - 1].start;
286 if (!IntersectWith(new_start, &cumuls.front(), &result) ||
287 !IntersectWith(new_end, &cumuls.back(), &result)) {
288 vehicle_breaks.resize(num_breaks - 2);
293 vehicle_breaks.resize(num_breaks - 2);