24#include "absl/container/flat_hash_set.h"
25#include "absl/log/check.h"
26#include "absl/types/span.h"
40class SetValuesFromTargets :
public DecisionBuilder {
42 SetValuesFromTargets(std::vector<IntVar*> variables,
43 std::vector<int64_t> targets)
44 : variables_(
std::move(variables)),
45 targets_(
std::move(targets)),
47 steps_(variables_.
size(), 0) {
48 DCHECK_EQ(variables_.size(), targets_.size());
50 Decision*
Next(Solver* solver)
override {
51 int index = index_.Value();
52 while (
index < variables_.size() && variables_[
index]->Bound()) {
55 index_.SetValue(solver,
index);
56 if (
index >= variables_.size())
return nullptr;
57 const int64_t variable_min = variables_[
index]->Min();
58 const int64_t variable_max = variables_[
index]->Max();
61 if (targets_[
index] <= variable_min) {
62 return solver->MakeAssignVariableValue(variables_[
index], variable_min);
63 }
else if (targets_[
index] >= variable_max) {
64 return solver->MakeAssignVariableValue(variables_[
index], variable_max);
66 int64_t step = steps_[
index];
71 if (
value < variable_min || variable_max <
value) {
72 step = GetNextStep(step);
83 steps_.SetValue(solver,
index, GetNextStep(step));
84 return solver->MakeAssignVariableValueOrDoNothing(variables_[
index],
90 int64_t GetNextStep(int64_t step)
const {
91 return (step > 0) ? -step :
CapSub(1, step);
93 const std::vector<IntVar*> variables_;
94 const std::vector<int64_t> targets_;
96 RevArray<int64_t> steps_;
102 std::vector<IntVar*> variables,
103 std::vector<int64_t> targets) {
105 new SetValuesFromTargets(std::move(variables), std::move(targets)));
110bool DimensionFixedTransitsEqualTransitEvaluatorForVehicle(
111 const RoutingDimension& dimension,
int vehicle) {
112 const RoutingModel*
const model = dimension.model();
113 int node =
model->Start(vehicle);
114 while (!
model->IsEnd(node)) {
115 if (!
model->NextVar(node)->Bound()) {
118 const int next =
model->NextVar(node)->Value();
119 if (dimension.transit_evaluator(vehicle)(node,
next) !=
120 dimension.FixedTransitVar(node)->Value()) {
128bool DimensionFixedTransitsEqualTransitEvaluators(
129 const RoutingDimension& dimension) {
130 for (
int vehicle = 0; vehicle < dimension.model()->vehicles(); vehicle++) {
131 if (!DimensionFixedTransitsEqualTransitEvaluatorForVehicle(dimension,
141void AppendRouteCumulAndBreakVarAndValues(
142 const RoutingDimension& dimension,
int vehicle,
144 absl::Span<const int64_t>
break_values, std::vector<IntVar*>* variables,
145 std::vector<int64_t>* values) {
146 auto& vars = *variables;
147 auto& vals = *values;
148 DCHECK_EQ(vars.size(), vals.size());
149 const int old_num_values = vals.size();
151 const RoutingModel&
model = *dimension.model();
153 int current =
model.Start(vehicle);
155 vars.push_back(dimension.CumulVar(current));
156 if (!
model.IsEnd(current)) {
157 current =
model.NextVar(current)->Value();
163 if (dimension.HasBreakConstraints()) {
165 dimension.GetBreakIntervalsOfVehicle(vehicle)) {
171 DCHECK_EQ(vars.size(), vals.size());
172 int new_num_values = old_num_values;
173 for (
int j = old_num_values; j < vals.size(); ++j) {
175 if (vals[j] == std::numeric_limits<int64_t>::min())
continue;
177 if (vars[j]->Bound())
continue;
178 vals[new_num_values] = vals[j];
179 vars[new_num_values] = vars[j];
182 vars.resize(new_num_values);
183 vals.resize(new_num_values);
186class SetCumulsFromLocalDimensionCosts :
public DecisionBuilder {
188 SetCumulsFromLocalDimensionCosts(
189 LocalDimensionCumulOptimizer* lp_optimizer,
190 LocalDimensionCumulOptimizer* mp_optimizer,
bool optimize_and_pack,
191 std::vector<RoutingModel::RouteDimensionTravelInfo>
192 dimension_travel_info_per_route)
193 : model_(*lp_optimizer->dimension()->
model()),
194 dimension_(*lp_optimizer->dimension()),
195 lp_optimizer_(lp_optimizer),
196 mp_optimizer_(mp_optimizer),
197 rg_index_(model_.GetDimensionResourceGroupIndices(&dimension_).empty()
199 : model_.GetDimensionResourceGroupIndex(&dimension_)),
200 resource_group_(rg_index_ >= 0 ? model_.GetResourceGroup(rg_index_)
202 vehicle_resource_class_values_(model_.vehicles()),
203 optimize_and_pack_(optimize_and_pack),
204 dimension_travel_info_per_route_(
205 std::move(dimension_travel_info_per_route)),
207 if (!dimension_travel_info_per_route_.empty()) {
208 DCHECK(optimize_and_pack_);
209 DCHECK_EQ(dimension_travel_info_per_route_.size(), model_.vehicles());
213 Decision*
Next(Solver* solver)
override {
214 if (decision_level_.Value() == 2)
return nullptr;
215 if (decision_level_.Value() == 1) {
216 Decision* d = set_values_from_targets_->Next(solver);
217 if (d ==
nullptr) decision_level_.SetValue(solver, 2);
220 decision_level_.SetValue(solver, 1);
221 if (!FillCPVariablesAndValues(solver)) {
224 set_values_from_targets_ =
226 return solver->MakeAssignVariablesValuesOrDoNothing(cp_variables_,
231 using Resource = RoutingModel::ResourceGroup::Resource;
232 using RCIndex = RoutingModel::ResourceClassIndex;
233 using RouteDimensionTravelInfo = RoutingModel::RouteDimensionTravelInfo;
235 bool FillCPVariablesAndValues(Solver* solver) {
236 DCHECK(DimensionFixedTransitsEqualTransitEvaluators(dimension_));
237 cp_variables_.clear();
240 std::vector<int> vehicles_without_resource_assignment;
241 std::vector<int> vehicles_with_resource_assignment;
243 used_resources_per_class;
244 DetermineVehiclesRequiringResourceAssignment(
245 &vehicles_without_resource_assignment,
246 &vehicles_with_resource_assignment, &used_resources_per_class);
248 const auto next = [&
model = model_](int64_t n) {
249 return model.NextVar(n)->Value();
254 for (
int vehicle : vehicles_without_resource_assignment) {
255 solver->TopPeriodicCheck();
257 std::vector<int64_t> break_start_end_values;
259 &break_start_end_values)) {
262 AppendRouteCumulAndBreakVarAndValues(dimension_, vehicle,
cumul_values,
263 break_start_end_values,
264 &cp_variables_, &cp_values_);
267 if (vehicles_with_resource_assignment.empty()) {
273 std::vector<int> resource_indices;
274 if (!ComputeVehicleResourceClassValuesAndIndices(
275 vehicles_with_resource_assignment, used_resources_per_class,
next,
276 &resource_indices)) {
279 DCHECK_EQ(resource_indices.size(), model_.vehicles());
280 const int num_resource_classes = resource_group_->GetResourceClassesCount();
281 for (
int v : vehicles_with_resource_assignment) {
282 DCHECK(
next(model_.Start(v)) != model_.End(v) ||
283 model_.IsVehicleUsedWhenEmpty(v));
285 vehicle_resource_class_values_[v];
286 const int resource_index = resource_indices[v];
287 DCHECK_GE(resource_index, 0);
291 resource_group_->GetResourceClassIndex(resource_index).value();
292 const std::vector<int64_t>& optimal_cumul_values =
cumul_values[rc_index];
293 const std::vector<int64_t>& optimal_break_values =
break_values[rc_index];
294 AppendRouteCumulAndBreakVarAndValues(dimension_, v, optimal_cumul_values,
295 optimal_break_values, &cp_variables_,
298 const std::vector<IntVar*>& resource_vars =
299 model_.ResourceVars(rg_index_);
300 DCHECK_EQ(resource_vars.size(), resource_indices.size());
301 cp_variables_.insert(cp_variables_.end(), resource_vars.begin(),
302 resource_vars.end());
303 cp_values_.insert(cp_values_.end(), resource_indices.begin(),
304 resource_indices.end());
309 void DetermineVehiclesRequiringResourceAssignment(
310 std::vector<int>* vehicles_without_resource_assignment,
311 std::vector<int>* vehicles_with_resource_assignment,
313 used_resources_per_class)
const {
314 vehicles_without_resource_assignment->clear();
315 vehicles_with_resource_assignment->clear();
316 used_resources_per_class->clear();
318 vehicles_without_resource_assignment->reserve(model_.vehicles());
319 for (
int v = 0; v < model_.vehicles(); ++v) {
320 vehicles_without_resource_assignment->push_back(v);
324 DCHECK_NE(resource_group_,
nullptr);
325 const int num_vehicles_req_res =
326 resource_group_->GetVehiclesRequiringAResource().size();
327 vehicles_without_resource_assignment->reserve(model_.vehicles() -
328 num_vehicles_req_res);
329 vehicles_with_resource_assignment->reserve(num_vehicles_req_res);
330 used_resources_per_class->
resize(
331 resource_group_->GetResourceClassesCount());
332 for (
int v = 0; v < model_.vehicles(); ++v) {
333 if (!resource_group_->VehicleRequiresAResource(v)) {
334 vehicles_without_resource_assignment->push_back(v);
335 }
else if (model_.NextVar(model_.Start(v))->Value() == model_.End(v) &&
336 !model_.IsVehicleUsedWhenEmpty(v)) {
339 vehicles_without_resource_assignment->push_back(v);
340 }
else if (model_.ResourceVar(v, rg_index_)->Bound()) {
341 vehicles_without_resource_assignment->push_back(v);
342 const int resource_idx = model_.ResourceVar(v, rg_index_)->Value();
343 DCHECK_GE(resource_idx, 0);
344 used_resources_per_class
345 ->
at(resource_group_->GetResourceClassIndex(resource_idx))
346 .insert(resource_idx);
348 vehicles_with_resource_assignment->push_back(v);
353 bool ComputeCumulAndBreakValuesForVehicle(
354 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
356 std::vector<int64_t>* break_start_end_values) {
358 break_start_end_values->clear();
359 const RouteDimensionTravelInfo& dimension_travel_info =
360 dimension_travel_info_per_route_.empty()
361 ? RouteDimensionTravelInfo()
362 : dimension_travel_info_per_route_[vehicle];
363 const Resource* resource =
nullptr;
364 if (rg_index_ >= 0 && model_.ResourceVar(vehicle, rg_index_)->Bound()) {
365 const int resource_index =
366 model_.ResourceVar(vehicle, rg_index_)->Value();
367 if (resource_index >= 0) {
369 &model_.GetResourceGroup(rg_index_)->GetResource(resource_index);
372 const bool use_mp_optimizer =
373 dimension_.HasBreakConstraints() &&
374 !dimension_.GetBreakIntervalsOfVehicle(vehicle).empty();
375 LocalDimensionCumulOptimizer*
const optimizer =
376 use_mp_optimizer ? mp_optimizer_ : lp_optimizer_;
377 DCHECK_NE(optimizer,
nullptr);
380 ? optimizer->ComputePackedRouteCumuls(
381 vehicle, next_accessor, dimension_travel_info, resource,
383 : optimizer->ComputeRouteCumuls(
384 vehicle, next_accessor, dimension_travel_info, resource,
391 DCHECK(!use_mp_optimizer);
392 DCHECK_NE(mp_optimizer_,
nullptr);
393 status = optimize_and_pack_
394 ? mp_optimizer_->ComputePackedRouteCumuls(
395 vehicle, next_accessor, dimension_travel_info,
397 : mp_optimizer_->ComputeRouteCumuls(
398 vehicle, next_accessor, dimension_travel_info,
409 bool ComputeVehicleResourceClassValuesAndIndices(
410 const std::vector<int>& vehicles_to_assign,
412 used_resources_per_class,
413 const std::function<int64_t(int64_t)>& next_accessor,
414 std::vector<int>* resource_indices) {
415 resource_indices->assign(model_.vehicles(), -1);
416 if (vehicles_to_assign.empty())
return true;
417 DCHECK_NE(resource_group_,
nullptr);
419 for (
int v : vehicles_to_assign) {
420 DCHECK(resource_group_->VehicleRequiresAResource(v));
422 vehicle_resource_class_values_[v];
424 v, *resource_group_, used_resources_per_class, next_accessor,
425 dimension_.transit_evaluator(v),
426 true, lp_optimizer_, mp_optimizer_,
434 resource_group_->GetResourceIndicesPerClass(),
435 used_resources_per_class,
436 [&vehicle_rc_values = vehicle_resource_class_values_](
int v) {
437 return &vehicle_rc_values[v].assignment_costs;
439 resource_indices) >= 0;
442 const RoutingModel& model_;
443 const RoutingDimension& dimension_;
444 LocalDimensionCumulOptimizer* lp_optimizer_;
445 LocalDimensionCumulOptimizer* mp_optimizer_;
449 const RoutingModel::ResourceGroup*
const resource_group_;
453 struct VehicleResourceClassValues {
458 std::vector<VehicleResourceClassValues> vehicle_resource_class_values_;
459 const bool optimize_and_pack_;
460 const std::vector<RouteDimensionTravelInfo> dimension_travel_info_per_route_;
461 std::vector<IntVar*> cp_variables_;
462 std::vector<int64_t> cp_values_;
466 Rev<int> decision_level_;
467 DecisionBuilder* set_values_from_targets_ =
nullptr;
475 std::vector<RoutingModel::RouteDimensionTravelInfo>
476 dimension_travel_info_per_route) {
477 return solver->
RevAlloc(
new SetCumulsFromLocalDimensionCosts(
478 lp_optimizer, mp_optimizer, optimize_and_pack,
479 std::move(dimension_travel_info_per_route)));
484class SetCumulsFromGlobalDimensionCosts :
public DecisionBuilder {
486 SetCumulsFromGlobalDimensionCosts(
487 GlobalDimensionCumulOptimizer* global_optimizer,
488 GlobalDimensionCumulOptimizer* global_mp_optimizer,
489 SearchMonitor* monitor,
bool optimize_and_pack,
490 std::vector<RoutingModel::RouteDimensionTravelInfo>
491 dimension_travel_info_per_route)
492 : global_optimizer_(global_optimizer),
493 global_mp_optimizer_(global_mp_optimizer),
495 optimize_and_pack_(optimize_and_pack),
496 dimension_travel_info_per_route_(
497 std::move(dimension_travel_info_per_route)) {
498 DCHECK(dimension_travel_info_per_route_.empty() ||
499 dimension_travel_info_per_route_.size() ==
500 global_optimizer_->dimension()->model()->vehicles());
504 const RoutingDimension* dimension = global_optimizer_->dimension();
505 const RoutingModel*
model = dimension->model();
506 cp_variables_ = dimension->cumuls();
507 if (dimension->HasBreakConstraints()) {
508 for (
int vehicle = 0; vehicle <
model->vehicles(); ++vehicle) {
510 dimension->GetBreakIntervalsOfVehicle(vehicle)) {
511 cp_variables_.push_back(
interval->SafeStartExpr(0)->Var());
512 cp_variables_.push_back(
interval->SafeEndExpr(0)->Var());
519 if (!optimize_and_pack_) {
520 for (
int rg_index :
model->GetDimensionResourceGroupIndices(dimension)) {
521 const std::vector<IntVar*>& res_vars =
model->ResourceVars(rg_index);
522 cp_variables_.insert(cp_variables_.end(), res_vars.begin(),
528 Decision*
Next(Solver* solver)
override {
529 const RoutingDimension* dimension = global_optimizer_->dimension();
530 DCHECK(DimensionFixedTransitsEqualTransitEvaluators(*dimension));
531 RoutingModel*
const model = dimension->model();
533 GlobalDimensionCumulOptimizer*
const optimizer =
534 model->GetDimensionResourceGroupIndices(dimension).empty()
536 : global_mp_optimizer_;
538 optimizer, &cumul_values_, &break_start_end_values_,
539 &resource_indices_per_group_);
546 ComputeCumulBreakAndResourceValues(
547 global_mp_optimizer_, &cumul_values_, &break_start_end_values_,
548 &resource_indices_per_group_);
559 cp_values_ = std::move(cumul_values_);
560 if (dimension->HasBreakConstraints()) {
561 cp_values_.insert(cp_values_.end(), break_start_end_values_.begin(),
562 break_start_end_values_.end());
564 if (optimize_and_pack_) {
568 for (
int rg_index :
model->GetDimensionResourceGroupIndices(dimension)) {
569 for (IntVar* res_var :
model->ResourceVars(rg_index)) {
570 DCHECK(res_var->Bound());
576 for (
int rg_index :
model->GetDimensionResourceGroupIndices(dimension)) {
577 const std::vector<int>& resource_values =
578 resource_indices_per_group_[rg_index];
579 DCHECK(!resource_values.empty());
580 cp_values_.insert(cp_values_.end(), resource_values.begin(),
581 resource_values.end());
584 DCHECK_EQ(cp_variables_.size(), cp_values_.size());
586 for (
int j = 0; j < cp_values_.size(); ++j) {
587 if (cp_values_[j] == std::numeric_limits<int64_t>::min()) {
588 cp_values_[j] = cp_variables_[j]->Min();
592 std::move(cp_values_)),
601 GlobalDimensionCumulOptimizer* optimizer,
603 std::vector<int64_t>* break_start_end_values,
604 std::vector<std::vector<int>>* resource_indices_per_group) {
605 DCHECK_NE(optimizer,
nullptr);
607 break_start_end_values->clear();
608 resource_indices_per_group->clear();
609 RoutingModel*
const model = optimizer->dimension()->model();
610 const auto next = [
model](int64_t n) {
return model->NextVar(n)->Value(); };
611 return optimize_and_pack_
612 ? optimizer->ComputePackedCumuls(
614 break_start_end_values)
615 : optimizer->ComputeCumuls(
617 break_start_end_values, resource_indices_per_group);
620 GlobalDimensionCumulOptimizer*
const global_optimizer_;
621 GlobalDimensionCumulOptimizer*
const global_mp_optimizer_;
622 SearchMonitor*
const monitor_;
623 const bool optimize_and_pack_;
626 std::vector<int64_t> cumul_values_;
627 std::vector<int64_t> break_start_end_values_;
628 std::vector<std::vector<int>> resource_indices_per_group_;
629 std::vector<int64_t> cp_values_;
630 std::vector<IntVar*> cp_variables_;
631 const std::vector<RoutingModel::RouteDimensionTravelInfo>
632 dimension_travel_info_per_route_;
640 bool optimize_and_pack,
641 std::vector<RoutingModel::RouteDimensionTravelInfo>
642 dimension_travel_info_per_route) {
643 return solver->
RevAlloc(
new SetCumulsFromGlobalDimensionCosts(
644 global_optimizer, global_mp_optimizer, monitor, optimize_and_pack,
645 std::move(dimension_travel_info_per_route)));
655class RestoreDimensionValuesForUnchangedRoutes :
public DecisionBuilder {
657 explicit RestoreDimensionValuesForUnchangedRoutes(RoutingModel*
model)
659 model_->AddAtSolutionCallback([
this]() { AtSolution(); });
660 next_last_value_.resize(model_->Nexts().size(), -1);
665 Decision*
Next(Solver*
const s)
override {
666 if (!must_return_decision_)
return nullptr;
667 s->SaveAndSetValue(&must_return_decision_,
false);
668 return MakeDecision(s);
675 is_initialized_ =
true;
676 const int num_nodes = model_->VehicleVars().size();
677 node_to_integer_variable_indices_.resize(num_nodes);
678 node_to_interval_variable_indices_.resize(num_nodes);
680 for (
const std::string& dimension_name : model_->GetAllDimensionNames()) {
681 const RoutingDimension& dimension =
682 model_->GetDimensionOrDie(dimension_name);
684 for (
const std::vector<IntVar*>& dimension_variables :
685 {dimension.cumuls(), dimension.slacks()}) {
686 const int num_dimension_variables = dimension_variables.size();
687 DCHECK_LE(num_dimension_variables, num_nodes);
688 for (
int node = 0; node < num_dimension_variables; ++node) {
689 node_to_integer_variable_indices_[node].push_back(
690 integer_variables_.size());
691 integer_variables_.push_back(dimension_variables[node]);
695 for (
int vehicle = 0; vehicle < model_->vehicles(); ++vehicle) {
696 if (!dimension.HasBreakConstraints())
continue;
697 const int vehicle_start = model_->Start(vehicle);
699 dimension.GetBreakIntervalsOfVehicle(vehicle)) {
700 node_to_interval_variable_indices_[vehicle_start].push_back(
701 interval_variables_.size());
702 interval_variables_.push_back(
interval);
706 integer_variables_last_min_.resize(integer_variables_.size());
707 interval_variables_last_start_min_.resize(interval_variables_.size());
708 interval_variables_last_end_max_.resize(interval_variables_.size());
711 Decision* MakeDecision(Solver*
const s) {
712 if (!is_initialized_)
return nullptr;
714 std::vector<int> unchanged_vehicles;
715 const int num_vehicles = model_->vehicles();
716 for (
int v = 0; v < num_vehicles; ++v) {
717 bool unchanged =
true;
718 for (
int current = model_->Start(v); !model_->IsEnd(current);
719 current = next_last_value_[current]) {
720 if (!model_->NextVar(current)->Bound() ||
721 next_last_value_[current] != model_->NextVar(current)->Value()) {
726 if (unchanged) unchanged_vehicles.push_back(v);
730 if (unchanged_vehicles.size() == num_vehicles)
return nullptr;
733 std::vector<IntVar*> vars;
734 std::vector<int64_t> values;
735 for (
const int vehicle : unchanged_vehicles) {
736 for (
int current = model_->Start(vehicle);
true;
737 current = next_last_value_[current]) {
738 for (
const int index : node_to_integer_variable_indices_[current]) {
739 vars.push_back(integer_variables_[
index]);
740 values.push_back(integer_variables_last_min_[
index]);
742 for (
const int index : node_to_interval_variable_indices_[current]) {
743 const int64_t
start_min = interval_variables_last_start_min_[
index];
744 const int64_t
end_max = interval_variables_last_end_max_[
index];
746 vars.push_back(interval_variables_[
index]->SafeStartExpr(0)->Var());
747 values.push_back(interval_variables_last_start_min_[
index]);
748 vars.push_back(interval_variables_[
index]->SafeEndExpr(0)->Var());
749 values.push_back(interval_variables_last_end_max_[
index]);
751 vars.push_back(interval_variables_[
index]->PerformedExpr()->Var());
755 if (model_->IsEnd(current))
break;
758 return s->MakeAssignVariablesValuesOrDoNothing(vars, values);
762 if (!is_initialized_) Initialize();
763 const int num_integers = integer_variables_.size();
766 for (
int i = 0;
i < num_integers; ++
i) {
767 integer_variables_last_min_[
i] = integer_variables_[
i]->Min();
769 const int num_intervals = interval_variables_.size();
770 for (
int i = 0;
i < num_intervals; ++
i) {
771 const bool is_performed = interval_variables_[
i]->MustBePerformed();
772 interval_variables_last_start_min_[
i] =
773 is_performed ? interval_variables_[
i]->StartMin() : 0;
774 interval_variables_last_end_max_[
i] =
775 is_performed ? interval_variables_[
i]->EndMax() : -1;
777 const int num_nodes = next_last_value_.size();
778 for (
int node = 0; node < num_nodes; ++node) {
779 if (model_->IsEnd(node))
continue;
780 next_last_value_[node] = model_->NextVar(node)->Value();
785 RoutingModel*
const model_;
788 std::vector<int> next_last_value_;
791 std::vector<std::vector<int>> node_to_integer_variable_indices_;
792 std::vector<std::vector<int>> node_to_interval_variable_indices_;
794 std::vector<IntVar*> integer_variables_;
795 std::vector<int64_t> integer_variables_last_min_;
796 std::vector<IntervalVar*> interval_variables_;
797 std::vector<int64_t> interval_variables_last_start_min_;
798 std::vector<int64_t> interval_variables_last_end_max_;
800 bool is_initialized_ =
false;
801 bool must_return_decision_ =
true;
806 RoutingModel*
model) {
807 return model->solver()->RevAlloc(
808 new RestoreDimensionValuesForUnchangedRoutes(
model));
815 CHECK(
var !=
nullptr);
818 weighted_finalizer_variable_targets_.size());
819 if (
index < weighted_finalizer_variable_targets_.size()) {
820 auto& [var_target, total_cost] =
821 weighted_finalizer_variable_targets_[
index];
822 DCHECK_EQ(var_target.var,
var);
823 DCHECK_EQ(var_target.target, target);
824 total_cost =
CapAdd(total_cost, cost);
826 DCHECK_EQ(
index, weighted_finalizer_variable_targets_.size());
827 weighted_finalizer_variable_targets_.push_back({{
var, target}, cost});
842 CHECK(
var !=
nullptr);
843 if (finalizer_variable_target_set_.contains(
var))
return;
844 finalizer_variable_target_set_.insert(
var);
845 finalizer_variable_targets_.push_back({
var, target});
857 std::stable_sort(weighted_finalizer_variable_targets_.begin(),
858 weighted_finalizer_variable_targets_.end(),
859 [](
const std::pair<VarTarget, int64_t>& var_cost1,
860 const std::pair<VarTarget, int64_t>& var_cost2) {
861 return var_cost1.second > var_cost2.second;
863 const int num_variables = weighted_finalizer_variable_targets_.size() +
864 finalizer_variable_targets_.size();
865 std::vector<IntVar*> variables;
866 std::vector<int64_t> targets;
867 variables.reserve(num_variables);
868 targets.reserve(num_variables);
869 for (
const auto& [var_target, cost] : weighted_finalizer_variable_targets_) {
870 variables.push_back(var_target.var);
871 targets.push_back(var_target.target);
873 for (
const auto& [
var, target] : finalizer_variable_targets_) {
874 variables.push_back(
var);
875 targets.push_back(target);
DecisionBuilder * CreateFinalizer()
void AddVariableToMinimize(IntVar *var)
void AddVariableTarget(IntVar *var, int64_t target)
void AddWeightedVariableToMinimize(IntVar *var, int64_t cost)
void AddVariableToMaximize(IntVar *var)
void AddWeightedVariableTarget(IntVar *var, int64_t target, int64_t cost)
FinalizerVariables.
void AddWeightedVariableToMaximize(IntVar *var, int64_t cost)
virtual IntVar * Var()=0
Creates a variable from the expression.
virtual IntExpr * SafeStartExpr(int64_t unperformed_value)=0
virtual IntExpr * SafeEndExpr(int64_t unperformed_value)=0
A search monitor is a simple set of callbacks to monitor all search events.
For the time being, Solver is neither MT_SAFE nor MT_HOT.
void resize(size_type new_size)
Collection::value_type::second_type & LookupOrInsert(Collection *const collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapAdd(int64_t x, int64_t y)
DimensionSchedulingStatus
@ INFEASIBLE
A solution could not be found.
@ OPTIMAL
An optimal solution was found respecting all constraints.
int64_t CapSub(int64_t x, int64_t y)
DecisionBuilder * MakeRestoreDimensionValuesForUnchangedRoutes(RoutingModel *model)
bool ComputeVehicleToResourceClassAssignmentCosts(int v, const RoutingModel::ResourceGroup &resource_group, const util_intops::StrongVector< RoutingModel::ResourceClassIndex, absl::flat_hash_set< int > > &ignored_resources_per_class, const std::function< int64_t(int64_t)> &next_accessor, const std::function< int64_t(int64_t, int64_t)> &transit_accessor, bool optimize_vehicle_costs, LocalDimensionCumulOptimizer *lp_optimizer, LocalDimensionCumulOptimizer *mp_optimizer, std::vector< int64_t > *assignment_costs, std::vector< std::vector< int64_t > > *cumul_values, std::vector< std::vector< int64_t > > *break_values)
DecisionBuilder * MakeSetCumulsFromLocalDimensionCosts(Solver *solver, LocalDimensionCumulOptimizer *lp_optimizer, LocalDimensionCumulOptimizer *mp_optimizer, bool optimize_and_pack, std::vector< RoutingModel::RouteDimensionTravelInfo > dimension_travel_info_per_route)
DecisionBuilder * MakeSetCumulsFromGlobalDimensionCosts(Solver *solver, GlobalDimensionCumulOptimizer *global_optimizer, GlobalDimensionCumulOptimizer *global_mp_optimizer, SearchMonitor *monitor, bool optimize_and_pack, std::vector< RoutingModel::RouteDimensionTravelInfo > dimension_travel_info_per_route)
Variant based on global optimizers, handling all routes together.
int64_t ComputeBestVehicleToResourceAssignment(const std::vector< int > &vehicles, const util_intops::StrongVector< RoutingModel::ResourceClassIndex, std::vector< int > > &resource_indices_per_class, const util_intops::StrongVector< RoutingModel::ResourceClassIndex, absl::flat_hash_set< int > > &ignored_resources_per_class, std::function< const std::vector< int64_t > *(int)> vehicle_to_resource_class_assignment_costs, std::vector< int > *resource_indices)
DecisionBuilder * MakeSetValuesFromTargets(Solver *solver, std::vector< IntVar * > variables, std::vector< int64_t > targets)
std::vector< int64_t > assignment_costs
std::vector< std::vector< int64_t > > cumul_values
std::vector< std::vector< int64_t > > break_values