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_max[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];
364 while (index_break_by_emax < num_tasks) {
366 int64_t current_time =
368 if (index_break_by_smin < num_tasks) {
372 if (previous_time < route_start_time && route_start_time < current_time) {
373 current_time = route_start_time;
375 if (previous_time < route_end_time && route_end_time < current_time) {
376 current_time = route_end_time;
380 if (num_active_tasks == 1) {
383 if (xor_active_tasks != route_end) {
384 tasks->
end_min[xor_active_tasks] =
386 CapSub(current_time, max_distance));
387 if (xor_active_tasks != route_start) {
391 minimum_break_duration,
392 CapSub(
CapSub(current_time, max_distance), previous_time)));
397 while (index_break_by_smin < num_tasks &&
398 current_time == tasks->
start_min[index_break_by_smin]) {
400 minimum_break_duration) {
401 xor_active_tasks ^= index_break_by_smin;
404 ++index_break_by_smin;
406 while (index_break_by_emax < num_tasks &&
410 minimum_break_duration) {
411 xor_active_tasks ^= index_break_by_emax;
414 ++index_break_by_emax;
416 if (current_time == route_start_time) {
417 xor_active_tasks ^= route_start;
420 if (current_time == route_end_time) {
421 xor_active_tasks ^= route_end;
426 if (num_active_tasks <= 0)
return false;
427 if (num_active_tasks == 1) {
428 if (xor_active_tasks != route_start) {
433 if (xor_active_tasks != route_end) {
435 tasks->
duration_min[xor_active_tasks], minimum_break_duration);
439 previous_time = current_time;
447 if (num_chain_tasks < 1)
return true;
452 int64_t sum_chain_durations = 0;
453 const auto duration_start = tasks->
duration_min.begin();
454 const auto duration_end = tasks->
duration_min.begin() + num_chain_tasks;
455 for (
auto it = duration_start; it != duration_end; ++it) {
456 sum_chain_durations =
CapAdd(sum_chain_durations, *it);
458 int64_t sum_forced_nonchain_durations = 0;
459 for (
int i = num_chain_tasks; i < tasks->
start_min.size(); ++i) {
465 sum_forced_nonchain_durations =
470 CapAdd(sum_chain_durations, sum_forced_nonchain_durations));
474 const int64_t end_minus_start =
488 if (num_chain_tasks < 1)
return true;
489 if (num_chain_tasks == tasks->
start_min.size())
return true;
490 const int task_index = num_chain_tasks;
492 const int64_t min_possible_chain_end = tasks->
end_min[num_chain_tasks - 1];
493 const int64_t max_possible_chain_start = tasks->
start_max[0];
495 int64_t total_duration = 0;
497 total_duration_before_.resize(num_chain_tasks);
498 for (
int i = 0; i < num_chain_tasks; ++i) {
499 total_duration_before_[i] = total_duration;
509 const int64_t chain_span_min =
510 min_possible_chain_end -
512 if (chain_span_min > tasks->
span_max) {
527 bool schedule_is_feasible =
false;
528 for (
int i = 0; i < num_chain_tasks; ++i) {
533 const int64_t block_start_min =
536 const int64_t block_start_max =
539 if (block_start_min > block_start_max)
continue;
553 const int64_t head_inflection =
554 max_possible_chain_start + total_duration_before_[i];
557 const int64_t tail_inflection =
558 min_possible_chain_end - (total_duration - total_duration_before_[i]) -
572 const int64_t optimal_interval_min_start =
573 std::min(head_inflection, tail_inflection);
574 const int64_t optimal_interval_max_start =
575 std::max(head_inflection, tail_inflection);
578 int64_t block_start =
std::max(optimal_interval_min_start, block_start_min);
582 if (optimal_interval_max_start < block_start_min) {
584 block_start = block_start_min;
585 }
else if (block_start_max < optimal_interval_min_start) {
587 block_start = block_start_max;
590 const int64_t head_duration =
591 std::max(block_start, head_inflection) - max_possible_chain_start;
592 const int64_t tail_duration =
593 min_possible_chain_end -
std::min(block_start, tail_inflection);
594 const int64_t optimal_span_at_i = head_duration + tail_duration;
595 span_min =
std::min(span_min, optimal_span_at_i);
596 schedule_is_feasible =
true;
598 if (!schedule_is_feasible || span_min > tasks->
span_max) {
610 const int num_nodes = path.size();
613 for (
int i = 0; i < num_nodes; ++i) {
614 const int64_t cumul_min = dimension.
CumulVar(path[i])->
Min();
615 const int64_t cumul_max = dimension.
CumulVar(path[i])->
Max();
620 const int64_t before_visit =
622 const int64_t after_visit =
623 (i == num_nodes - 1) ? 0 : travel_bounds.
pre_travels[i];
633 if (i == num_nodes - 1)
break;
640 const int64_t pre_travel = travel_bounds.
pre_travels[i];
641 const int64_t post_travel = travel_bounds.
post_travels[i];
646 CapAdd(pre_travel, post_travel))));
651 CapAdd(pre_travel, post_travel))));
667 const int num_travels = travel_bounds->
min_travels.size();
707 model_(dimension->
model()),
708 dimension_(dimension) {
709 vehicle_demons_.resize(model_->
vehicles());
713 for (
int vehicle = 0; vehicle < model_->
vehicles(); vehicle++) {
719 solver(),
this, &GlobalVehicleBreaksConstraint::PropagateVehicle,
720 "PropagateVehicle", vehicle);
723 interval->WhenAnything(vehicle_demons_[vehicle]);
726 const int num_cumuls = dimension_->
cumuls().size();
727 const int num_nexts = model_->
Nexts().size();
728 for (
int node = 0; node < num_cumuls; node++) {
730 solver(),
this, &GlobalVehicleBreaksConstraint::PropagateNode,
731 "PropagateNode", node);
732 if (node < num_nexts) {
742 for (
int vehicle = 0; vehicle < model_->
vehicles(); vehicle++) {
745 PropagateVehicle(vehicle);
753 void GlobalVehicleBreaksConstraint::PropagateNode(
int node) {
756 if (vehicle < 0 || vehicle_demons_[vehicle] ==
nullptr)
return;
760 void GlobalVehicleBreaksConstraint::FillPartialPathOfVehicle(
int vehicle) {
762 int current = model_->
Start(vehicle);
763 while (!model_->
IsEnd(current)) {
764 path_.push_back(current);
767 : model_->
End(vehicle);
769 path_.push_back(current);
772 void GlobalVehicleBreaksConstraint::FillPathTravels(
773 const std::vector<int64_t>& path) {
774 const int num_travels = path.size() - 1;
777 for (
int i = 0; i < num_travels; ++i) {
785 void GlobalVehicleBreaksConstraint::PropagateVehicle(
int vehicle) {
787 FillPartialPathOfVehicle(vehicle);
788 const int num_nodes = path_.size();
789 FillPathTravels(path_);
793 travel_bounds_.
pre_travels.assign(num_nodes - 1, 0);
829 task_translators_.clear();
830 for (
int i = 0; i < num_nodes; ++i) {
831 const int64_t before_visit =
833 const int64_t after_visit =
834 (i == num_nodes - 1) ? 0 : travel_bounds_.
pre_travels[i];
835 task_translators_.emplace_back(dimension_->
CumulVar(path_[i]), before_visit,
837 if (i == num_nodes - 1)
break;
838 task_translators_.emplace_back();
842 if (!
interval->MustBePerformed())
continue;
843 task_translators_.emplace_back(
interval);
847 const int num_tasks = tasks_.
start_min.size();
848 for (
int task = 0; task < num_tasks; ++task) {
849 task_translators_[task].SetStartMin(tasks_.
start_min[task]);
850 task_translators_[task].SetStartMax(tasks_.
start_max[task]);
851 task_translators_[task].SetDurationMin(tasks_.
duration_min[task]);
852 task_translators_[task].SetEndMin(tasks_.
end_min[task]);
853 task_translators_[task].SetEndMax(tasks_.
end_max[task]);
861 const int64_t last_bound_arc =
862 num_nodes - 2 - (model_->
NextVar(path_[num_nodes - 2])->
Bound() ? 0 : 1);
863 for (
int i = 0; i <= last_bound_arc; ++i) {
864 const int64_t arc_start_max =
867 const int64_t arc_end_min =
869 i < num_nodes - 2 ? travel_bounds_.
pre_travels[i + 1] : 0);
870 int64_t total_break_inside_arc = 0;
873 if (!
interval->MustBePerformed())
continue;
874 const int64_t interval_start_max =
interval->StartMax();
875 const int64_t interval_end_min =
interval->EndMin();
876 const int64_t interval_duration_min =
interval->DurationMin();
879 if (arc_start_max < interval_end_min &&
880 interval_start_max < arc_end_min) {
881 total_break_inside_arc += interval_duration_min;
890 bool has_optional =
false;
898 if (!has_optional)
return;
900 const std::vector<IntervalVar*>& break_intervals =
902 for (
int pos = 0; pos < num_nodes - 1; ++pos) {
903 const int64_t current_slack_max = dimension_->
SlackVar(path_[pos])->
Max();
904 const int64_t visit_start_offset =
906 const int64_t visit_start_max =
908 const int64_t visit_end_offset =
909 (pos < num_nodes - 1) ? travel_bounds_.
pre_travels[pos] : 0;
910 const int64_t visit_end_min =
913 for (IntervalVar*
interval : break_intervals) {
914 if (!
interval->MayBePerformed())
continue;
915 const bool interval_is_performed =
interval->MustBePerformed();
916 const int64_t interval_start_max =
interval->StartMax();
917 const int64_t interval_end_min =
interval->EndMin();
918 const int64_t interval_duration_min =
interval->DurationMin();
921 if (pos < num_nodes - 1 && interval_duration_min > current_slack_max) {
924 const int64_t arc_start_offset =
926 const int64_t arc_start_max = visit_start_max;
927 const int64_t arc_end_offset =
928 (pos < num_nodes - 2) ? travel_bounds_.
pre_travels[pos + 1] : 0;
929 const int64_t arc_end_min =
932 if (arc_start_max < interval_end_min) {
934 if (interval_is_performed) {
935 dimension_->
CumulVar(path_[pos + 1])
940 if (interval_start_max < arc_end_min) {
942 if (interval_is_performed) {
952 if (visit_start_max < interval_end_min) {
953 interval->SetStartMin(visit_end_min);
954 if (interval_is_performed) {
960 if (interval_start_max < visit_end_min) {
961 interval->SetEndMax(visit_start_max);
962 if (interval_is_performed) {
972 class VehicleBreaksFilter :
public BasePathFilter {
974 VehicleBreaksFilter(
const RoutingModel& routing_model,
975 const RoutingDimension& dimension);
976 std::string DebugString()
const override {
return "VehicleBreaksFilter"; }
977 bool AcceptPath(int64_t path_start, int64_t chain_start,
978 int64_t chain_end)
override;
982 void FillPathOfVehicle(int64_t vehicle);
983 std::vector<int64_t> path_;
985 const RoutingModel& model_;
986 const RoutingDimension& dimension_;
988 DisjunctivePropagator disjunctive_propagator_;
989 DisjunctivePropagator::Tasks tasks_;
991 std::vector<int64_t> old_start_min_;
992 std::vector<int64_t> old_start_max_;
993 std::vector<int64_t> old_end_min_;
994 std::vector<int64_t> old_end_max_;
996 std::vector<int> start_to_vehicle_;
997 TravelBounds travel_bounds_;
1000 VehicleBreaksFilter::VehicleBreaksFilter(
const RoutingModel& routing_model,
1001 const RoutingDimension& dimension)
1002 : BasePathFilter(routing_model.Nexts(),
1003 routing_model.Size() + routing_model.vehicles()),
1004 model_(routing_model),
1005 dimension_(dimension) {
1007 start_to_vehicle_.resize(Size(), -1);
1008 for (
int i = 0; i < routing_model.vehicles(); ++i) {
1009 start_to_vehicle_[routing_model.Start(i)] = i;
1013 void VehicleBreaksFilter::FillPathOfVehicle(int64_t vehicle) {
1015 int current = model_.
Start(vehicle);
1016 while (!model_.
IsEnd(current)) {
1017 path_.push_back(current);
1018 current = GetNext(current);
1020 path_.push_back(current);
1023 bool VehicleBreaksFilter::AcceptPath(int64_t path_start, int64_t chain_start,
1024 int64_t chain_end) {
1025 const int vehicle = start_to_vehicle_[path_start];
1031 FillPathOfVehicle(vehicle);
1036 tasks_.num_chain_tasks = tasks_.start_min.size();
1040 tasks_.forbidden_intervals.clear();
1041 if (std::any_of(path_.begin(), path_.end(), [
this](int64_t node) {
1042 return dimension_.forbidden_intervals()[node].NumIntervals() > 0;
1044 tasks_.forbidden_intervals.assign(tasks_.start_min.size(),
nullptr);
1045 for (
int i = 0; i < path_.size(); ++i) {
1046 tasks_.forbidden_intervals[2 * i] =
1051 tasks_.distance_duration =
1056 bool is_feasible =
true;
1057 int maximum_num_iterations = 8;
1058 while (--maximum_num_iterations >= 0) {
1059 old_start_min_ = tasks_.start_min;
1060 old_start_max_ = tasks_.start_max;
1061 old_end_min_ = tasks_.end_min;
1062 old_end_max_ = tasks_.end_max;
1063 is_feasible = disjunctive_propagator_.
Propagate(&tasks_);
1064 if (!is_feasible)
break;
1066 if ((old_start_min_ == tasks_.start_min) &&
1067 (old_start_max_ == tasks_.start_max) &&
1068 (old_end_min_ == tasks_.end_min) && (old_end_max_ == tasks_.end_max)) {
1080 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 * FixedTransitVar(int64_t index) const
RoutingModel * model() const
Returns the model on which the dimension was created.
bool HasBreakConstraints() const
Returns true if any break interval or break distance was defined.
int GetPreTravelEvaluatorOfVehicle(int vehicle) const
!defined(SWIGPYTHON)
const std::vector< IntervalVar * > & GetBreakIntervalsOfVehicle(int vehicle) const
Returns the break intervals set by SetBreakIntervalsOfVehicle().
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 * CumulVar(int64_t index) const
Get the cumul, transit and slack variables for the given node (given as int64_t var index).
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
const std::vector< SortedDisjointIntervalList > & forbidden_intervals() const
Returns forbidden intervals for each node.
IntVar * NextVar(int64_t index) const
!defined(SWIGPYTHON)
IntVar * VehicleVar(int64_t index) const
Returns the vehicle variable of the node corresponding to index.
Solver * solver() const
Returns the underlying constraint solver.
int64_t Start(int vehicle) const
Model inspection.
int vehicles() const
Returns the number of vehicle routes in the model.
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...
bool IsEnd(int64_t index) const
Returns true if 'index' represents the last node of a route.
const TransitCallback2 & TransitCallback(int callback_index) const
int64_t End(int vehicle) const
Returns the variable index of the ending node of a vehicle route.
T * RevAlloc(T *object)
Registers the given object as being reversible.
void Fail()
Abandon the current branch in the search tree. A backtrack will follow.
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)
Demon * MakeDelayedConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
IntVarLocalSearchFilter * MakeVehicleBreaksFilter(const RoutingModel &routing_model, const RoutingDimension &dimension)
int64_t CapSub(int64_t x, int64_t y)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
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)
void FillTravelBoundsOfVehicle(int vehicle, const std::vector< int64_t > &path, const RoutingDimension &dimension, TravelBounds *travel_bounds)
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