69 if (num_chain_tasks > 0) {
72 for (
int task = 0; task < num_chain_tasks; ++task) {
82 for (
int task = num_chain_tasks - 1; task >= 0; --task) {
86 if (time < tasks->
start_min[task])
return false;
91 const int num_tasks = tasks->
start_min.size();
92 for (
int task = 0; task < num_tasks; ++task) {
123 const int num_tasks = tasks->
start_min.size();
125 for (
int task = 0; task < num_tasks; ++task) {
126 const int64_t t = -tasks->
start_min[task];
131 for (
int task = 0; task < num_tasks; ++task) {
132 const int64_t t = -tasks->
start_max[task];
142 std::reverse(it, it + num_chain_tasks);
143 std::reverse(it + num_chain_tasks, it + num_tasks);
153 const int num_tasks = tasks->
start_min.size();
155 tasks_by_start_min_.resize(num_tasks);
156 std::iota(tasks_by_start_min_.begin(), tasks_by_start_min_.end(), 0);
158 tasks_by_start_min_.begin(), tasks_by_start_min_.end(),
159 [&](
int i,
int j) { return tasks->start_min[i] < tasks->start_min[j]; });
160 event_of_task_.resize(num_tasks);
161 for (
int event = 0;
event < num_tasks; ++event) {
162 event_of_task_[tasks_by_start_min_[event]] = event;
165 tasks_by_end_max_.resize(num_tasks);
166 std::iota(tasks_by_end_max_.begin(), tasks_by_end_max_.end(), 0);
168 tasks_by_end_max_.begin(), tasks_by_end_max_.end(),
169 [&](
int i,
int j) { return tasks->end_max[i] < tasks->end_max[j]; });
173 theta_lambda_tree_.
Reset(num_tasks);
174 for (
const int task : tasks_by_end_max_) {
186 for (
int i = num_tasks - 1; i >= 0; --i) {
187 const int task = tasks_by_end_max_[i];
188 const int64_t envelope = theta_lambda_tree_.
GetEnvelope();
193 int64_t available_energy;
195 tasks->
end_max[task], &critical_event, &optional_event,
197 const int optional_task = tasks_by_start_min_[optional_event];
207 theta_lambda_tree_.
RemoveEvent(event_of_task_[task]);
214 const int num_tasks = tasks->
start_min.size();
216 tasks_by_start_min_.resize(num_tasks);
217 std::iota(tasks_by_start_min_.begin(), tasks_by_start_min_.end(), 0);
219 tasks_by_start_min_.begin(), tasks_by_start_min_.end(),
220 [&](
int i,
int j) { return tasks->start_min[i] < tasks->start_min[j]; });
221 event_of_task_.resize(num_tasks);
222 for (
int event = 0;
event < num_tasks; ++event) {
223 event_of_task_[tasks_by_start_min_[event]] = event;
225 theta_lambda_tree_.
Reset(num_tasks);
229 nonchain_tasks_by_start_max_.resize(num_tasks - num_chain_tasks);
230 std::iota(nonchain_tasks_by_start_max_.begin(),
231 nonchain_tasks_by_start_max_.end(), num_chain_tasks);
232 std::sort(nonchain_tasks_by_start_max_.begin(),
233 nonchain_tasks_by_start_max_.end(), [&tasks](
int i,
int j) {
234 return tasks->end_max[i] - tasks->duration_min[i] <
235 tasks->end_max[j] - tasks->duration_min[j];
240 int index_nonchain = 0;
241 for (
int i = 0; i < num_chain_tasks; ++i) {
244 while (index_nonchain < nonchain_tasks_by_start_max_.size()) {
245 const int task = nonchain_tasks_by_start_max_[index_nonchain];
250 event_of_task_[task], tasks->
start_min[task],
256 const int64_t new_start_min = theta_lambda_tree_.
GetEnvelope();
268 const int num_tasks = tasks->
start_min.size();
269 for (
int task = 0; task < num_tasks; ++task) {
305 const int route_start = 0;
307 const int num_tasks = tasks->
start_min.size();
326 for (
int task = tasks->
num_chain_tasks + 1; task < num_tasks; ++task) {
330 for (
int task = num_tasks - 2; task >= tasks->
num_chain_tasks; --task) {
336 while (index_break_by_emax < num_tasks &&
337 tasks->
end_max[index_break_by_emax] <= tasks->
end_min[route_start]) {
338 ++index_break_by_emax;
341 if (index_break_by_emax == num_tasks) {
357 int64_t xor_active_tasks = route_start;
358 int num_active_tasks = 1;
360 const int64_t route_start_time =
362 const int64_t route_end_time = tasks->
start_min[route_end];
366 int index_break_by_smin = index_break_by_emax;
367 while (index_break_by_emax < num_tasks) {
369 int64_t current_time =
371 if (index_break_by_smin < num_tasks) {
375 if (previous_time < route_start_time && route_start_time < current_time) {
376 current_time = route_start_time;
378 if (previous_time < route_end_time && route_end_time < current_time) {
379 current_time = route_end_time;
383 if (num_active_tasks == 1) {
386 if (xor_active_tasks != route_end) {
387 tasks->
end_min[xor_active_tasks] =
389 CapSub(current_time, max_distance));
390 if (xor_active_tasks != route_start) {
394 minimum_break_duration,
395 CapSub(
CapSub(current_time, max_distance), previous_time)));
400 while (index_break_by_smin < num_tasks &&
401 current_time == tasks->
start_min[index_break_by_smin]) {
403 minimum_break_duration) {
404 xor_active_tasks ^= index_break_by_smin;
407 ++index_break_by_smin;
409 while (index_break_by_emax < num_tasks &&
413 minimum_break_duration) {
414 xor_active_tasks ^= index_break_by_emax;
417 ++index_break_by_emax;
419 if (current_time == route_start_time) {
420 xor_active_tasks ^= route_start;
423 if (current_time == route_end_time) {
424 xor_active_tasks ^= route_end;
429 if (num_active_tasks <= 0)
return false;
430 if (num_active_tasks == 1) {
431 if (xor_active_tasks != route_start) {
436 if (xor_active_tasks != route_end) {
438 tasks->
duration_min[xor_active_tasks], minimum_break_duration);
442 previous_time = current_time;
450 if (num_chain_tasks < 1)
return true;
455 int64_t sum_chain_durations = 0;
456 const auto duration_start = tasks->
duration_min.begin();
457 const auto duration_end = tasks->
duration_min.begin() + num_chain_tasks;
458 for (
auto it = duration_start; it != duration_end; ++it) {
459 sum_chain_durations =
CapAdd(sum_chain_durations, *it);
461 int64_t sum_forced_nonchain_durations = 0;
462 for (
int i = num_chain_tasks; i < tasks->
start_min.size(); ++i) {
468 sum_forced_nonchain_durations =
473 CapAdd(sum_chain_durations, sum_forced_nonchain_durations));
477 const int64_t end_minus_start =
491 if (num_chain_tasks < 1)
return true;
492 if (num_chain_tasks == tasks->
start_min.size())
return true;
493 const int task_index = num_chain_tasks;
495 const int64_t min_possible_chain_end = tasks->
end_min[num_chain_tasks - 1];
496 const int64_t max_possible_chain_start = tasks->
start_max[0];
498 int64_t total_duration = 0;
500 total_duration_before_.resize(num_chain_tasks);
501 for (
int i = 0; i < num_chain_tasks; ++i) {
502 total_duration_before_[i] = total_duration;
512 const int64_t chain_span_min =
513 min_possible_chain_end -
515 if (chain_span_min > tasks->
span_max) {
530 bool schedule_is_feasible =
false;
531 for (
int i = 0; i < num_chain_tasks; ++i) {
536 const int64_t block_start_min =
539 const int64_t block_start_max =
542 if (block_start_min > block_start_max)
continue;
556 const int64_t head_inflection =
557 max_possible_chain_start + total_duration_before_[i];
560 const int64_t tail_inflection =
561 min_possible_chain_end - (total_duration - total_duration_before_[i]) -
575 const int64_t optimal_interval_min_start =
576 std::min(head_inflection, tail_inflection);
577 const int64_t optimal_interval_max_start =
578 std::max(head_inflection, tail_inflection);
581 int64_t block_start =
std::max(optimal_interval_min_start, block_start_min);
585 if (optimal_interval_max_start < block_start_min) {
587 block_start = block_start_min;
588 }
else if (block_start_max < optimal_interval_min_start) {
590 block_start = block_start_max;
593 const int64_t head_duration =
594 std::max(block_start, head_inflection) - max_possible_chain_start;
595 const int64_t tail_duration =
596 min_possible_chain_end -
std::min(block_start, tail_inflection);
597 const int64_t optimal_span_at_i = head_duration + tail_duration;
598 span_min =
std::min(span_min, optimal_span_at_i);
599 schedule_is_feasible =
true;
601 if (!schedule_is_feasible || span_min > tasks->
span_max) {
613 const int num_nodes = path.size();
616 for (
int i = 0; i < num_nodes; ++i) {
617 const int64_t cumul_min = dimension.
CumulVar(path[i])->
Min();
618 const int64_t cumul_max = dimension.
CumulVar(path[i])->
Max();
623 const int64_t before_visit =
625 const int64_t after_visit =
626 (i == num_nodes - 1) ? 0 : travel_bounds.
pre_travels[i];
636 if (i == num_nodes - 1)
break;
643 const int64_t pre_travel = travel_bounds.
pre_travels[i];
644 const int64_t post_travel = travel_bounds.
post_travels[i];
649 CapAdd(pre_travel, post_travel))));
654 CapAdd(pre_travel, post_travel))));
670 const int num_travels = travel_bounds->
min_travels.size();
710 model_(dimension->
model()),
711 dimension_(dimension) {
712 vehicle_demons_.resize(model_->
vehicles());
716 for (
int vehicle = 0; vehicle < model_->
vehicles(); vehicle++) {
722 solver(),
this, &GlobalVehicleBreaksConstraint::PropagateVehicle,
723 "PropagateVehicle", vehicle);
726 interval->WhenAnything(vehicle_demons_[vehicle]);
729 const int num_cumuls = dimension_->
cumuls().size();
730 const int num_nexts = model_->
Nexts().size();
731 for (
int node = 0; node < num_cumuls; node++) {
733 solver(),
this, &GlobalVehicleBreaksConstraint::PropagateNode,
734 "PropagateNode", node);
735 if (node < num_nexts) {
745 for (
int vehicle = 0; vehicle < model_->
vehicles(); vehicle++) {
748 PropagateVehicle(vehicle);
756void GlobalVehicleBreaksConstraint::PropagateNode(
int node) {
759 if (vehicle < 0 || vehicle_demons_[vehicle] ==
nullptr)
return;
763void GlobalVehicleBreaksConstraint::FillPartialPathOfVehicle(
int vehicle) {
765 int current = model_->
Start(vehicle);
766 while (!model_->
IsEnd(current)) {
767 path_.push_back(current);
770 : model_->
End(vehicle);
772 path_.push_back(current);
775void GlobalVehicleBreaksConstraint::FillPathTravels(
776 const std::vector<int64_t>& path) {
777 const int num_travels = path.size() - 1;
780 for (
int i = 0; i < num_travels; ++i) {
788void GlobalVehicleBreaksConstraint::PropagateVehicle(
int vehicle) {
790 FillPartialPathOfVehicle(vehicle);
791 const int num_nodes = path_.size();
792 FillPathTravels(path_);
796 travel_bounds_.
pre_travels.assign(num_nodes - 1, 0);
832 task_translators_.clear();
833 for (
int i = 0; i < num_nodes; ++i) {
834 const int64_t before_visit =
836 const int64_t after_visit =
837 (i == num_nodes - 1) ? 0 : travel_bounds_.
pre_travels[i];
838 task_translators_.emplace_back(dimension_->
CumulVar(path_[i]), before_visit,
840 if (i == num_nodes - 1)
break;
841 task_translators_.emplace_back();
845 if (!
interval->MustBePerformed())
continue;
846 task_translators_.emplace_back(
interval);
850 const int num_tasks = tasks_.
start_min.size();
851 for (
int task = 0; task < num_tasks; ++task) {
852 task_translators_[task].SetStartMin(tasks_.
start_min[task]);
853 task_translators_[task].SetStartMax(tasks_.
start_max[task]);
854 task_translators_[task].SetDurationMin(tasks_.
duration_min[task]);
855 task_translators_[task].SetEndMin(tasks_.
end_min[task]);
856 task_translators_[task].SetEndMax(tasks_.
end_max[task]);
864 const int64_t last_bound_arc =
865 num_nodes - 2 - (model_->
NextVar(path_[num_nodes - 2])->
Bound() ? 0 : 1);
866 for (
int i = 0; i <= last_bound_arc; ++i) {
867 const int64_t arc_start_max =
870 const int64_t arc_end_min =
872 i < num_nodes - 2 ? travel_bounds_.
pre_travels[i + 1] : 0);
873 int64_t total_break_inside_arc = 0;
876 if (!
interval->MustBePerformed())
continue;
877 const int64_t interval_start_max =
interval->StartMax();
878 const int64_t interval_end_min =
interval->EndMin();
879 const int64_t interval_duration_min =
interval->DurationMin();
882 if (arc_start_max < interval_end_min &&
883 interval_start_max < arc_end_min) {
884 total_break_inside_arc += interval_duration_min;
893 bool has_optional =
false;
901 if (!has_optional)
return;
903 const std::vector<IntervalVar*>& break_intervals =
905 for (
int pos = 0; pos < num_nodes - 1; ++pos) {
906 const int64_t current_slack_max = dimension_->
SlackVar(path_[pos])->
Max();
907 const int64_t visit_start_offset =
909 const int64_t visit_start_max =
911 const int64_t visit_end_offset =
912 (pos < num_nodes - 1) ? travel_bounds_.
pre_travels[pos] : 0;
913 const int64_t visit_end_min =
916 for (IntervalVar*
interval : break_intervals) {
917 if (!
interval->MayBePerformed())
continue;
918 const bool interval_is_performed =
interval->MustBePerformed();
919 const int64_t interval_start_max =
interval->StartMax();
920 const int64_t interval_end_min =
interval->EndMin();
921 const int64_t interval_duration_min =
interval->DurationMin();
924 if (pos < num_nodes - 1 && interval_duration_min > current_slack_max) {
927 const int64_t arc_start_offset =
929 const int64_t arc_start_max = visit_start_max;
930 const int64_t arc_end_offset =
931 (pos < num_nodes - 2) ? travel_bounds_.
pre_travels[pos + 1] : 0;
932 const int64_t arc_end_min =
935 if (arc_start_max < interval_end_min) {
937 if (interval_is_performed) {
938 dimension_->
CumulVar(path_[pos + 1])
943 if (interval_start_max < arc_end_min) {
945 if (interval_is_performed) {
955 if (visit_start_max < interval_end_min) {
956 interval->SetStartMin(visit_end_min);
957 if (interval_is_performed) {
963 if (interval_start_max < visit_end_min) {
964 interval->SetEndMax(visit_start_max);
965 if (interval_is_performed) {
975class VehicleBreaksFilter :
public BasePathFilter {
977 VehicleBreaksFilter(
const RoutingModel& routing_model,
978 const RoutingDimension& dimension);
979 std::string DebugString()
const override {
return "VehicleBreaksFilter"; }
980 bool AcceptPath(int64_t path_start, int64_t chain_start,
981 int64_t chain_end)
override;
985 void FillPathOfVehicle(int64_t vehicle);
986 std::vector<int64_t> path_;
988 const RoutingModel& model_;
989 const RoutingDimension& dimension_;
991 DisjunctivePropagator disjunctive_propagator_;
992 DisjunctivePropagator::Tasks tasks_;
994 std::vector<int64_t> old_start_min_;
995 std::vector<int64_t> old_start_max_;
996 std::vector<int64_t> old_end_min_;
997 std::vector<int64_t> old_end_max_;
999 std::vector<int> start_to_vehicle_;
1000 TravelBounds travel_bounds_;
1003VehicleBreaksFilter::VehicleBreaksFilter(
const RoutingModel& routing_model,
1004 const RoutingDimension& dimension)
1005 : BasePathFilter(routing_model.Nexts(),
1006 routing_model.Size() + routing_model.vehicles()),
1007 model_(routing_model),
1008 dimension_(dimension) {
1010 start_to_vehicle_.resize(Size(), -1);
1011 for (
int i = 0; i < routing_model.vehicles(); ++i) {
1012 start_to_vehicle_[routing_model.Start(i)] = i;
1016void VehicleBreaksFilter::FillPathOfVehicle(int64_t vehicle) {
1018 int current = model_.
Start(vehicle);
1019 while (!model_.
IsEnd(current)) {
1020 path_.push_back(current);
1021 current = GetNext(current);
1023 path_.push_back(current);
1026bool VehicleBreaksFilter::AcceptPath(int64_t path_start, int64_t chain_start,
1027 int64_t chain_end) {
1028 const int vehicle = start_to_vehicle_[path_start];
1034 FillPathOfVehicle(vehicle);
1039 tasks_.num_chain_tasks = tasks_.start_min.size();
1043 tasks_.forbidden_intervals.clear();
1044 if (std::any_of(path_.begin(), path_.end(), [
this](int64_t node) {
1045 return dimension_.forbidden_intervals()[node].NumIntervals() > 0;
1047 tasks_.forbidden_intervals.assign(tasks_.start_min.size(),
nullptr);
1048 for (
int i = 0; i < path_.size(); ++i) {
1049 tasks_.forbidden_intervals[2 * i] =
1054 tasks_.distance_duration =
1059 bool is_feasible =
true;
1060 int maximum_num_iterations = 8;
1061 while (--maximum_num_iterations >= 0) {
1062 old_start_min_ = tasks_.start_min;
1063 old_start_max_ = tasks_.start_max;
1064 old_end_min_ = tasks_.end_min;
1065 old_end_max_ = tasks_.end_max;
1066 is_feasible = disjunctive_propagator_.
Propagate(&tasks_);
1067 if (!is_feasible)
break;
1069 if ((old_start_min_ == tasks_.start_min) &&
1070 (old_start_max_ == tasks_.start_max) &&
1071 (old_end_min_ == tasks_.end_min) && (old_end_max_ == tasks_.end_max)) {
1083 new VehicleBreaksFilter(routing_model, dimension));
#define DCHECK_LE(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
A constraint is the main modeling object.
A Demon is the base element of a propagation queue.
bool EdgeFinding(Tasks *tasks)
Does edge-finding deductions on all tasks.
bool Precedences(Tasks *tasks)
Propagates the deductions from the chain of precedences, if there is one.
bool DistanceDuration(Tasks *tasks)
Propagates distance_duration constraints, if any.
bool MirrorTasks(Tasks *tasks)
Transforms the problem with a time symmetry centered in 0.
bool ForbiddenIntervals(Tasks *tasks)
Tasks might have holes in their domain, this enforces such holes.
bool Propagate(Tasks *tasks)
Computes new bounds for all tasks, returns false if infeasible.
bool DetectablePrecedencesWithChain(Tasks *tasks)
Does detectable precedences deductions on tasks in the chain precedence, taking the time windows of n...
bool ChainSpanMinDynamic(Tasks *tasks)
Computes a lower bound of the span of the chain, taking into account only the first nonchain task.
bool ChainSpanMin(Tasks *tasks)
Propagates a lower bound of the chain span, end[num_chain_tasks] - start[0], to span_min.
void Post() override
This method is called when the constraint is processed by the solver.
void InitialPropagate() override
This method performs the initial propagation of the constraint.
GlobalVehicleBreaksConstraint(const RoutingDimension *dimension)
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual int64_t Min() const =0
virtual void SetMax(int64_t m)=0
virtual void SetMin(int64_t m)=0
virtual int64_t Max() const =0
virtual void WhenRange(Demon *d)=0
Attach a demon that will watch the min or the max of the expression.
virtual void WhenBound(Demon *d)=0
This method attaches a demon that will be awakened when the variable is bound.
Interval variables are often used in scheduling.
virtual int64_t DurationMax() const =0
virtual int64_t DurationMin() const =0
These methods query, set, and watch the duration of the interval var.
virtual bool MustBePerformed() const =0
These methods query, set, and watch the performed status of the interval var.
virtual int64_t EndMin() const =0
These methods query, set, and watch the end position of the interval var.
virtual int64_t StartMin() const =0
These methods query, set, and watch the start position of the interval var.
virtual int64_t EndMax() const =0
virtual int64_t StartMax() const =0
void EnqueueDelayedDemon(Demon *const d)
This method pushes the demon onto the propagation queue.
Dimensions represent quantities accumulated at nodes along the routes.
const std::vector< IntVar * > & cumuls() const
Like CumulVar(), TransitVar(), SlackVar() but return the whole variable vectors instead (indexed by i...
IntVar * CumulVar(int64_t index) const
Get the cumul, transit and slack variables for the given node (given as int64_t var index).
IntVar * SlackVar(int64_t index) const
const RoutingModel::TransitCallback2 & transit_evaluator(int vehicle) const
Returns the callback evaluating the transit value between two node indices for a given vehicle.
IntVar * FixedTransitVar(int64_t index) const
bool HasBreakConstraints() const
Returns true if any break interval or break distance was defined.
int GetPreTravelEvaluatorOfVehicle(int vehicle) const
!defined(SWIGPYTHON)
RoutingModel * model() const
Returns the model on which the dimension was created.
const std::vector< IntervalVar * > & GetBreakIntervalsOfVehicle(int vehicle) const
Returns the break intervals set by SetBreakIntervalsOfVehicle().
const std::vector< SortedDisjointIntervalList > & forbidden_intervals() const
Returns forbidden intervals for each node.
const std::vector< std::pair< int64_t, int64_t > > & GetBreakDistanceDurationOfVehicle(int vehicle) const
Returns the pairs (distance, duration) specified by break distance constraints.
int GetPostTravelEvaluatorOfVehicle(int vehicle) const
Solver * solver() const
Returns the underlying constraint solver.
const TransitCallback2 & TransitCallback(int callback_index) const
IntVar * VehicleVar(int64_t index) const
Returns the vehicle variable of the node corresponding to index.
IntVar * NextVar(int64_t index) const
!defined(SWIGPYTHON)
const std::vector< IntVar * > & Nexts() const
Returns all next variables of the model, such that Nexts(i) is the next variable of the node correspo...
int64_t Start(int vehicle) const
Model inspection.
int vehicles() const
Returns the number of vehicle routes in the model.
bool IsEnd(int64_t index) const
Returns true if 'index' represents the last node of a route.
int64_t End(int vehicle) const
Returns the variable index of the ending node of a vehicle route.
void Fail()
Abandon the current branch in the search tree. A backtrack will follow.
T * RevAlloc(T *object)
Registers the given object as being reversible.
void GetEventsWithOptionalEnvelopeGreaterThan(IntegerType target_envelope, int *critical_event, int *optional_event, IntegerType *available_energy) const
IntegerType GetOptionalEnvelope() const
void RemoveEvent(int event)
void Reset(int num_events)
void AddOrUpdateOptionalEvent(int event, IntegerType initial_envelope_opt, IntegerType energy_max)
void AddOrUpdateEvent(int event, IntegerType initial_envelope, IntegerType energy_min, IntegerType energy_max)
IntegerType GetEnvelope() const
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
IntVarLocalSearchFilter * MakeVehicleBreaksFilter(const RoutingModel &routing_model, const RoutingDimension &dimension)
int64_t CapSub(int64_t x, int64_t y)
void AppendTasksFromIntervals(const std::vector< IntervalVar * > &intervals, DisjunctivePropagator::Tasks *tasks)
void AppendTasksFromPath(const std::vector< int64_t > &path, const TravelBounds &travel_bounds, const RoutingDimension &dimension, DisjunctivePropagator::Tasks *tasks)
void FillPathEvaluation(const std::vector< int64_t > &path, const RoutingModel::TransitCallback2 &evaluator, std::vector< int64_t > *values)
Demon * MakeDelayedConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
void FillTravelBoundsOfVehicle(int vehicle, const std::vector< int64_t > &path, const RoutingDimension &dimension, TravelBounds *travel_bounds)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
A structure to hold tasks described by their features.
std::vector< std::pair< int64_t, int64_t > > distance_duration
std::vector< int64_t > end_min
std::vector< int64_t > start_min
std::vector< const SortedDisjointIntervalList * > forbidden_intervals
std::vector< bool > is_preemptible
std::vector< int64_t > end_max
std::vector< int64_t > duration_max
std::vector< int64_t > start_max
std::vector< int64_t > duration_min
std::vector< int64_t > post_travels
std::vector< int64_t > max_travels
std::vector< int64_t > pre_travels
std::vector< int64_t > min_travels