Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
routing_lp_scheduling.h
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#ifndef OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_LP_SCHEDULING_H_
15#define OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_LP_SCHEDULING_H_
16
17#include <algorithm>
18#include <cstdint>
19#include <deque>
20#include <functional>
21#include <limits>
22#include <map>
23#include <memory>
24#include <ostream>
25#include <string>
26#include <utility>
27#include <vector>
28
29#include "absl/container/flat_hash_map.h"
30#include "absl/container/flat_hash_set.h"
31#include "absl/log/check.h"
32#include "absl/strings/str_format.h"
33#include "absl/strings/string_view.h"
34#include "absl/time/time.h"
39#include "ortools/constraint_solver/routing_parameters.pb.h"
41#include "ortools/glop/parameters.pb.h"
44#include "ortools/sat/cp_model.pb.h"
46#include "ortools/sat/model.h"
47#include "ortools/sat/sat_parameters.pb.h"
49
50namespace operations_research {
51
52// Classes to solve dimension cumul placement (aka scheduling) problems using
53// linear programming.
54
55// Utility class used in the core optimizer to tighten the cumul bounds as much
56// as possible based on the model precedences.
58 public:
59 explicit CumulBoundsPropagator(const RoutingDimension* dimension);
60
61 // Tightens the cumul bounds starting from the current cumul var min/max,
62 // and propagating the precedences resulting from the next_accessor, and the
63 // dimension's precedence rules.
64 // Returns false iff the precedences are infeasible with the given routes.
65 // Otherwise, the user can call CumulMin() and CumulMax() to retrieve the new
66 // bounds of an index.
68 const std::function<int64_t(int64_t)>& next_accessor,
69 int64_t cumul_offset,
70 const std::vector<RoutingModel::RouteDimensionTravelInfo>*
71 dimension_travel_info_per_route = nullptr);
72
73 int64_t CumulMin(int index) const {
74 return propagated_bounds_[PositiveNode(index)];
75 }
76
77 int64_t CumulMax(int index) const {
78 const int64_t negated_upper_bound = propagated_bounds_[NegativeNode(index)];
79 return negated_upper_bound == std::numeric_limits<int64_t>::min()
80 ? std::numeric_limits<int64_t>::max()
81 : -negated_upper_bound;
82 }
83
84 const RoutingDimension& dimension() const { return dimension_; }
85
86 private:
87 // An arc "tail --offset--> head" represents the relation
88 // tail + offset <= head.
89 // As arcs are stored by tail, we don't store it in the struct.
90 struct ArcInfo {
91 int head;
92 int64_t offset;
93 };
94 static const int kNoParent;
95 static const int kParentToBePropagated;
96
97 // Return the node corresponding to the lower bound of the cumul of index and
98 // -index respectively.
99 int PositiveNode(int index) const { return 2 * index; }
100 int NegativeNode(int index) const { return 2 * index + 1; }
101
102 void AddNodeToQueue(int node) {
103 if (!node_in_queue_[node]) {
104 bf_queue_.push_back(node);
105 node_in_queue_[node] = true;
106 }
107 }
108
109 // Adds the relation first_index + offset <= second_index, by adding arcs
110 // first_index --offset--> second_index and
111 // -second_index --offset--> -first_index.
112 void AddArcs(int first_index, int second_index, int64_t offset);
113
114 bool InitializeArcsAndBounds(
115 const std::function<int64_t(int64_t)>& next_accessor,
116 int64_t cumul_offset,
117 const std::vector<RoutingModel::RouteDimensionTravelInfo>*
118 dimension_travel_info_per_route = nullptr);
119
120 bool UpdateCurrentLowerBoundOfNode(int node, int64_t new_lb, int64_t offset);
121
122 bool DisassembleSubtree(int source, int target);
123
124 bool CleanupAndReturnFalse() {
125 // We clean-up node_in_queue_ for future calls, and return false.
126 for (int node_to_cleanup : bf_queue_) {
127 node_in_queue_[node_to_cleanup] = false;
128 }
129 bf_queue_.clear();
130 return false;
131 }
132
133 const RoutingDimension& dimension_;
134 const int64_t num_nodes_;
135
136 // TODO(user): Investigate if all arcs for a given tail can be created
137 // at the same time, in which case outgoing_arcs_ could point to an absl::Span
138 // for each tail index.
139 std::vector<std::vector<ArcInfo>> outgoing_arcs_;
140
141 std::deque<int> bf_queue_;
142 std::vector<bool> node_in_queue_;
143 std::vector<int> tree_parent_node_of_;
144 // After calling PropagateCumulBounds(), for each node index n,
145 // propagated_bounds_[2*n] and -propagated_bounds_[2*n+1] respectively contain
146 // the propagated lower and upper bounds of n's cumul variable.
147 std::vector<int64_t> propagated_bounds_;
148
149 // Vector used in DisassembleSubtree() to avoid memory reallocation.
150 std::vector<int> tmp_dfs_stack_;
151
152 // Used to store the pickup/delivery pairs encountered on the routes.
153 std::vector<std::pair<int64_t, int64_t>>
154 visited_pickup_delivery_indices_for_pair_;
155};
156
158 // An optimal solution was found respecting all constraints.
159 OPTIMAL,
160 // An optimal solution was found, however constraints which were relaxed were
161 // violated.
163 // A solution could not be found.
165};
166
168 public:
170 virtual void Clear() = 0;
171 virtual int CreateNewPositiveVariable() = 0;
172 virtual void SetVariableName(int index, absl::string_view name) = 0;
173 virtual bool SetVariableBounds(int index, int64_t lower_bound,
174 int64_t upper_bound) = 0;
176 const std::vector<int64_t>& starts,
177 const std::vector<int64_t>& ends) = 0;
178 virtual int64_t GetVariableLowerBound(int index) const = 0;
179 virtual int64_t GetVariableUpperBound(int index) const = 0;
180 virtual void SetObjectiveCoefficient(int index, double coefficient) = 0;
181 virtual double GetObjectiveCoefficient(int index) const = 0;
182 virtual void ClearObjective() = 0;
183 virtual int NumVariables() const = 0;
184 virtual int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound) = 0;
185 virtual void SetCoefficient(int ct, int index, double coefficient) = 0;
186 virtual bool IsCPSATSolver() = 0;
187 virtual void AddObjectiveConstraint() = 0;
188 virtual void AddMaximumConstraint(int max_var, std::vector<int> vars) = 0;
189 virtual void AddProductConstraint(int product_var, std::vector<int> vars) = 0;
190 virtual void SetEnforcementLiteral(int ct, int condition) = 0;
191 virtual DimensionSchedulingStatus Solve(absl::Duration duration_limit) = 0;
192 virtual int64_t GetObjectiveValue() const = 0;
193 virtual double GetValue(int index) const = 0;
194 virtual bool SolutionIsInteger() const = 0;
195
196 // This function is meant to override the parameters of the solver.
197 virtual void SetParameters(const std::string& parameters) = 0;
198
199 // Returns if the model is empty or not.
200 virtual bool ModelIsEmpty() const { return true; }
201
202 // Prints an understandable view of the model.
203 virtual std::string PrintModel() const = 0;
204
205 // Adds a variable with bounds [lower_bound, upper_bound].
206 int AddVariable(int64_t lower_bound, int64_t upper_bound) {
207 CHECK_LE(lower_bound, upper_bound);
208 const int variable = CreateNewPositiveVariable();
210 return variable;
211 }
212 // Adds a linear constraint, enforcing
213 // lower_bound <= sum variable * coeff <= upper_bound,
214 // and returns the identifier of that constraint.
216 int64_t lower_bound, int64_t upper_bound,
217 absl::Span<const std::pair<int, double>> variable_coeffs) {
218 CHECK_LE(lower_bound, upper_bound);
220 for (const auto& variable_coeff : variable_coeffs) {
221 SetCoefficient(ct, variable_coeff.first, variable_coeff.second);
222 }
223 return ct;
224 }
225 // Adds a linear constraint and a 0/1 variable that is true iff
226 // lower_bound <= sum variable * coeff <= upper_bound,
227 // and returns the identifier of that variable.
229 int64_t lower_bound, int64_t upper_bound,
230 absl::Span<const std::pair<int, double>> weighted_variables) {
231 const int reification_ct = AddLinearConstraint(1, 1, {});
232 if (std::numeric_limits<int64_t>::min() < lower_bound) {
233 const int under_lower_bound = AddVariable(0, 1);
234#ifndef NDEBUG
235 SetVariableName(under_lower_bound, "under_lower_bound");
236#endif
237 SetCoefficient(reification_ct, under_lower_bound, 1);
238 const int under_lower_bound_ct =
239 AddLinearConstraint(std::numeric_limits<int64_t>::min(),
240 lower_bound - 1, weighted_variables);
241 SetEnforcementLiteral(under_lower_bound_ct, under_lower_bound);
242 }
243 if (upper_bound < std::numeric_limits<int64_t>::max()) {
244 const int above_upper_bound = AddVariable(0, 1);
245#ifndef NDEBUG
246 SetVariableName(above_upper_bound, "above_upper_bound");
247#endif
248 SetCoefficient(reification_ct, above_upper_bound, 1);
249 const int above_upper_bound_ct = AddLinearConstraint(
250 upper_bound + 1, std::numeric_limits<int64_t>::max(),
251 weighted_variables);
252 SetEnforcementLiteral(above_upper_bound_ct, above_upper_bound);
253 }
254 const int within_bounds = AddVariable(0, 1);
255#ifndef NDEBUG
256 SetVariableName(within_bounds, "within_bounds");
257#endif
258 SetCoefficient(reification_ct, within_bounds, 1);
259 const int within_bounds_ct =
260 AddLinearConstraint(lower_bound, upper_bound, weighted_variables);
261 SetEnforcementLiteral(within_bounds_ct, within_bounds);
262 return within_bounds;
263 }
264};
265
267 public:
268 RoutingGlopWrapper(bool is_relaxation, const glop::GlopParameters& parameters)
269 : is_relaxation_(is_relaxation) {
270 lp_solver_.SetParameters(parameters);
271 linear_program_.SetMaximizationProblem(false);
272 }
273 void Clear() override {
274 linear_program_.Clear();
275 linear_program_.SetMaximizationProblem(false);
276 allowed_intervals_.clear();
277 }
279 return linear_program_.CreateNewVariable().value();
280 }
281 void SetVariableName(int index, absl::string_view name) override {
282 linear_program_.SetVariableName(glop::ColIndex(index), name);
283 }
285 int64_t upper_bound) override {
286 DCHECK_GE(lower_bound, 0);
287 // When variable upper bounds are greater than this threshold, precision
288 // issues arise in GLOP. In this case we are just going to suppose that
289 // these high bound values are infinite and not set the upper bound.
290 const int64_t kMaxValue = 1e10;
291 const double lp_min = lower_bound;
292 const double lp_max =
293 (upper_bound > kMaxValue) ? glop::kInfinity : upper_bound;
294 if (lp_min <= lp_max) {
295 linear_program_.SetVariableBounds(glop::ColIndex(index), lp_min, lp_max);
296 return true;
297 }
298 // The linear_program would not be feasible, and it cannot handle the
299 // lp_min > lp_max case, so we must detect infeasibility here.
300 return false;
301 }
302 void SetVariableDisjointBounds(int index, const std::vector<int64_t>& starts,
303 const std::vector<int64_t>& ends) override {
304 // TODO(user): Investigate if we can avoid rebuilding the interval list
305 // each time (we could keep a reference to the forbidden interval list in
306 // RoutingDimension but we would need to store cumul offsets and use them
307 // when checking intervals).
308 allowed_intervals_[index] =
309 std::make_unique<SortedDisjointIntervalList>(starts, ends);
310 }
311 int64_t GetVariableLowerBound(int index) const override {
312 return linear_program_.variable_lower_bounds()[glop::ColIndex(index)];
313 }
314 int64_t GetVariableUpperBound(int index) const override {
315 const double upper_bound =
316 linear_program_.variable_upper_bounds()[glop::ColIndex(index)];
317 DCHECK_GE(upper_bound, 0);
318 return upper_bound == glop::kInfinity ? std::numeric_limits<int64_t>::max()
319 : static_cast<int64_t>(upper_bound);
320 }
321 void SetObjectiveCoefficient(int index, double coefficient) override {
322 linear_program_.SetObjectiveCoefficient(glop::ColIndex(index), coefficient);
323 }
324 double GetObjectiveCoefficient(int index) const override {
325 return linear_program_.objective_coefficients()[glop::ColIndex(index)];
326 }
327 void ClearObjective() override {
328 for (glop::ColIndex i(0); i < linear_program_.num_variables(); ++i) {
329 linear_program_.SetObjectiveCoefficient(i, 0);
330 }
331 }
332 int NumVariables() const override {
333 return linear_program_.num_variables().value();
334 }
335 int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound) override {
336 const glop::RowIndex ct = linear_program_.CreateNewConstraint();
337 linear_program_.SetConstraintBounds(
338 ct,
339 (lower_bound == std::numeric_limits<int64_t>::min()) ? -glop::kInfinity
340 : lower_bound,
341 (upper_bound == std::numeric_limits<int64_t>::max()) ? glop::kInfinity
342 : upper_bound);
343 return ct.value();
344 }
345 void SetCoefficient(int ct, int index, double coefficient) override {
346 // Necessary to keep the model clean
347 // (cf. glop::LinearProgram::NotifyThatColumnsAreClean).
348 if (coefficient == 0.0) return;
349 linear_program_.SetCoefficient(glop::RowIndex(ct), glop::ColIndex(index),
351 }
352 bool IsCPSATSolver() override { return false; }
353 void AddObjectiveConstraint() override {
354 double max_coefficient = 0;
355 for (int variable = 0; variable < NumVariables(); variable++) {
356 const double coefficient = GetObjectiveCoefficient(variable);
357 max_coefficient = std::max(MathUtil::Abs(coefficient), max_coefficient);
358 }
359 DCHECK_GE(max_coefficient, 0);
360 if (max_coefficient == 0) {
361 // There are no terms in the objective.
362 return;
363 }
364 const glop::RowIndex ct = linear_program_.CreateNewConstraint();
365 double normalized_objective_value = 0;
366 for (int variable = 0; variable < NumVariables(); variable++) {
367 const double coefficient = GetObjectiveCoefficient(variable);
368 if (coefficient != 0) {
369 const double normalized_coeff = coefficient / max_coefficient;
370 SetCoefficient(ct.value(), variable, normalized_coeff);
371 normalized_objective_value += normalized_coeff * GetValue(variable);
372 }
373 }
374 normalized_objective_value = std::max(
375 normalized_objective_value, GetObjectiveValue() / max_coefficient);
376 linear_program_.SetConstraintBounds(ct, -glop::kInfinity,
377 normalized_objective_value);
378 }
379 void AddMaximumConstraint(int /*max_var*/,
380 std::vector<int> /*vars*/) override {}
381 void AddProductConstraint(int /*product_var*/,
382 std::vector<int> /*vars*/) override {}
383 void SetEnforcementLiteral(int /*ct*/, int /*condition*/) override {};
384 DimensionSchedulingStatus Solve(absl::Duration duration_limit) override {
385 lp_solver_.GetMutableParameters()->set_max_time_in_seconds(
386 absl::ToDoubleSeconds(duration_limit));
387
388 // Because we construct the lp one constraint at a time and we never call
389 // SetCoefficient() on the same variable twice for a constraint, we know
390 // that the columns do not contain duplicates and are already ordered by
391 // constraint so we do not need to call linear_program->CleanUp() which can
392 // be costly. Note that the assumptions are DCHECKed() in the call below.
393 linear_program_.NotifyThatColumnsAreClean();
394 VLOG(2) << linear_program_.Dump();
395 const glop::ProblemStatus status = lp_solver_.Solve(linear_program_);
399 }
400 if (is_relaxation_) {
402 }
403 for (const auto& allowed_interval : allowed_intervals_) {
404 const double value_double = GetValue(allowed_interval.first);
405 const int64_t value =
406 (value_double >= std::numeric_limits<int64_t>::max())
407 ? std::numeric_limits<int64_t>::max()
408 : MathUtil::FastInt64Round(value_double);
409 const SortedDisjointIntervalList* const interval_list =
410 allowed_interval.second.get();
411 const auto it = interval_list->FirstIntervalGreaterOrEqual(value);
412 if (it == interval_list->end() || value < it->start) {
414 }
415 }
417 }
418 int64_t GetObjectiveValue() const override {
419 return MathUtil::FastInt64Round(lp_solver_.GetObjectiveValue());
420 }
421 double GetValue(int index) const override {
422 return lp_solver_.variable_values()[glop::ColIndex(index)];
423 }
424 bool SolutionIsInteger() const override {
425 return linear_program_.SolutionIsInteger(lp_solver_.variable_values(),
426 /*absolute_tolerance*/ 1e-3);
427 }
428
429 void SetParameters(const std::string& parameters) override {
430 glop::GlopParameters params;
431 const bool status = params.ParseFromString(parameters);
432 DCHECK(status);
433 lp_solver_.SetParameters(params);
434 }
435
436 // Prints an understandable view of the model
437 // TODO(user): Improve output readability.
438 std::string PrintModel() const override { return linear_program_.Dump(); }
439
440 private:
441 const bool is_relaxation_;
442 glop::LinearProgram linear_program_;
443 glop::LPSolver lp_solver_;
444 absl::flat_hash_map<int, std::unique_ptr<SortedDisjointIntervalList>>
445 allowed_intervals_;
446};
447
449 public:
451 parameters_.set_num_search_workers(1);
452 // Keeping presolve but with 1 iteration; as of 10/2023 it is
453 // significantly faster than both full presolve and no presolve.
454 parameters_.set_cp_model_presolve(true);
455 parameters_.set_max_presolve_iterations(1);
456 parameters_.set_catch_sigint_signal(false);
457 parameters_.set_mip_max_bound(1e8);
458 parameters_.set_search_branching(sat::SatParameters::LP_SEARCH);
459 parameters_.set_linearization_level(2);
460 parameters_.set_cut_level(0);
461 parameters_.set_use_absl_random(false);
462 }
464 void Clear() override {
465 model_.Clear();
466 response_.Clear();
467 objective_coefficients_.clear();
468 }
470 const int index = model_.variables_size();
471 sat::IntegerVariableProto* const variable = model_.add_variables();
472 variable->add_domain(0);
473 variable->add_domain(static_cast<int64_t>(parameters_.mip_max_bound()));
474 return index;
475 }
476 void SetVariableName(int index, absl::string_view name) override {
477 model_.mutable_variables(index)->set_name(name.data());
478 }
480 int64_t upper_bound) override {
481 DCHECK_GE(lower_bound, 0);
482 const int64_t capped_upper_bound =
483 std::min<int64_t>(upper_bound, parameters_.mip_max_bound());
484 if (lower_bound > capped_upper_bound) return false;
485 sat::IntegerVariableProto* const variable = model_.mutable_variables(index);
486 variable->set_domain(0, lower_bound);
487 variable->set_domain(1, capped_upper_bound);
488 return true;
489 }
490 void SetVariableDisjointBounds(int index, const std::vector<int64_t>& starts,
491 const std::vector<int64_t>& ends) override {
492 DCHECK_EQ(starts.size(), ends.size());
493 const int ct = CreateNewConstraint(1, 1);
494 for (int i = 0; i < starts.size(); ++i) {
495 const int variable = CreateNewPositiveVariable();
496#ifndef NDEBUG
497 SetVariableName(variable,
498 absl::StrFormat("disjoint(%ld, %ld)", index, i));
499#endif
500 SetVariableBounds(variable, 0, 1);
501 SetCoefficient(ct, variable, 1);
502 const int window_ct = CreateNewConstraint(starts[i], ends[i]);
503 SetCoefficient(window_ct, index, 1);
504 model_.mutable_constraints(window_ct)->add_enforcement_literal(variable);
505 }
506 }
507 int64_t GetVariableLowerBound(int index) const override {
508 return model_.variables(index).domain(0);
509 }
510 int64_t GetVariableUpperBound(int index) const override {
511 const auto& domain = model_.variables(index).domain();
512 return domain[domain.size() - 1];
513 }
514 void SetObjectiveCoefficient(int index, double coefficient) override {
515 if (index >= objective_coefficients_.size()) {
516 objective_coefficients_.resize(index + 1, 0);
517 }
518 objective_coefficients_[index] = coefficient;
519 sat::FloatObjectiveProto* const objective =
520 model_.mutable_floating_point_objective();
521 objective->add_vars(index);
522 objective->add_coeffs(coefficient);
523 }
524 double GetObjectiveCoefficient(int index) const override {
525 return (index < objective_coefficients_.size())
526 ? objective_coefficients_[index]
527 : 0;
528 }
529 void ClearObjective() override {
530 model_.mutable_floating_point_objective()->Clear();
531 }
532 int NumVariables() const override { return model_.variables_size(); }
533 int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound) override {
534 sat::LinearConstraintProto* const ct =
535 model_.add_constraints()->mutable_linear();
536 ct->add_domain(lower_bound);
537 ct->add_domain(upper_bound);
538 return model_.constraints_size() - 1;
539 }
540 void SetCoefficient(int ct_index, int index, double coefficient) override {
541 sat::LinearConstraintProto* const ct =
542 model_.mutable_constraints(ct_index)->mutable_linear();
543 ct->add_vars(index);
544 const int64_t integer_coefficient = coefficient;
545 ct->add_coeffs(integer_coefficient);
546 }
547 bool IsCPSATSolver() override { return true; }
548 void AddObjectiveConstraint() override {
549 const sat::CpObjectiveProto& objective = response_.integer_objective();
550 int64_t activity = 0;
551 for (int i = 0; i < objective.vars_size(); ++i) {
552 activity += response_.solution(objective.vars(i)) * objective.coeffs(i);
553 }
554 const int ct =
555 CreateNewConstraint(std::numeric_limits<int64_t>::min(), activity);
556 for (int i = 0; i < objective.vars_size(); ++i) {
557 SetCoefficient(ct, objective.vars(i), objective.coeffs(i));
558 }
559 model_.clear_objective();
560 }
561 void AddMaximumConstraint(int max_var, std::vector<int> vars) override {
562 sat::LinearArgumentProto* const ct =
563 model_.add_constraints()->mutable_lin_max();
564 ct->mutable_target()->add_vars(max_var);
565 ct->mutable_target()->add_coeffs(1);
566 for (const int var : vars) {
567 sat::LinearExpressionProto* const expr = ct->add_exprs();
568 expr->add_vars(var);
569 expr->add_coeffs(1);
570 }
571 }
572 void AddProductConstraint(int product_var, std::vector<int> vars) override {
573 sat::LinearArgumentProto* const ct =
574 model_.add_constraints()->mutable_int_prod();
575 ct->mutable_target()->add_vars(product_var);
576 ct->mutable_target()->add_coeffs(1);
577 for (const int var : vars) {
578 sat::LinearExpressionProto* expr = ct->add_exprs();
579 expr->add_vars(var);
580 expr->add_coeffs(1);
581 }
582 }
583 void SetEnforcementLiteral(int ct, int condition) override {
584 DCHECK_LT(ct, model_.constraints_size());
585 model_.mutable_constraints(ct)->add_enforcement_literal(condition);
586 }
587 DimensionSchedulingStatus Solve(absl::Duration duration_limit) override {
588 parameters_.set_max_time_in_seconds(absl::ToDoubleSeconds(duration_limit));
589 VLOG(2) << model_.DebugString();
590 if (hint_.vars_size() == model_.variables_size()) {
591 *model_.mutable_solution_hint() = hint_;
592 }
594 model.Add(sat::NewSatParameters(parameters_));
595 response_ = sat::SolveCpModel(model_, &model);
596 VLOG(2) << response_;
597 if (response_.status() == sat::CpSolverStatus::OPTIMAL ||
598 (response_.status() == sat::CpSolverStatus::FEASIBLE &&
599 !model_.has_floating_point_objective())) {
600 hint_.Clear();
601 for (int i = 0; i < response_.solution_size(); ++i) {
602 hint_.add_vars(i);
603 hint_.add_values(response_.solution(i));
604 }
606 }
608 }
609 int64_t GetObjectiveValue() const override {
610 return MathUtil::FastInt64Round(response_.objective_value());
611 }
612 double GetValue(int index) const override {
613 return response_.solution(index);
614 }
615 bool SolutionIsInteger() const override { return true; }
616
617 // NOTE: This function is not implemented for the CP-SAT solver.
618 void SetParameters(const std::string& /*parameters*/) override {
619 DCHECK(false);
620 }
621
622 bool ModelIsEmpty() const override { return model_.ByteSizeLong() == 0; }
623
624 // Prints an understandable view of the model
625 std::string PrintModel() const override;
626
627 private:
628 sat::CpModelProto model_;
629 sat::CpSolverResponse response_;
630 sat::SatParameters parameters_;
631 std::vector<double> objective_coefficients_;
632 sat::PartialVariableAssignment hint_;
633};
634
635// Utility class used in Local/GlobalDimensionCumulOptimizer to set the linear
636// solver constraints and solve the problem.
638 using RouteDimensionTravelInfo = RoutingModel::RouteDimensionTravelInfo;
639 using Resource = RoutingModel::ResourceGroup::Resource;
640
641 public:
642 DimensionCumulOptimizerCore(const RoutingDimension* dimension,
643 bool use_precedence_propagator);
644
645 // Finds an optimal (or just feasible) solution for the route for the given
646 // resource. If the resource is null, it is simply ignored.
648 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
649 const RouteDimensionTravelInfo& dimension_travel_info,
650 const Resource* resource, bool optimize_vehicle_costs,
651 RoutingLinearSolverWrapper* solver, std::vector<int64_t>* cumul_values,
652 std::vector<int64_t>* break_values, int64_t* cost_without_transit,
653 int64_t* transit_cost, bool clear_lp = true);
654
655 // Given some cumuls and breaks, computes the solution cost by solving the
656 // same model as in OptimizeSingleRouteWithResource() with the addition of
657 // constraints for cumuls and breaks.
659 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
660 const RouteDimensionTravelInfo& dimension_travel_info,
662 absl::Span<const int64_t> solution_cumul_values,
663 absl::Span<const int64_t> solution_break_values,
664 int64_t* cost_without_transits, int64_t* cost_offset = nullptr,
665 bool reuse_previous_model_if_possible = true, bool clear_lp = false,
666 bool clear_solution_constraints = true,
667 absl::Duration* solve_duration = nullptr);
668
669 // Computes the optimal scheduling solution(s) for the route for each resource
670 // in 'resources' with an index in 'resource_indices'.
671 // If both 'resources' and 'resource_indices' are empty, computes the optimal
672 // solution for the route itself (without added resource constraints).
673 std::vector<DimensionSchedulingStatus> OptimizeSingleRouteWithResources(
674 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
675 const std::function<int64_t(int64_t, int64_t)>& transit_accessor,
676 const RouteDimensionTravelInfo& dimension_travel_info,
677 const std::vector<Resource>& resources,
678 const std::vector<int>& resource_indices, bool optimize_vehicle_costs,
680 std::vector<std::vector<int64_t>>* cumul_values,
681 std::vector<std::vector<int64_t>>* break_values,
682 std::vector<int64_t>* costs_without_transits, int64_t* transit_cost,
683 bool clear_lp = true);
684
685 // In the Optimize() method, if both 'cumul_values' and 'cost' parameters are
686 // null, we don't optimize the cost and stop at the first feasible solution in
687 // the linear solver (since in this case only feasibility is of interest).
688 // When 'optimize_resource_assignment' is false, the resource var values are
689 // used to constrain the vehicle routes according to their assigned resource.
691 const std::function<int64_t(int64_t)>& next_accessor,
692 const std::vector<RouteDimensionTravelInfo>&
693 dimension_travel_info_per_route,
694 RoutingLinearSolverWrapper* solver, std::vector<int64_t>* cumul_values,
695 std::vector<int64_t>* break_values,
696 std::vector<std::vector<int>>* resource_indices_per_group,
697 int64_t* cost_without_transits, int64_t* transit_cost,
698 bool clear_lp = true, bool optimize_resource_assignment = true);
699
701 const std::function<int64_t(int64_t)>& next_accessor,
702 const std::vector<RouteDimensionTravelInfo>&
703 dimension_travel_info_per_route,
704 RoutingLinearSolverWrapper* solver, std::vector<int64_t>* cumul_values,
705 std::vector<int64_t>* break_values);
706
708 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
709 const RouteDimensionTravelInfo& dimension_travel_info,
710 const Resource* resource, RoutingLinearSolverWrapper* solver,
711 std::vector<int64_t>* cumul_values, std::vector<int64_t>* break_values);
712
713 const RoutingDimension* dimension() const { return dimension_; }
714
715 private:
716 // Initializes the containers and given solver. Must be called prior to
717 // setting any constraints and solving.
718 void InitOptimizer(RoutingLinearSolverWrapper* solver);
719
720 // Computes the minimum/maximum of cumuls for nodes on "route", and sets them
721 // in current_route_[min|max]_cumuls_ respectively.
722 bool ExtractRouteCumulBounds(absl::Span<const int64_t> route,
723 int64_t cumul_offset);
724
725 // Tighten the minimum/maximum of cumuls for nodes on "route"
726 // If the propagator_ is not null, uses the bounds tightened by the
727 // propagator. Otherwise, the minimum transits are used to tighten them.
728 bool TightenRouteCumulBounds(const std::vector<int64_t>& route,
729 const std::vector<int64_t>& min_transits,
730 int64_t cumul_offset);
731
732 // Sets the constraints for all nodes on "vehicle"'s route according to
733 // "next_accessor". If optimize_costs is true, also sets the objective
734 // coefficients for the LP.
735 // Returns false if some infeasibility was detected, true otherwise.
736 bool SetRouteCumulConstraints(
737 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
738 const std::function<int64_t(int64_t, int64_t)>& transit_accessor,
739 const RouteDimensionTravelInfo& dimension_travel_info,
740 int64_t cumul_offset, bool optimize_costs,
741 RoutingLinearSolverWrapper* solver, int64_t* route_transit_cost,
742 int64_t* route_cost_offset);
743
744 // Sets the constraints for all variables related to travel. Handles
745 // static or time-dependent travel values.
746 // Returns false if some infeasibility was detected, true otherwise.
747 bool SetRouteTravelConstraints(
748 const RouteDimensionTravelInfo& dimension_travel_info,
749 const std::vector<int>& lp_slacks,
750 const std::vector<int64_t>& fixed_transit,
752
753 // Sets the global constraints on the dimension, and adds global objective
754 // cost coefficients if optimize_costs is true.
755 // NOTE: When called, the call to this function MUST come after
756 // SetRouteCumulConstraints() has been called on all routes, so that
757 // index_to_cumul_variable_ and min_start/max_end_cumul_ are correctly
758 // initialized.
759 // Returns false if some infeasibility was detected, true otherwise.
760 bool SetGlobalConstraints(
761 const std::function<int64_t(int64_t)>& next_accessor,
762 int64_t cumul_offset, bool optimize_costs,
763 bool optimize_resource_assignment, RoutingLinearSolverWrapper* solver);
764
765 bool SetGlobalConstraintsForResourceAssignment(
766 const std::function<int64_t(int64_t)>& next_accessor,
767 int64_t cumul_offset, RoutingLinearSolverWrapper* solver);
768
769 void SetValuesFromLP(const std::vector<int>& lp_variables, int64_t offset,
771 std::vector<int64_t>* lp_values) const;
772
773 void SetResourceIndices(
775 std::vector<std::vector<int>>* resource_indices_per_group) const;
776
777 // This function packs the routes of the given vehicles while keeping the cost
778 // of the LP lower than its current (supposed optimal) objective value.
779 // It does so by setting the current objective variables' coefficient to 0 and
780 // setting the coefficient of the route ends to 1, to first minimize the route
781 // ends' cumuls, and then maximizes the starts' cumuls without increasing the
782 // ends.
783 DimensionSchedulingStatus PackRoutes(
784 std::vector<int> vehicles, RoutingLinearSolverWrapper* solver,
785 const glop::GlopParameters& packing_parameters);
786
787 std::unique_ptr<CumulBoundsPropagator> propagator_;
788 std::vector<int64_t> current_route_min_cumuls_;
789 std::vector<int64_t> current_route_max_cumuls_;
790 const RoutingDimension* const dimension_;
791 // Scheduler variables for current route cumuls and for all nodes cumuls.
792 std::vector<int> current_route_cumul_variables_;
793 std::vector<int> index_to_cumul_variable_;
794 // Scheduler variables for current route breaks and all vehicle breaks.
795 // There are two variables for each break: start and end.
796 // current_route_break_variables_ has variables corresponding to
797 // break[0] start, break[0] end, break[1] start, break[1] end, etc.
798 std::vector<int> current_route_break_variables_;
799 // Vector all_break_variables contains the break variables of all vehicles,
800 // in the same format as current_route_break_variables.
801 // It is the concatenation of break variables of vehicles in [0, #vehicles).
802 std::vector<int> all_break_variables_;
803 // Allows to retrieve break variables of a given vehicle: those go from
804 // all_break_variables_[vehicle_to_all_break_variables_offset_[vehicle]] to
805 // all_break_variables[vehicle_to_all_break_variables_offset_[vehicle+1]-1].
806 std::vector<int> vehicle_to_all_break_variables_offset_;
807 // The following vector contains indices of resource-to-vehicle assignment
808 // variables. For every resource group, stores indices of
809 // num_resources*num_vehicles boolean variables indicating whether resource #r
810 // is assigned to vehicle #v.
811 std::vector<std::vector<int>>
812 resource_group_to_resource_to_vehicle_assignment_variables_;
813
814 int max_end_cumul_;
815 int min_start_cumul_;
816 std::vector<std::pair<int64_t, int64_t>>
817 visited_pickup_delivery_indices_for_pair_;
818};
819
820// Class used to compute optimal values for dimension cumuls of routes,
821// minimizing cumul soft lower and upper bound costs, and vehicle span costs of
822// a route.
823// In its methods, next_accessor is a callback returning the next node of a
824// given node on a route.
826 public:
828 const RoutingDimension* dimension,
829 RoutingSearchParameters::SchedulingSolver solver_type);
830
831 // If feasible, computes the optimal cost of the route performed by a vehicle,
832 // minimizing cumul soft lower and upper bound costs and vehicle span costs,
833 // and stores it in "optimal_cost" (if not null).
834 // Returns true iff the route respects all constraints.
836 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
837 int64_t* optimal_cost);
838
839 // Same as ComputeRouteCumulCost, but the cost computed does not contain
840 // the part of the vehicle span cost due to fixed transits.
842 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
843 int64_t* optimal_cost_without_transits);
844
845 std::vector<DimensionSchedulingStatus>
847 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
848 const std::function<int64_t(int64_t, int64_t)>& transit_accessor,
849 const std::vector<RoutingModel::ResourceGroup::Resource>& resources,
850 const std::vector<int>& resource_indices, bool optimize_vehicle_costs,
851 std::vector<int64_t>* optimal_costs_without_transits,
852 std::vector<std::vector<int64_t>>* optimal_cumuls,
853 std::vector<std::vector<int64_t>>* optimal_breaks);
854
855 // If feasible, computes the optimal values for cumul and break variables
856 // of the route performed by a vehicle, minimizing cumul soft lower, upper
857 // bound costs and vehicle span costs, stores them in "optimal_cumuls"
858 // (if not null), and optimal_breaks, and returns true.
859 // Returns false if the route is not feasible.
861 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
862 const RoutingModel::RouteDimensionTravelInfo& dimension_travel_info,
863 const RoutingModel::ResourceGroup::Resource* resource,
864 std::vector<int64_t>* optimal_cumuls,
865 std::vector<int64_t>* optimal_breaks);
866
867 // Simple combination of ComputeRouteCumulCostWithoutFixedTransits() and
868 // ComputeRouteCumuls().
870 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
871 const RoutingModel::RouteDimensionTravelInfo& dimension_travel_info,
872 std::vector<int64_t>* optimal_cumuls,
873 std::vector<int64_t>* optimal_breaks,
874 int64_t* optimal_cost_without_transits);
875
876 // If feasible, computes the cost of a given route performed by a vehicle
877 // defined by its cumuls and breaks.
879 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
880 const RoutingModel::RouteDimensionTravelInfo& dimension_travel_info,
881 const std::vector<int64_t>& solution_cumul_values,
882 const std::vector<int64_t>& solution_break_values, int64_t* solution_cost,
883 int64_t* cost_offset = nullptr,
884 bool reuse_previous_model_if_possible = false, bool clear_lp = true,
885 absl::Duration* solve_duration = nullptr);
886
887 // Similar to ComputeRouteCumuls, but also tries to pack the cumul values on
888 // the route, such that the cost remains the same, the cumul of route end is
889 // minimized, and then the cumul of the start of the route is maximized.
890 // If 'resource' is non-null, the packed route must also respect its start/end
891 // time window.
893 int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
894 const RoutingModel::RouteDimensionTravelInfo& dimension_travel_info,
895 const RoutingModel::ResourceGroup::Resource* resource,
896 std::vector<int64_t>* packed_cumuls, std::vector<int64_t>* packed_breaks);
897
898 const RoutingDimension* dimension() const {
899 return optimizer_core_.dimension();
900 }
901
902 private:
903 std::vector<std::unique_ptr<RoutingLinearSolverWrapper>> solver_;
904 DimensionCumulOptimizerCore optimizer_core_;
905};
906
908 public:
910 const RoutingDimension* dimension,
911 RoutingSearchParameters::SchedulingSolver solver_type);
912 // If feasible, computes the optimal cost of the entire model with regards to
913 // the optimizer_core_'s dimension costs, minimizing cumul soft lower/upper
914 // bound costs and vehicle/global span costs, and stores it in "optimal_cost"
915 // (if not null).
916 // Returns true iff all the constraints can be respected.
918 const std::function<int64_t(int64_t)>& next_accessor,
919 int64_t* optimal_cost_without_transits);
920 // If feasible, computes the optimal values for cumul, break and resource
921 // variables, minimizing cumul soft lower/upper bound costs and vehicle/global
922 // span costs, stores them in "optimal_cumuls" (if not null), "optimal_breaks"
923 // and "optimal_resource_indices_per_group", and returns true.
924 // Returns false if the routes are not feasible.
926 const std::function<int64_t(int64_t)>& next_accessor,
927 const std::vector<RoutingModel::RouteDimensionTravelInfo>&
928 dimension_travel_info_per_route,
929 std::vector<int64_t>* optimal_cumuls,
930 std::vector<int64_t>* optimal_breaks,
931 std::vector<std::vector<int>>* optimal_resource_indices_per_group);
932
933 // Similar to ComputeCumuls, but also tries to pack the cumul values on all
934 // routes, such that the cost remains the same, the cumuls of route ends are
935 // minimized, and then the cumuls of the starts of the routes are maximized.
936 // NOTE: It's assumed that all resource variables (if any) are Bound() when
937 // calling this method, so each vehicle's resource attributes are set as
938 // constraint on its route and no resource assignment is required.
940 const std::function<int64_t(int64_t)>& next_accessor,
941 const std::vector<RoutingModel::RouteDimensionTravelInfo>&
942 dimension_travel_info_per_route,
943 std::vector<int64_t>* packed_cumuls, std::vector<int64_t>* packed_breaks);
944
945 const RoutingDimension* dimension() const {
946 return optimizer_core_.dimension();
947 }
948
949 private:
950 std::unique_ptr<RoutingLinearSolverWrapper> solver_;
951 DimensionCumulOptimizerCore optimizer_core_;
952};
953
954// Finds the approximate (*) min-cost (i.e. best) assignment of all vehicles
955// v ∈ 'vehicles' to resources, i.e. indices in [0..num_resources), where the
956// costs of assigning a vehicle v to a resource r of class r_c is given by
957// 'vehicle_to_resource_class_assignment_costs(v)[r_c]', unless the latter is
958// empty in which case vehicle v does not need a resource.
959//
960// Returns the cost of that optimal assignment, or -1 if it's infeasible.
961// Moreover, if 'resource_indices' != nullptr, it assumes that its size is the
962// global number of vehicles, and assigns its element #v with the resource r
963// assigned to v, or -1 if none.
964//
965// (*) COST SCALING: When the costs are so large that they could possibly yield
966// int64_t overflow, this method returns a *lower* bound of the actual optimal
967// cost, and the assignment output in 'resource_indices' may be suboptimal if
968// that lower bound isn't tight (but it should be very close).
969//
970// COMPLEXITY: in practice, should be roughly
971// O(num_resource_classes * vehicles.size() + resource_indices->size()).
973 const std::vector<int>& vehicles,
974 const util_intops::StrongVector<RoutingModel::ResourceClassIndex,
975 std::vector<int>>& resource_indices_per_class,
976 const util_intops::StrongVector<RoutingModel::ResourceClassIndex,
977 absl::flat_hash_set<int>>&
978 ignored_resources_per_class,
979 std::function<const std::vector<int64_t>*(int)>
980 vehicle_to_resource_class_assignment_costs,
981 std::vector<int>* resource_indices);
982
983// Computes the vehicle-to-resource-class assignment costs for the given vehicle
984// to all resource classes in the group, and sets these costs in
985// 'assignment_costs' (if non-null). The latter is cleared and kept empty if the
986// vehicle 'v' should not have a resource assigned to it.
987// optimize_vehicle_costs indicates if the costs should be optimized or if
988// we merely care about feasibility (cost of 0) and infeasibility (cost of -1)
989// of the assignments.
990// The cumul and break values corresponding to the assignment of each resource
991// are also set in cumul_values and break_values, if non-null.
993 int v, const RoutingModel::ResourceGroup& resource_group,
994 const util_intops::StrongVector<RoutingModel::ResourceClassIndex,
995 absl::flat_hash_set<int>>&
996 ignored_resources_per_class,
997 const std::function<int64_t(int64_t)>& next_accessor,
998 const std::function<int64_t(int64_t, int64_t)>& transit_accessor,
999 bool optimize_vehicle_costs, LocalDimensionCumulOptimizer* lp_optimizer,
1000 LocalDimensionCumulOptimizer* mp_optimizer,
1001 std::vector<int64_t>* assignment_costs,
1002 std::vector<std::vector<int64_t>>* cumul_values,
1003 std::vector<std::vector<int64_t>>* break_values);
1004
1005// Simple struct returned by ComputePiecewiseLinearFormulationValue() to
1006// indicate if the value could be computed and if not, on what side the value
1007// was from the definition interval.
1014
1015// Computes pwl(x) for pwl a PieceWiseLinearFormulation.
1016// Returns a PieceWiseEvaluationStatus to indicate if the value could be
1017// computed (filled in value) and if not, why.
1019 const RoutingModel::RouteDimensionTravelInfo::TransitionInfo::
1020 PiecewiseLinearFormulation& pwl,
1021 int64_t x, int64_t* value, double delta = 0);
1022
1023// Like ComputePiecewiseLinearFormulationValue(), computes pwl(x) for pwl a
1024// PiecewiseLinearFormulation. For convex PiecewiseLinearFormulations, if x is
1025// outside the bounds of the function, instead of returning an error like in
1026// PiecewiseLinearFormulation, the function will still be defined by its outer
1027// segments.
1029 const RoutingModel::RouteDimensionTravelInfo::TransitionInfo::
1030 PiecewiseLinearFormulation& pwl,
1031 int64_t x, double delta = 0);
1032
1033// Structure to store the slope and y_intercept of a segment.
1035 double slope;
1037
1038 friend ::std::ostream& operator<<(::std::ostream& os,
1039 const SlopeAndYIntercept& it) {
1040 return os << "{" << it.slope << ", " << it.y_intercept << "}";
1041 }
1042};
1043
1044// Converts a vector of SlopeAndYIntercept to a vector of convexity regions.
1045// Convexity regions are defined such that, all segment in a convexity region
1046// form a convex function. The boolean in the vector is set to true if the
1047// segment associated to it starts a new convexity region. Therefore, a convex
1048// function would yield {true, false, false, ...} and a concave function would
1049// yield {true, true, true, ...}.
1050std::vector<bool> SlopeAndYInterceptToConvexityRegions(
1051 const std::vector<SlopeAndYIntercept>& slope_and_y_intercept);
1052
1053// Given a PiecewiseLinearFormulation, returns a vector of slope and y-intercept
1054// corresponding to each segment. Only the segments in [index_start, index_end[
1055// will be considered.
1056std::vector<SlopeAndYIntercept> PiecewiseLinearFormulationToSlopeAndYIntercept(
1057 const RoutingModel::RouteDimensionTravelInfo::TransitionInfo::
1058 PiecewiseLinearFormulation& pwl_function,
1059 int index_start = 0, int index_end = -1);
1060
1061} // namespace operations_research
1062
1063#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_LP_SCHEDULING_H_
CumulBoundsPropagator(const RoutingDimension *dimension)
bool PropagateCumulBounds(const std::function< int64_t(int64_t)> &next_accessor, int64_t cumul_offset, const std::vector< RoutingModel::RouteDimensionTravelInfo > *dimension_travel_info_per_route=nullptr)
const RoutingDimension & dimension() const
DimensionSchedulingStatus Optimize(const std::function< int64_t(int64_t)> &next_accessor, const std::vector< RouteDimensionTravelInfo > &dimension_travel_info_per_route, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values, std::vector< std::vector< int > > *resource_indices_per_group, int64_t *cost_without_transits, int64_t *transit_cost, bool clear_lp=true, bool optimize_resource_assignment=true)
DimensionSchedulingStatus OptimizeAndPack(const std::function< int64_t(int64_t)> &next_accessor, const std::vector< RouteDimensionTravelInfo > &dimension_travel_info_per_route, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values)
DimensionSchedulingStatus OptimizeSingleRouteWithResource(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const RouteDimensionTravelInfo &dimension_travel_info, const Resource *resource, bool optimize_vehicle_costs, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values, int64_t *cost_without_transit, int64_t *transit_cost, bool clear_lp=true)
DimensionCumulOptimizerCore(const RoutingDimension *dimension, bool use_precedence_propagator)
std::vector< DimensionSchedulingStatus > OptimizeSingleRouteWithResources(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const std::function< int64_t(int64_t, int64_t)> &transit_accessor, const RouteDimensionTravelInfo &dimension_travel_info, const std::vector< Resource > &resources, const std::vector< int > &resource_indices, bool optimize_vehicle_costs, RoutingLinearSolverWrapper *solver, std::vector< std::vector< int64_t > > *cumul_values, std::vector< std::vector< int64_t > > *break_values, std::vector< int64_t > *costs_without_transits, int64_t *transit_cost, bool clear_lp=true)
DimensionSchedulingStatus OptimizeAndPackSingleRoute(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const RouteDimensionTravelInfo &dimension_travel_info, const Resource *resource, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values)
DimensionSchedulingStatus ComputeSingleRouteSolutionCostWithoutFixedTransits(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const RouteDimensionTravelInfo &dimension_travel_info, RoutingLinearSolverWrapper *solver, absl::Span< const int64_t > solution_cumul_values, absl::Span< const int64_t > solution_break_values, int64_t *cost_without_transits, int64_t *cost_offset=nullptr, bool reuse_previous_model_if_possible=true, bool clear_lp=false, bool clear_solution_constraints=true, absl::Duration *solve_duration=nullptr)
DimensionSchedulingStatus ComputeCumulCostWithoutFixedTransits(const std::function< int64_t(int64_t)> &next_accessor, int64_t *optimal_cost_without_transits)
GlobalDimensionCumulOptimizer(const RoutingDimension *dimension, RoutingSearchParameters::SchedulingSolver solver_type)
GlobalDimensionCumulOptimizer.
DimensionSchedulingStatus ComputeCumuls(const std::function< int64_t(int64_t)> &next_accessor, const std::vector< RoutingModel::RouteDimensionTravelInfo > &dimension_travel_info_per_route, std::vector< int64_t > *optimal_cumuls, std::vector< int64_t > *optimal_breaks, std::vector< std::vector< int > > *optimal_resource_indices_per_group)
DimensionSchedulingStatus ComputePackedCumuls(const std::function< int64_t(int64_t)> &next_accessor, const std::vector< RoutingModel::RouteDimensionTravelInfo > &dimension_travel_info_per_route, std::vector< int64_t > *packed_cumuls, std::vector< int64_t > *packed_breaks)
DimensionSchedulingStatus ComputeRouteSolutionCostWithoutFixedTransits(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const RoutingModel::RouteDimensionTravelInfo &dimension_travel_info, const std::vector< int64_t > &solution_cumul_values, const std::vector< int64_t > &solution_break_values, int64_t *solution_cost, int64_t *cost_offset=nullptr, bool reuse_previous_model_if_possible=false, bool clear_lp=true, absl::Duration *solve_duration=nullptr)
DimensionSchedulingStatus ComputeRouteCumulsAndCostWithoutFixedTransits(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const RoutingModel::RouteDimensionTravelInfo &dimension_travel_info, std::vector< int64_t > *optimal_cumuls, std::vector< int64_t > *optimal_breaks, int64_t *optimal_cost_without_transits)
LocalDimensionCumulOptimizer(const RoutingDimension *dimension, RoutingSearchParameters::SchedulingSolver solver_type)
LocalDimensionCumulOptimizer.
DimensionSchedulingStatus ComputeRouteCumuls(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const RoutingModel::RouteDimensionTravelInfo &dimension_travel_info, const RoutingModel::ResourceGroup::Resource *resource, std::vector< int64_t > *optimal_cumuls, std::vector< int64_t > *optimal_breaks)
DimensionSchedulingStatus ComputeRouteCumulCost(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, int64_t *optimal_cost)
DimensionSchedulingStatus ComputeRouteCumulCostWithoutFixedTransits(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, int64_t *optimal_cost_without_transits)
std::vector< DimensionSchedulingStatus > ComputeRouteCumulCostsForResourcesWithoutFixedTransits(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const std::function< int64_t(int64_t, int64_t)> &transit_accessor, const std::vector< RoutingModel::ResourceGroup::Resource > &resources, const std::vector< int > &resource_indices, bool optimize_vehicle_costs, std::vector< int64_t > *optimal_costs_without_transits, std::vector< std::vector< int64_t > > *optimal_cumuls, std::vector< std::vector< int64_t > > *optimal_breaks)
DimensionSchedulingStatus ComputePackedRouteCumuls(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const RoutingModel::RouteDimensionTravelInfo &dimension_travel_info, const RoutingModel::ResourceGroup::Resource *resource, std::vector< int64_t > *packed_cumuls, std::vector< int64_t > *packed_breaks)
static int64_t FastInt64Round(double x)
Definition mathutil.h:272
static T Abs(const T x)
Definition mathutil.h:96
void AddMaximumConstraint(int max_var, std::vector< int > vars) override
void SetParameters(const std::string &) override
void SetVariableDisjointBounds(int index, const std::vector< int64_t > &starts, const std::vector< int64_t > &ends) override
double GetValue(int index) const override
int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound) override
DimensionSchedulingStatus Solve(absl::Duration duration_limit) override
void SetCoefficient(int ct_index, int index, double coefficient) override
void SetVariableName(int index, absl::string_view name) override
bool SetVariableBounds(int index, int64_t lower_bound, int64_t upper_bound) override
void SetObjectiveCoefficient(int index, double coefficient) override
double GetObjectiveCoefficient(int index) const override
std::string PrintModel() const override
Prints an understandable view of the model.
int64_t GetVariableUpperBound(int index) const override
void SetEnforcementLiteral(int ct, int condition) override
int64_t GetVariableLowerBound(int index) const override
bool ModelIsEmpty() const override
Returns if the model is empty or not.
void AddProductConstraint(int product_var, std::vector< int > vars) override
int64_t GetVariableLowerBound(int index) const override
bool SetVariableBounds(int index, int64_t lower_bound, int64_t upper_bound) override
double GetValue(int index) const override
double GetObjectiveCoefficient(int index) const override
RoutingGlopWrapper(bool is_relaxation, const glop::GlopParameters &parameters)
void SetObjectiveCoefficient(int index, double coefficient) override
void AddMaximumConstraint(int, std::vector< int >) override
DimensionSchedulingStatus Solve(absl::Duration duration_limit) override
int64_t GetVariableUpperBound(int index) const override
void SetVariableDisjointBounds(int index, const std::vector< int64_t > &starts, const std::vector< int64_t > &ends) override
void SetCoefficient(int ct, int index, double coefficient) override
void SetVariableName(int index, absl::string_view name) override
int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound) override
void AddProductConstraint(int, std::vector< int >) override
void SetParameters(const std::string &parameters) override
This function is meant to override the parameters of the solver.
virtual int64_t GetObjectiveValue() const =0
virtual DimensionSchedulingStatus Solve(absl::Duration duration_limit)=0
virtual void SetCoefficient(int ct, int index, double coefficient)=0
virtual int64_t GetVariableUpperBound(int index) const =0
int AddLinearConstraint(int64_t lower_bound, int64_t upper_bound, absl::Span< const std::pair< int, double > > variable_coeffs)
virtual int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound)=0
virtual void SetEnforcementLiteral(int ct, int condition)=0
virtual void AddProductConstraint(int product_var, std::vector< int > vars)=0
virtual std::string PrintModel() const =0
Prints an understandable view of the model.
virtual double GetValue(int index) const =0
virtual void SetVariableDisjointBounds(int index, const std::vector< int64_t > &starts, const std::vector< int64_t > &ends)=0
int AddReifiedLinearConstraint(int64_t lower_bound, int64_t upper_bound, absl::Span< const std::pair< int, double > > weighted_variables)
virtual void SetObjectiveCoefficient(int index, double coefficient)=0
virtual bool SetVariableBounds(int index, int64_t lower_bound, int64_t upper_bound)=0
virtual void SetParameters(const std::string &parameters)=0
This function is meant to override the parameters of the solver.
virtual void AddMaximumConstraint(int max_var, std::vector< int > vars)=0
virtual void SetVariableName(int index, absl::string_view name)=0
virtual bool ModelIsEmpty() const
Returns if the model is empty or not.
virtual int64_t GetVariableLowerBound(int index) const =0
virtual double GetObjectiveCoefficient(int index) const =0
int AddVariable(int64_t lower_bound, int64_t upper_bound)
Adds a variable with bounds [lower_bound, upper_bound].
A full-fledged linear programming solver.
Definition lp_solver.h:31
GlopParameters * GetMutableParameters()
Definition lp_solver.cc:140
Fractional GetObjectiveValue() const
Returns the objective value of the solution with its offset and scaling.
Definition lp_solver.cc:527
const DenseRow & variable_values() const
Accessors to information related to variables.
Definition lp_solver.h:109
void SetParameters(const GlopParameters &parameters)
Definition lp_solver.cc:126
ABSL_MUST_USE_RESULT ProblemStatus Solve(const LinearProgram &lp)
Definition lp_solver.cc:144
const DenseRow & objective_coefficients() const
Returns the objective coefficients (or cost) of variables as a row vector.
Definition lp_data.h:231
void Clear()
Clears, i.e. reset the object to its initial value.
Definition lp_data.cc:143
bool SolutionIsInteger(const DenseRow &solution, Fractional absolute_tolerance) const
Definition lp_data.cc:526
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition lp_data.cc:335
const DenseRow & variable_lower_bounds() const
Definition lp_data.h:237
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition lp_data.cc:258
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition lp_data.cc:318
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Defines the coefficient for col / row.
Definition lp_data.cc:326
const DenseRow & variable_upper_bounds() const
Definition lp_data.h:240
void SetVariableName(ColIndex col, absl::string_view name)
Definition lp_data.cc:241
ColIndex num_variables() const
Returns the number of variables.
Definition lp_data.h:213
void SetMaximizationProblem(bool maximize)
Definition lp_data.cc:352
T Add(std::function< T(Model *)> f)
Definition model.h:89
SatParameters parameters
const std::string name
A name for logging purposes.
const Constraint * ct
int64_t value
IntVar * var
absl::Status status
Definition g_gurobi.cc:44
double upper_bound
double lower_bound
GRBmodel * model
int ct_index
int index
constexpr double kInfinity
Infinity for type Fractional.
Definition lp_types.h:89
ProblemStatus
Different statuses for a given problem.
Definition lp_types.h:107
std::function< SatParameters(Model *)> NewSatParameters(const std::string &params)
CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model)
In SWIG mode, we don't want anything besides these top-level includes.
@ INFEASIBLE
A solution could not be found.
@ OPTIMAL
An optimal solution was found respecting all constraints.
PiecewiseEvaluationStatus ComputePiecewiseLinearFormulationValue(const RoutingModel::RouteDimensionTravelInfo::TransitionInfo::PiecewiseLinearFormulation &pwl, int64_t x, int64_t *value, double delta)
std::vector< bool > SlopeAndYInterceptToConvexityRegions(const std::vector< SlopeAndYIntercept > &slope_and_y_intercept)
int64_t ComputeConvexPiecewiseLinearFormulationValue(const RoutingModel::RouteDimensionTravelInfo::TransitionInfo::PiecewiseLinearFormulation &pwl, int64_t x, double delta)
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)
std::vector< SlopeAndYIntercept > PiecewiseLinearFormulationToSlopeAndYIntercept(const RoutingModel::RouteDimensionTravelInfo::TransitionInfo::PiecewiseLinearFormulation &pwl_function, int index_start, int index_end)
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)
const Variable x
Definition qp_tests.cc:127
int64_t delta
Definition resource.cc:1709
std::vector< int64_t > assignment_costs
std::vector< std::vector< int64_t > > cumul_values
std::vector< std::vector< int64_t > > break_values
int64_t coefficient
int64_t start
Structure to store the slope and y_intercept of a segment.
friend::std::ostream & operator<<(::std::ostream &os, const SlopeAndYIntercept &it)