C++ Reference

C++ Reference: Routing

routing_lp_scheduling.h
Go to the documentation of this file.
1 // Copyright 2010-2018 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 "absl/memory/memory.h"
19 #include "ortools/glop/lp_solver.h"
20 #include "ortools/lp_data/lp_types.h"
21 #include "ortools/sat/cp_model.h"
22 #include "ortools/util/saturated_arithmetic.h"
23 
24 namespace operations_research {
25 
26 // Classes to solve dimension cumul placement (aka scheduling) problems using
27 // linear programming.
28 
29 // Utility class used in the core optimizer to tighten the cumul bounds as much
30 // as possible based on the model precedences.
32  public:
34 
35  // Tightens the cumul bounds starting from the current cumul var min/max,
36  // and propagating the precedences resulting from the next_accessor, and the
37  // dimension's precedence rules.
38  // Returns false iff the precedences are infeasible with the given routes.
39  // Otherwise, the user can call CumulMin() and CumulMax() to retrieve the new
40  // bounds of an index.
41  bool PropagateCumulBounds(const std::function<int64(int64)>& next_accessor,
42  int64 cumul_offset);
43 
44  int64 CumulMin(int index) const {
45  return propagated_bounds_[PositiveNode(index)];
46  }
47 
48  int64 CumulMax(int index) const {
49  const int64 negated_upper_bound = propagated_bounds_[NegativeNode(index)];
50  return negated_upper_bound == kint64min ? kint64max : -negated_upper_bound;
51  }
52 
53  const RoutingDimension& dimension() const { return dimension_; }
54 
55  private:
56  // An arc "tail --offset--> head" represents the relation
57  // tail + offset <= head.
58  // As arcs are stored by tail, we don't store it in the struct.
59  struct ArcInfo {
60  int head;
61  int64 offset;
62  };
63  static const int kNoParent;
64  static const int kParentToBePropagated;
65 
66  // Return the node corresponding to the lower bound of the cumul of index and
67  // -index respectively.
68  int PositiveNode(int index) const { return 2 * index; }
69  int NegativeNode(int index) const { return 2 * index + 1; }
70 
71  void AddNodeToQueue(int node) {
72  if (!node_in_queue_[node]) {
73  bf_queue_.push_back(node);
74  node_in_queue_[node] = true;
75  }
76  }
77 
78  // Adds the relation first_index + offset <= second_index, by adding arcs
79  // first_index --offset--> second_index and
80  // -second_index --offset--> -first_index.
81  void AddArcs(int first_index, int second_index, int64 offset);
82 
83  bool InitializeArcsAndBounds(const std::function<int64(int64)>& next_accessor,
84  int64 cumul_offset);
85 
86  bool UpdateCurrentLowerBoundOfNode(int node, int64 new_lb, int64 offset);
87 
88  bool DisassembleSubtree(int source, int target);
89 
90  bool CleanupAndReturnFalse() {
91  // We clean-up node_in_queue_ for future calls, and return false.
92  for (int node_to_cleanup : bf_queue_) {
93  node_in_queue_[node_to_cleanup] = false;
94  }
95  bf_queue_.clear();
96  return false;
97  }
98 
99  const RoutingDimension& dimension_;
100  const int64 num_nodes_;
101 
102  // TODO(user): Investigate if all arcs for a given tail can be created
103  // at the same time, in which case outgoing_arcs_ could point to an absl::Span
104  // for each tail index.
105  std::vector<std::vector<ArcInfo>> outgoing_arcs_;
106 
107  std::deque<int> bf_queue_;
108  std::vector<bool> node_in_queue_;
109  std::vector<int> tree_parent_node_of_;
110  // After calling PropagateCumulBounds(), for each node index n,
111  // propagated_bounds_[2*n] and -propagated_bounds_[2*n+1] respectively contain
112  // the propagated lower and upper bounds of n's cumul variable.
113  std::vector<int64> propagated_bounds_;
114 
115  // Vector used in DisassembleSubtree() to avoid memory reallocation.
116  std::vector<int> tmp_dfs_stack_;
117 
118  // Used to store the pickup/delivery pairs encountered on the routes.
119  std::vector<std::pair<int64, int64>>
120  visited_pickup_delivery_indices_for_pair_;
121 };
122 
124  public:
126  virtual void Clear() = 0;
127  virtual int CreateNewPositiveVariable() = 0;
128  virtual bool SetVariableBounds(int index, int64 lower_bound,
129  int64 upper_bound) = 0;
130  virtual void SetVariableDisjointBounds(int index,
131  const std::vector<int64>& starts,
132  const std::vector<int64>& ends) = 0;
133  virtual int64 GetVariableLowerBound(int index) const = 0;
134  virtual void SetObjectiveCoefficient(int index, double coefficient) = 0;
135  virtual double GetObjectiveCoefficient(int index) const = 0;
136  virtual void ClearObjective() = 0;
137  virtual int NumVariables() const = 0;
138  virtual int CreateNewConstraint(int64 lower_bound, int64 upper_bound) = 0;
139  virtual void SetCoefficient(int ct, int index, double coefficient) = 0;
140  virtual bool Solve(absl::Duration duration_limit) = 0;
141  virtual double GetObjectiveValue() const = 0;
142  virtual double GetValue(int index) const = 0;
143 };
144 
146  public:
147  explicit RoutingGlopWrapper(const glop::GlopParameters& parameters) {
148  lp_solver_.SetParameters(parameters);
149  linear_program_.SetMaximizationProblem(false);
150  }
151  void Clear() override {
152  linear_program_.Clear();
153  linear_program_.SetMaximizationProblem(false);
154  }
155  int CreateNewPositiveVariable() override {
156  return linear_program_.CreateNewVariable().value();
157  }
158  bool SetVariableBounds(int index, int64 lower_bound,
159  int64 upper_bound) override {
160  DCHECK_GE(lower_bound, 0);
161  // When variable upper bounds are greater than this threshold, precision
162  // issues arise in GLOP. In this case we are just going to suppose that
163  // these high bound values are infinite and not set the upper bound.
164  const int64 kMaxValue = 1e10;
165  const double lp_min = lower_bound;
166  const double lp_max =
167  (upper_bound > kMaxValue) ? glop::kInfinity : upper_bound;
168  if (lp_min <= lp_max) {
169  linear_program_.SetVariableBounds(glop::ColIndex(index), lp_min, lp_max);
170  return true;
171  }
172  // The linear_program would not be feasible, and it cannot handle the
173  // lp_min > lp_max case, so we must detect infeasibility here.
174  return false;
175  }
176  void SetVariableDisjointBounds(int index, const std::vector<int64>& starts,
177  const std::vector<int64>& ends) override {}
178  int64 GetVariableLowerBound(int index) const override {
179  return linear_program_.variable_lower_bounds()[glop::ColIndex(index)];
180  }
181  void SetObjectiveCoefficient(int index, double coefficient) override {
182  linear_program_.SetObjectiveCoefficient(glop::ColIndex(index), coefficient);
183  }
184  double GetObjectiveCoefficient(int index) const override {
185  return linear_program_.objective_coefficients()[glop::ColIndex(index)];
186  }
187  void ClearObjective() override {
188  for (glop::ColIndex i(0); i < linear_program_.num_variables(); ++i) {
189  linear_program_.SetObjectiveCoefficient(i, 0);
190  }
191  }
192  int NumVariables() const override {
193  return linear_program_.num_variables().value();
194  }
195  int CreateNewConstraint(int64 lower_bound, int64 upper_bound) override {
196  const glop::RowIndex ct = linear_program_.CreateNewConstraint();
197  linear_program_.SetConstraintBounds(
198  ct, (lower_bound == kint64min) ? -glop::kInfinity : lower_bound,
199  (upper_bound == kint64max) ? glop::kInfinity : upper_bound);
200  return ct.value();
201  }
202  void SetCoefficient(int ct, int index, double coefficient) override {
203  linear_program_.SetCoefficient(glop::RowIndex(ct), glop::ColIndex(index),
204  coefficient);
205  }
206  bool Solve(absl::Duration duration_limit) override {
207  lp_solver_.GetMutableParameters()->set_max_time_in_seconds(
208  absl::ToDoubleSeconds(duration_limit));
209 
210  // Because we construct the lp one constraint at a time and we never call
211  // SetCoefficient() on the same variable twice for a constraint, we know
212  // that the columns do not contain duplicates and are already ordered by
213  // constraint so we do not need to call linear_program->CleanUp() which can
214  // be costly. Note that the assumptions are DCHECKed() in the call below.
215  linear_program_.NotifyThatColumnsAreClean();
216  VLOG(2) << linear_program_.Dump();
217  const glop::ProblemStatus status = lp_solver_.Solve(linear_program_);
218  if (status != glop::ProblemStatus::OPTIMAL &&
219  status != glop::ProblemStatus::IMPRECISE) {
220  linear_program_.Clear();
221  return false;
222  }
223  return true;
224  }
225  double GetObjectiveValue() const override {
226  return lp_solver_.GetObjectiveValue();
227  }
228  double GetValue(int index) const override {
229  return lp_solver_.variable_values()[glop::ColIndex(index)];
230  }
231 
232  private:
233  glop::LinearProgram linear_program_;
234  glop::LPSolver lp_solver_;
235 };
236 
238  public:
239  RoutingCPSatWrapper() : objective_offset_(0), first_constraint_to_offset_(0) {
240  parameters_.set_num_search_workers(1);
241  // Keeping presolve but with 0 iterations; as of 11/2019 it is
242  // significantly faster than both full presolve and no presolve.
243  parameters_.set_cp_model_presolve(true);
244  parameters_.set_max_presolve_iterations(0);
245  parameters_.set_catch_sigint_signal(false);
246  }
247  ~RoutingCPSatWrapper() override {}
248  void Clear() override {
249  model_.Clear();
250  response_.Clear();
251  objective_coefficients_.clear();
252  objective_offset_ = 0;
253  variable_offset_.clear();
254  constraint_offset_.clear();
255  first_constraint_to_offset_ = 0;
256  }
257  int CreateNewPositiveVariable() override {
258  const int index = model_.variables_size();
259  if (index >= variable_offset_.size()) {
260  variable_offset_.resize(index + 1, 0);
261  }
262  sat::IntegerVariableProto* const variable = model_.add_variables();
263  variable->add_domain(0);
264  variable->add_domain(static_cast<int64>(parameters_.mip_max_bound()));
265  return index;
266  }
267  bool SetVariableBounds(int index, int64 lower_bound,
268  int64 upper_bound) override {
269  DCHECK_GE(lower_bound, 0);
270  variable_offset_[index] = lower_bound;
271  sat::IntegerVariableProto* const variable = model_.mutable_variables(index);
272  variable->set_domain(0, 0);
273  const int64 offset_upper_bound = CapSub(upper_bound, lower_bound);
274  if (offset_upper_bound < 0) return false;
275  if (offset_upper_bound <= parameters_.mip_max_bound()) {
276  variable->set_domain(1, offset_upper_bound);
277  } else {
278  variable->set_domain(1, parameters_.mip_max_bound());
279  }
280  return true;
281  }
282  void SetVariableDisjointBounds(int index, const std::vector<int64>& starts,
283  const std::vector<int64>& ends) override {
284  DCHECK_EQ(starts.size(), ends.size());
285  const int ct = CreateNewConstraint(1, 1);
286  for (int i = 0; i < starts.size(); ++i) {
287  const int variable = CreateNewPositiveVariable();
288  SetVariableBounds(variable, 0, 1);
289  SetCoefficient(ct, variable, 1);
290  const int window_ct = CreateNewConstraint(starts[i], ends[i]);
291  SetCoefficient(window_ct, index, 1);
292  model_.mutable_constraints(window_ct)->add_enforcement_literal(variable);
293  }
294  }
295  int64 GetVariableLowerBound(int index) const override {
296  return CapAdd(model_.variables(index).domain(0), variable_offset_[index]);
297  }
298  void SetObjectiveCoefficient(int index, double coefficient) override {
299  // TODO(user): Check variable bounds are never set after setting the
300  // objective coefficient.
301  if (index >= objective_coefficients_.size()) {
302  objective_coefficients_.resize(index + 1, 0);
303  }
304  objective_coefficients_[index] = coefficient;
305  sat::CpObjectiveProto* const objective = model_.mutable_objective();
306  objective->add_vars(index);
307  objective->add_coeffs(coefficient);
308  objective_offset_ += coefficient * variable_offset_[index];
309  }
310  double GetObjectiveCoefficient(int index) const override {
311  return (index < objective_coefficients_.size())
312  ? objective_coefficients_[index]
313  : 0;
314  }
315  void ClearObjective() override {
316  model_.mutable_objective()->Clear();
317  objective_offset_ = 0;
318  }
319  int NumVariables() const override { return model_.variables_size(); }
320  int CreateNewConstraint(int64 lower_bound, int64 upper_bound) override {
321  const int ct_index = model_.constraints_size();
322  if (ct_index >= constraint_offset_.size()) {
323  constraint_offset_.resize(ct_index + 1, 0);
324  }
325  sat::LinearConstraintProto* const ct =
326  model_.add_constraints()->mutable_linear();
327  ct->add_domain(lower_bound);
328  ct->add_domain(upper_bound);
329  return ct_index;
330  }
331  void SetCoefficient(int ct_index, int index, double coefficient) override {
332  // TODO(user): Check variable bounds are never set after setting the
333  // variable coefficient.
334  sat::LinearConstraintProto* const ct =
335  model_.mutable_constraints(ct_index)->mutable_linear();
336  ct->add_vars(index);
337  ct->add_coeffs(coefficient);
338  constraint_offset_[ct_index] =
339  CapAdd(constraint_offset_[ct_index],
340  CapProd(variable_offset_[index], coefficient));
341  }
342  bool Solve(absl::Duration duration_limit) override {
343  // Set constraint offsets
344  for (int ct_index = first_constraint_to_offset_;
345  ct_index < constraint_offset_.size(); ++ct_index) {
346  sat::LinearConstraintProto* const ct =
347  model_.mutable_constraints(ct_index)->mutable_linear();
348  ct->set_domain(0, CapSub(ct->domain(0), constraint_offset_[ct_index]));
349  ct->set_domain(1, CapSub(ct->domain(1), constraint_offset_[ct_index]));
350  }
351  first_constraint_to_offset_ = constraint_offset_.size();
352  parameters_.set_max_time_in_seconds(absl::ToDoubleSeconds(duration_limit));
353  VLOG(2) << model_.DebugString();
354  if (hint_.vars_size() == model_.variables_size()) {
355  *model_.mutable_solution_hint() = hint_;
356  }
357  sat::Model model;
358  model.Add(sat::NewSatParameters(parameters_));
359  response_ = sat::SolveCpModel(model_, &model);
360  VLOG(2) << response_.DebugString();
361  if (response_.status() == sat::CpSolverStatus::OPTIMAL ||
362  (response_.status() == sat::CpSolverStatus::FEASIBLE &&
363  !model_.has_objective())) {
364  hint_.Clear();
365  for (int i = 0; i < response_.solution_size(); ++i) {
366  hint_.add_vars(i);
367  hint_.add_values(response_.solution(i));
368  }
369  return true;
370  }
371  return false;
372  }
373  double GetObjectiveValue() const override {
374  return response_.objective_value() + objective_offset_;
375  }
376  double GetValue(int index) const override {
377  return response_.solution(index) + variable_offset_[index];
378  }
379 
380  private:
381  sat::CpModelProto model_;
382  sat::CpSolverResponse response_;
383  sat::SatParameters parameters_;
384  std::vector<double> objective_coefficients_;
385  double objective_offset_;
386  std::vector<int64> variable_offset_;
387  std::vector<int64> constraint_offset_;
388  int first_constraint_to_offset_;
389  sat::PartialVariableAssignment hint_;
390 };
391 
392 // Utility class used in Local/GlobalDimensionCumulOptimizer to set the linear
393 // solver constraints and solve the problem.
395  public:
397  bool use_precedence_propagator)
398  : dimension_(dimension),
399  visited_pickup_delivery_indices_for_pair_(
400  dimension->model()->GetPickupAndDeliveryPairs().size(), {-1, -1}) {
401  if (use_precedence_propagator) {
402  propagator_ = absl::make_unique<CumulBoundsPropagator>(dimension);
403  }
404  }
405 
406  // In the OptimizeSingleRoute() and Optimize() methods, if both "cumul_values"
407  // and "cost" parameters are null, we don't optimize the cost and stop at the
408  // first feasible solution in the linear solver (since in this case only
409  // feasibility is of interest).
410  bool OptimizeSingleRoute(int vehicle,
411  const std::function<int64(int64)>& next_accessor,
412  RoutingLinearSolverWrapper* solver,
413  std::vector<int64>* cumul_values, int64* cost,
414  int64* transit_cost, bool clear_lp = true);
415 
416  bool Optimize(const std::function<int64(int64)>& next_accessor,
417  RoutingLinearSolverWrapper* solver,
418  std::vector<int64>* cumul_values, int64* cost,
419  int64* transit_cost, bool clear_lp = true);
420 
421  bool OptimizeAndPack(const std::function<int64(int64)>& next_accessor,
422  RoutingLinearSolverWrapper* solver,
423  std::vector<int64>* cumul_values);
424 
426  int vehicle, const std::function<int64(int64)>& next_accessor,
427  RoutingLinearSolverWrapper* solver, std::vector<int64>* cumul_values);
428 
429  const RoutingDimension* dimension() const { return dimension_; }
430 
431  private:
432  // Initializes the containers and given solver. Must be called prior to
433  // setting any contraints and solving.
434  void InitOptimizer(RoutingLinearSolverWrapper* solver);
435 
436  // Computes the minimum/maximum of cumuls for nodes on "route", and sets them
437  // in current_route_[min|max]_cumuls_ respectively.
438  // If the propagator_ is not null, uses the bounds tightened by the
439  // propagator.
440  // Otherwise, the bounds are computed by going over the nodes on the route
441  // using the CP bounds, and the fixed transits are used to tighten them.
442  bool ComputeRouteCumulBounds(const std::vector<int64>& route,
443  const std::vector<int64>& fixed_transits,
444  int64 cumul_offset);
445 
446  // Sets the constraints for all nodes on "vehicle"'s route according to
447  // "next_accessor". If optimize_costs is true, also sets the objective
448  // coefficients for the LP.
449  // Returns false if some infeasibility was detected, true otherwise.
450  bool SetRouteCumulConstraints(
451  int vehicle, const std::function<int64(int64)>& next_accessor,
452  int64 cumul_offset, bool optimize_costs,
453  RoutingLinearSolverWrapper* solver, int64* route_transit_cost,
454  int64* route_cost_offset);
455 
456  // Sets the global constraints on the dimension, and adds global objective
457  // cost coefficients if optimize_costs is true.
458  // NOTE: When called, the call to this function MUST come after
459  // SetRouteCumulConstraints() has been called on all routes, so that
460  // index_to_cumul_variable_ and min_start/max_end_cumul_ are correctly
461  // initialized.
462  void SetGlobalConstraints(bool optimize_costs,
464 
465  void SetCumulValuesFromLP(const std::vector<int>& cumul_variables,
466  int64 offset, RoutingLinearSolverWrapper* solver,
467  std::vector<int64>* cumul_values);
468 
469  // This function packs the routes of the given vehicles while keeping the cost
470  // of the LP lower than its current (supposed optimal) objective value.
471  // It does so by setting the current objective variables' coefficient to 0 and
472  // setting the coefficient of the route ends to 1, to first minimize the route
473  // ends' cumuls, and then maximizes the starts' cumuls without increasing the
474  // ends.
475  bool PackRoutes(std::vector<int> vehicles,
477 
478  std::unique_ptr<CumulBoundsPropagator> propagator_;
479  std::vector<int64> current_route_min_cumuls_;
480  std::vector<int64> current_route_max_cumuls_;
481  const RoutingDimension* const dimension_;
482  std::vector<int> current_route_cumul_variables_;
483  std::vector<int> index_to_cumul_variable_;
484  int max_end_cumul_;
485  int min_start_cumul_;
486  std::vector<std::pair<int64, int64>>
487  visited_pickup_delivery_indices_for_pair_;
488 };
489 
490 // Class used to compute optimal values for dimension cumuls of routes,
491 // minimizing cumul soft lower and upper bound costs, and vehicle span costs of
492 // a route.
493 // In its methods, next_accessor is a callback returning the next node of a
494 // given node on a route.
496  public:
500 
501  // If feasible, computes the optimal cost of the route performed by a vehicle,
502  // minimizing cumul soft lower and upper bound costs and vehicle span costs,
503  // and stores it in "optimal_cost" (if not null).
504  // Returns true iff the route respects all constraints.
505  bool ComputeRouteCumulCost(int vehicle,
506  const std::function<int64(int64)>& next_accessor,
507  int64* optimal_cost);
508 
509  // Same as ComputeRouteCumulCost, but the cost computed does not contain
510  // the part of the vehicle span cost due to fixed transits.
512  int vehicle, const std::function<int64(int64)>& next_accessor,
513  int64* optimal_cost_without_transits);
514 
515  // If feasible, computes the optimal cumul values of the route performed by a
516  // vehicle, minimizing cumul soft lower and upper bound costs and vehicle span
517  // costs, stores them in "optimal_cumuls" (if not null), and returns true.
518  // Returns false if the route is not feasible.
519  bool ComputeRouteCumuls(int vehicle,
520  const std::function<int64(int64)>& next_accessor,
521  std::vector<int64>* optimal_cumuls);
522 
523  // Similar to ComputeRouteCumuls, but also tries to pack the cumul values on
524  // the route, such that the cost remains the same, the cumul of route end is
525  // minimized, and then the cumul of the start of the route is maximized.
527  int vehicle, const std::function<int64(int64)>& next_accessor,
528  std::vector<int64>* packed_cumuls);
529 
530  const RoutingDimension* dimension() const {
531  return optimizer_core_.dimension();
532  }
533 
534  private:
535  std::vector<std::unique_ptr<RoutingLinearSolverWrapper>> solver_;
536  DimensionCumulOptimizerCore optimizer_core_;
537 };
538 
540  public:
542  // If feasible, computes the optimal cost of the entire model with regards to
543  // the optimizer_core_'s dimension costs, minimizing cumul soft lower/upper
544  // bound costs and vehicle/global span costs, and stores it in "optimal_cost"
545  // (if not null).
546  // Returns true iff all the constraints can be respected.
548  const std::function<int64(int64)>& next_accessor,
549  int64* optimal_cost_without_transits);
550  // If feasible, computes the optimal cumul values, minimizing cumul soft
551  // lower/upper bound costs and vehicle/global span costs, stores them in
552  // "optimal_cumuls" (if not null), and returns true.
553  // Returns false if the routes are not feasible.
554  bool ComputeCumuls(const std::function<int64(int64)>& next_accessor,
555  std::vector<int64>* optimal_cumuls);
556 
557  // Returns true iff the routes resulting from the next_accessor are feasible
558  // wrt the constraints on the optimizer_core_.dimension()'s cumuls.
559  bool IsFeasible(const std::function<int64(int64)>& next_accessor);
560 
561  // Similar to ComputeCumuls, but also tries to pack the cumul values on all
562  // routes, such that the cost remains the same, the cumuls of route ends are
563  // minimized, and then the cumuls of the starts of the routes are maximized.
564  bool ComputePackedCumuls(const std::function<int64(int64)>& next_accessor,
565  std::vector<int64>* packed_cumuls);
566 
567  const RoutingDimension* dimension() const {
568  return optimizer_core_.dimension();
569  }
570 
571  private:
572  std::unique_ptr<RoutingLinearSolverWrapper> solver_;
573  DimensionCumulOptimizerCore optimizer_core_;
574 };
575 
576 } // namespace operations_research
577 
578 #endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_LP_SCHEDULING_H_
virtual int CreateNewPositiveVariable()=0
double GetObjectiveValue() const override
void SetVariableDisjointBounds(int index, const std::vector< int64 > &starts, const std::vector< int64 > &ends) override
virtual double GetObjectiveValue() const =0
double GetObjectiveCoefficient(int index) const override
bool Solve(absl::Duration duration_limit) override
virtual double GetValue(int index) const =0
~RoutingCPSatWrapper() override
bool SetVariableBounds(int index, int64 lower_bound, int64 upper_bound) override
int64 GetVariableLowerBound(int index) const override
const RoutingDimension * dimension() const
void Clear() override
const RoutingDimension & dimension() const
virtual int CreateNewConstraint(int64 lower_bound, int64 upper_bound)=0
void SetCoefficient(int ct_index, int index, double coefficient) override
DimensionCumulOptimizerCore(const RoutingDimension *dimension, bool use_precedence_propagator)
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
const RoutingDimension * dimension() const
bool ComputeCumulCostWithoutFixedTransits(const std::function< int64(int64)> &next_accessor, int64 *optimal_cost_without_transits)
bool OptimizeAndPack(const std::function< int64(int64)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64 > *cumul_values)
int NumVariables() const override
virtual int64 GetVariableLowerBound(int index) const =0
bool ComputeRouteCumuls(int vehicle, const std::function< int64(int64)> &next_accessor, std::vector< int64 > *optimal_cumuls)
bool Solve(absl::Duration duration_limit) override
double GetValue(int index) const override
RoutingGlopWrapper(const glop::GlopParameters &parameters)
virtual bool Solve(absl::Duration duration_limit)=0
bool IsFeasible(const std::function< int64(int64)> &next_accessor)
int64 CumulMin(int index) const
virtual void SetObjectiveCoefficient(int index, double coefficient)=0
int CreateNewPositiveVariable() override
int CreateNewConstraint(int64 lower_bound, int64 upper_bound) override
void SetObjectiveCoefficient(int index, double coefficient) override
RoutingCPSatWrapper()
int CreateNewConstraint(int64 lower_bound, int64 upper_bound) override
bool ComputeRouteCumulCost(int vehicle, const std::function< int64(int64)> &next_accessor, int64 *optimal_cost)
bool SetVariableBounds(int index, int64 lower_bound, int64 upper_bound) override
int NumVariables() const override
void SetVariableDisjointBounds(int index, const std::vector< int64 > &starts, const std::vector< int64 > &ends) override
double GetValue(int index) const override
Dimensions represent quantities accumulated at nodes along the routes.
Definition: routing.h:2076
bool PropagateCumulBounds(const std::function< int64(int64)> &next_accessor, int64 cumul_offset)
bool ComputeCumuls(const std::function< int64(int64)> &next_accessor, std::vector< int64 > *optimal_cumuls)
virtual void Clear()=0
void SetCoefficient(int ct, int index, double coefficient) override
double GetObjectiveValue() const override
CumulBoundsPropagator(const RoutingDimension *dimension)
double GetObjectiveCoefficient(int index) const override
bool OptimizeSingleRoute(int vehicle, const std::function< int64(int64)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64 > *cumul_values, int64 *cost, int64 *transit_cost, bool clear_lp=true)
bool OptimizeAndPackSingleRoute(int vehicle, const std::function< int64(int64)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64 > *cumul_values)
int CreateNewPositiveVariable() override
void SetObjectiveCoefficient(int index, double coefficient) override
virtual void SetCoefficient(int ct, int index, double coefficient)=0
bool ComputeRouteCumulCostWithoutFixedTransits(int vehicle, const std::function< int64(int64)> &next_accessor, int64 *optimal_cost_without_transits)
virtual void SetVariableDisjointBounds(int index, const std::vector< int64 > &starts, const std::vector< int64 > &ends)=0
void ClearObjective() override
bool ComputePackedRouteCumuls(int vehicle, const std::function< int64(int64)> &next_accessor, std::vector< int64 > *packed_cumuls)
int64 GetVariableLowerBound(int index) const override
RoutingSearchParameters_SchedulingSolver
int64 CumulMax(int index) const
virtual bool SetVariableBounds(int index, int64 lower_bound, int64 upper_bound)=0
bool Optimize(const std::function< int64(int64)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64 > *cumul_values, int64 *cost, int64 *transit_cost, bool clear_lp=true)
virtual int NumVariables() const =0
LocalDimensionCumulOptimizer(const RoutingDimension *dimension, RoutingSearchParameters::SchedulingSolver solver_type)
virtual double GetObjectiveCoefficient(int index) const =0
virtual ~RoutingLinearSolverWrapper()
const RoutingDimension * dimension() const
void ClearObjective() override
bool ComputePackedCumuls(const std::function< int64(int64)> &next_accessor, std::vector< int64 > *packed_cumuls)
virtual void ClearObjective()=0
void Clear() override
GlobalDimensionCumulOptimizer(const RoutingDimension *dimension)