OR-Tools  9.0
indexed_model.h
Go to the documentation of this file.
1 // Copyright 2010-2021 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 // An index based C++ API for building optimization problems.
15 //
16 // Models problems of the form:
17 // min c * x + d
18 // s.t. clb <= A * x <= cub
19 // vlb <= x <= vub
20 // x_i integer for i in I
21 // where:
22 // * x in R^m are the decision variables,
23 // * c in R^m,
24 // * d in R,
25 // * vlb and lbu in R^m and can be infinte,
26 // * clb, cub are in R^n and can be infinite,
27 // * A is an m by n matrix.
28 // * I is a subset of the variables.
29 //
30 // The min in the objective can also be changed to a max.
31 //
32 //
33 // A simple example:
34 //
35 // Model the problem:
36 // max 2.0 * x + y
37 // s.t. x + y <= 1.5
38 // x in {0.0, 1.0}
39 // 0 <= y <= 2.5
40 //
41 // using ::operations_research::math_opt::IndexedModel;
42 // using ::operations_research::math_opt::VariableId;
43 // using ::operations_research::math_opt::LinearConstraintId;
44 // using ::operations_research::math_opt::ModelProto;
45 // using ::operations_research::math_opt::ModelProtoUpdate;
46 //
47 // IndexedModel model("my_model");
48 // const VariableId x = model.AddVariable(0.0, 1.0, true, "x");
49 // const VariableId y = model.AddVariable(0.0, 2.5, false, "y");
50 // const LinearConstraintId c = model.AddLinearConstraint(
51 // -std::numeric_limits<double>::infinity, 1.5, "c");
52 // model.set_linear_constraint_coefficient(x, c, 1.0);
53 // model.set_linear_constraint_coefficient(y, c, 1.0);
54 // model.set_linear_objective_coefficient(x, 2.0);
55 // model.set_linear_objective_coefficient(y, 1.0);
56 // model.set_maximize();
57 //
58 // Now, export to a proto describing the model:
59 //
60 // const ModelProto model_proto = model.ExportModel();
61 //
62 // Modify the problem and get a model update proto:
63 //
64 // model.Checkpoint();
65 // c.set_upper_bound(2.0);
66 // const ModelUpdate update_proto = model.ExportModelUpdate();
67 //
68 // Reading and writing model properties:
69 //
70 // Properties of the model (e.g. variable/constraint bounds) can be written
71 // and read in amortized O(1) time. Deleting a variable will take time
72 // O(#constraints containing the variable), and likewise deleting a constraint
73 // will take time O(#variables in the constraint). The constraint matrix is
74 // stored as hash map where the key is a {LinearConstraintId, VariableId}
75 // pair and the value is the coefficient. The nonzeros of the matrix are
76 // additionally stored by row and by column, but these indices generated lazily
77 // upon first use. Asking for the set of variables in a constraint, the
78 // constraints in a variable, deleting a variable or constraint, or requesting a
79 // ModelUpdate proto will all trigger these additional indices to be generated.
80 //
81 // Exporting the Model proto:
82 //
83 // The Model proto is an equivalent representation to IndexedModel. It has a
84 // smaller memory footprint and optimized for storage/transport, rather than
85 // efficient modification. It is also the format consumed by solvers in this
86 // library. The Model proto can be generated by calling
87 // IndexedModel::ExportModel().
88 //
89 // Incrementalism, the ModelUpdate proto, and Checkpoints:
90 //
91 // To update an existing model as specified by a Model proto, solvers consume a
92 // ModelUpdate proto, which describes the changes to a model (e.g. new
93 // variables or a change in a variable bound). IndexedModel tracks the changes
94 // made and produces a ModelUpdate proto describing these changes with the
95 // method IndexedModel::ExportModelUpdate(). The changes returned will be the
96 // modifications since the previous call to IndexedModel::Checkpoint(). Note
97 // that, for newly initialized models, before the first checkpoint, there is no
98 // additional memory overhead from tracking changes. See
99 // g3doc/ortools/math_opt/g3doc/model_building_complexity.md
100 // for details.
101 //
102 // On bad input:
103 //
104 // Using a bad variable id or constraint id (an id not in the current model,
105 // which includes ids that have been deleted) on any method will result in an
106 // immediate failure (either a CHECK failure or an exception, which is an
107 // implementation detail you should not rely on). We make no attempt to say if a
108 // model is invalid (e.g. a variable lower bound is infinite, exceeds an upper
109 // bound, or is NaN). The exported models are validated instead, see
110 // model_validator.h.
111 
112 #ifndef OR_TOOLS_MATH_OPT_INDEXED_MODEL_H_
113 #define OR_TOOLS_MATH_OPT_INDEXED_MODEL_H_
114 
115 #include <cstdint>
116 #include <limits>
117 #include <string>
118 #include <utility>
119 #include <vector>
120 
121 #include "absl/container/flat_hash_map.h"
122 #include "absl/container/flat_hash_set.h"
123 #include "absl/meta/type_traits.h"
124 #include "absl/strings/string_view.h"
125 #include "absl/types/span.h"
126 #include "ortools/base/int_type.h"
128 #include "ortools/base/map_util.h"
129 #include "ortools/math_opt/model.pb.h"
130 #include "ortools/math_opt/model_update.pb.h"
131 #include "ortools/math_opt/result.pb.h"
132 #include "ortools/math_opt/solution.pb.h"
133 #include "ortools/math_opt/sparse_containers.pb.h"
134 
135 namespace operations_research {
136 namespace math_opt {
137 
138 DEFINE_INT_TYPE(VariableId, int64_t);
139 DEFINE_INT_TYPE(LinearConstraintId, int64_t);
140 
141 // A mathematical optimization model.
142 //
143 // Supports the efficient creation and modification of an optimization model,
144 // and the export of Model and ModelUpdate protos.
145 //
146 // All methods run in amortized O(1) (as amortized over calls to that exact
147 // function) unless otherwise specified.
149  public:
150  // Creates an empty minimization problem.
151  explicit IndexedModel(absl::string_view name = "") : name_(name) {}
152  inline const std::string& name() const { return name_; }
153 
155  // Variables
157 
158  // Adds a continuous unbounded variable to the model and returns its id.
159  //
160  // See AddVariable(double, double, bool, absl::string_view) for details.
161  inline VariableId AddVariable(absl::string_view name = "");
162 
163  // Adds a variable to the model and returns its id.
164  //
165  // The returned ids begin at zero and increase by one with each call to
166  // AddVariable. Deleted ids are NOT reused. If no variables are deleted,
167  // the ids in the model will be consecutive.
168  VariableId AddVariable(double lower_bound, double upper_bound,
169  bool is_integer, absl::string_view name = "");
170 
171  inline double variable_lower_bound(VariableId id) const;
172  inline double variable_upper_bound(VariableId id) const;
173  inline bool is_variable_integer(VariableId id) const;
174  inline const std::string& variable_name(VariableId id) const;
175 
176  inline void set_variable_lower_bound(VariableId id, double lower_bound);
177  inline void set_variable_upper_bound(VariableId id, double upper_bound);
178  inline void set_variable_is_integer(VariableId id, bool is_integer);
179  inline void set_variable_as_integer(VariableId id);
180  inline void set_variable_as_continuous(VariableId id);
181 
182  // Removes a variable from the model.
183  //
184  // It is an error to use a deleted variable id as input to any subsequent
185  // function calls on the model. Runs in O(#constraints containing the
186  // variable).
187  void DeleteVariable(VariableId id);
188 
189  // The number of variables in the model.
190  //
191  // Equal to the number of variables created minus the number of variables
192  // deleted.
193  inline int num_variables() const;
194 
195  // The returned id of the next call to AddVariable.
196  //
197  // Equal to the number of variables created.
198  inline VariableId next_variable_id() const;
199 
200  // Returns true if this id has been created and not yet deleted.
201  inline bool has_variable(VariableId id) const;
202 
203  // The VariableIds in use (not deleted), order not defined.
204  std::vector<VariableId> variables() const;
205 
206  // Returns a sorted vector of all existing (not deleted) variables in the
207  // model.
208  //
209  // Runs in O(n log(n)), where n is the number of variables returned.
210  std::vector<VariableId> SortedVariables() const;
211 
213  // Linear Constraints
215 
216  // Adds a linear constraint to the model with a lower bound of -inf and an
217  // upper bound of +inf and returns its id.
218  //
219  // See AddLinearConstraint(double, double, absl::string_view) for details.
220  inline LinearConstraintId AddLinearConstraint(absl::string_view name = "");
221 
222  // Adds a linear constraint to the model returns its id.
223  //
224  // The returned ids begin at zero and increase by one with each call to
225  // AddLinearConstraint. Deleted ids are NOT reused. If no linear
226  // constraints are deleted, the ids in the model will be consecutive.
227  LinearConstraintId AddLinearConstraint(double lower_bound, double upper_bound,
228  absl::string_view name = "");
229 
230  inline double linear_constraint_lower_bound(LinearConstraintId id) const;
231  inline double linear_constraint_upper_bound(LinearConstraintId id) const;
232  inline const std::string& linear_constraint_name(LinearConstraintId id) const;
233 
234  inline void set_linear_constraint_lower_bound(LinearConstraintId id,
235  double lower_bound);
236  inline void set_linear_constraint_upper_bound(LinearConstraintId id,
237  double upper_bound);
238 
239  // Removes a linear constraint from the model.
240  //
241  // It is an error to use a deleted linear constraint id as input to any
242  // subsequent function calls on the model. Runs in O(#variables in the linear
243  // constraint).
244  void DeleteLinearConstraint(LinearConstraintId id);
245 
246  // The number of linear constraints in the model.
247  //
248  // Equal to the number of linear constraints created minus the number of
249  // linear constraints deleted.
250  inline int num_linear_constraints() const;
251 
252  // The returned id of the next call to AddLinearConstraint.
253  //
254  // Equal to the number of linear constraints created.
255  inline LinearConstraintId next_linear_constraint_id() const;
256 
257  // Returns true if this id has been created and not yet deleted.
258  inline bool has_linear_constraint(LinearConstraintId id) const;
259 
260  // The LinearConstraintsIds in use (not deleted), order not defined.
261  std::vector<LinearConstraintId> linear_constraints() const;
262 
263  // Returns a sorted vector of all existing (not deleted) linear constraints in
264  // the model.
265  //
266  // Runs in O(n log(n)), where n is the number of linear constraints returned.
267  std::vector<LinearConstraintId> SortedLinearConstraints() const;
268 
270  // Linear constraint matrix
272 
273  // Returns 0.0 if the entry is not in matrix.
274  inline double linear_constraint_coefficient(LinearConstraintId constraint,
275  VariableId variable) const;
277  LinearConstraintId constraint, VariableId variable) const;
278 
279  // Setting a value to 0.0 will delete the {constraint, variable} pair from the
280  // underlying sparse matrix representation (and has no effect if the pair is
281  // not present).
282  inline void set_linear_constraint_coefficient(LinearConstraintId constraint,
283  VariableId variable,
284  double value);
285 
286  // The {linear constraint, variable} pairs with nonzero linear constraint
287  // matrix coefficients.
288  inline const absl::flat_hash_map<std::pair<LinearConstraintId, VariableId>,
289  double>&
290  linear_constraint_matrix() const;
291 
292  // Returns the variables with nonzero coefficients in a linear constraint.
293  //
294  // Runs in O(1), but triggers allocations that are O(nnz) on first use through
295  // a lazy initialization.
296  inline const absl::flat_hash_set<VariableId>& variables_in_linear_constraint(
297  LinearConstraintId constraint);
298 
299  // Returns the linear constraints with nonzero coefficients on a variable.
300  //
301  // Runs in O(1), but triggers allocations that are O(nnz) on first use through
302  // a lazy initialization.
303  inline const absl::flat_hash_set<LinearConstraintId>&
304  linear_constraints_with_variable(VariableId variable);
305 
307  // Objective
309 
310  inline bool is_maximize() const;
311  inline double objective_offset() const;
312  // Returns 0.0 if this variable has no linear objective coefficient.
313  inline double linear_objective_coefficient(VariableId variable) const;
315  VariableId variable) const;
316 
317  inline void set_is_maximize(bool is_maximize);
318  inline void set_maximize();
319  inline void set_minimize();
320  inline void set_objective_offset(double value);
321 
322  // Setting a value to 0.0 will delete the variable from the underlying sparse
323  // representation (and has no effect if the variable is not present).
324  inline void set_linear_objective_coefficient(VariableId variable,
325  double value);
326 
327  // Equivalent to calling set_linear_objective_coefficient(v, 0.0) for every
328  // variable with nonzero objective coefficient.
329  //
330  // Runs in O(#variables with nonzero objective coefficient).
331  inline void clear_objective();
332 
333  // The variables with nonzero linear objective coefficients.
334  inline const absl::flat_hash_map<VariableId, double>& linear_objective()
335  const;
336 
337  // Returns a sorted vector of all variables in the model with nonzero linear
338  // objective coefficients.
339  //
340  // Runs in O(n log(n)), where n is the number of variables returned.
341  std::vector<VariableId> SortedLinearObjectiveNonzeroVariables() const;
342 
344  // Export
346 
347  // Returns a proto representation of the optimization model.
348  ModelProto ExportModel() const;
349 
350  // Returns a proto representation of the changes to the model since the most
351  // recent checkpoint.
352  ModelUpdateProto ExportModelUpdate();
353 
354  // Use the current model state as the starting point to calculate the
355  // ModelUpdateProto next time ExportModelUpdate() is called.
356  void Checkpoint();
357 
358  private:
359  struct VariableData {
360  double lower_bound = -std::numeric_limits<double>::infinity();
361  double upper_bound = std::numeric_limits<double>::infinity();
362  bool is_integer = false;
363  std::string name = "";
364  };
365  struct LinearConstraintData {
366  double lower_bound = -std::numeric_limits<double>::infinity();
367  double upper_bound = std::numeric_limits<double>::infinity();
368  std::string name = "";
369  };
370 
371  template <typename T>
372  void set_variable_property(VariableId id, T value, T VariableData::*field,
373  absl::flat_hash_set<VariableId>& dirty_set);
374 
375  inline void set_linear_constraint_property(
376  const LinearConstraintId id, double value,
377  double LinearConstraintData::*field,
378  absl::flat_hash_set<LinearConstraintId>& dirty_set);
379 
380  // Initializes lazy_matrix_columns_ (column major storage of the linear
381  // constraint matrix) if it is still empty and there is at least one variable
382  // in the model.
383  void EnsureLazyMatrixColumns();
384 
385  // Initializes lazy_matrix_rows_ (row major storage of the linear constraint
386  // matrix) if it is still empty and there is at least one linear constraint in
387  // the model.
388  void EnsureLazyMatrixRows();
389 
390  // Export a single variable to proto.
391  void AppendVariable(VariableId id, VariablesProto& variables_proto) const;
392 
393  // Export a single linear constraint to proto.
394  void AppendLinearConstraint(
395  LinearConstraintId id,
396  LinearConstraintsProto& linear_constraints_proto) const;
397 
398  // If an element in entries is not found in linear_constraint_matrix_, it is
399  // set to 0.0 in matrix. Entries should be sorted by constraint then by
400  // variable.
401  void ExportLinearConstraintMatrix(
402  absl::Span<const std::pair<LinearConstraintId, VariableId>> entries,
403  SparseDoubleMatrixProto& matrix) const;
404 
405  std::string name_;
406  VariableId next_variable_id_ = VariableId(0);
407  LinearConstraintId next_linear_constraint_id_ = LinearConstraintId(0);
408 
409  bool is_maximize_ = false;
410  double objective_offset_ = 0.0;
411 
412  absl::flat_hash_map<VariableId, VariableData> variables_;
413  absl::flat_hash_map<LinearConstraintId, LinearConstraintData>
414  linear_constraints_;
415  // The values of the map must never include zero.
416  absl::flat_hash_map<VariableId, double> linear_objective_;
417  // The values of the map must never include zero.
418  absl::flat_hash_map<std::pair<LinearConstraintId, VariableId>, double>
419  linear_constraint_matrix_;
420  absl::flat_hash_map<VariableId, absl::flat_hash_set<LinearConstraintId>>
421  lazy_matrix_columns_;
422  absl::flat_hash_map<LinearConstraintId, absl::flat_hash_set<VariableId>>
423  lazy_matrix_rows_;
424 
425  // Update information
426  //
427  // Implicitly, all data for variables and constraints added after the last
428  // checkpoint are considered "new" and will NOT be stored in the "dirty" data
429  // structures below.
430  VariableId variables_checkpoint_ = VariableId(0);
431  LinearConstraintId linear_constraints_checkpoint_ = LinearConstraintId(0);
432  bool dirty_objective_direction_ = false;
433  bool dirty_objective_offset_ = false;
434 
435  absl::flat_hash_set<VariableId> dirty_variable_deletes_;
436  absl::flat_hash_set<VariableId> dirty_variable_lower_bounds_;
437  absl::flat_hash_set<VariableId> dirty_variable_upper_bounds_;
438  absl::flat_hash_set<VariableId> dirty_variable_is_integer_;
439 
440  absl::flat_hash_set<VariableId> dirty_linear_objective_coefficients_;
441 
442  absl::flat_hash_set<LinearConstraintId> dirty_linear_constraint_deletes_;
443  absl::flat_hash_set<LinearConstraintId> dirty_linear_constraint_lower_bounds_;
444  absl::flat_hash_set<LinearConstraintId> dirty_linear_constraint_upper_bounds_;
445 
446  // Only for pairs where both the variable and constraint are before the
447  // checkpoint, i.e.
448  // var_id < variables_checkpoint_ &&
449  // lin_con_id < linear_constraints_checkpoint_
450  absl::flat_hash_set<std::pair<LinearConstraintId, VariableId>>
451  dirty_linear_constraint_matrix_keys_;
452 };
453 
454 // A solution to the problem modeled in IndexedModel.
455 //
456 // IndexedPrimalSolution will satisfy (see top of file notation):
457 // objective_value = c * variable_values + d
458 // In addition, if feasible (as is typical), it should additionally satisfy:
459 // vlb <= variable_values <= vub
460 // clb <= A * variable_values <= cub
461 // variable_values_i integer for i in I.
462 //
463 // For details, see go/mathopt-solutions#primal-solution.
465  absl::flat_hash_map<VariableId, double> variable_values;
467 };
468 
469 // A direction of improving objective value that maintains feasibility.
470 //
471 // Indexed primal ray will satisfy (see top of file notation):
472 // * c * x < 0 for minimization problems, c * x > 0 for maximization problems.
473 // * A_j * x <= 0 for finite cub_j
474 // * A_j * x >= 0 for finite clb_j
475 // * x_i <= 0 for finite vub_i
476 // * x_i >= 0 for finite vlb_i
477 // where A_j are the row of matrix coefficients for the jth linear constraint.
478 //
479 //
480 // Note that this alone does not prove unboundedness, you also need a feasible
481 // point. This is a certificate of dual infeasibility for LPs, see
482 // go/mathopt-dual#dual-inf-cert.
483 //
484 // For details, see go/mathopt-solutions#primal-ray.
486  absl::flat_hash_map<VariableId, double> variable_values;
487 };
488 
489 // A solution to the dual of the problem modeled in IndexedModel. Applies only
490 // when the problem has a dual (e.g. LP).
491 //
492 // For details, see go/mathopt-dual#dual-solution.
493 // For an primal interpretation as objective-value/optimality certificates see:
494 // go/mathopt-solutions#opt-certificate
496  absl::flat_hash_map<LinearConstraintId, double> dual_values;
497  absl::flat_hash_map<VariableId, double> reduced_costs;
499 };
500 
501 // A direction of improving objective value that maintains feasibility for the
502 // dual problem. Applies only when the problem has a dual (e.g. LP).
503 //
504 // Note that this alone does not prove dual unboundedness, you also need a dual
505 // feasible point.
506 //
507 // Also, a certificate of primal infeasibility.
508 //
509 // For details, see
510 // go/mathopt-dual#dual-ray
511 // go/mathopt-solutions#primal-inf-cert
513  absl::flat_hash_map<LinearConstraintId, double> dual_values;
514  absl::flat_hash_map<VariableId, double> reduced_costs;
515 };
516 
517 // A basis for a solution of the problem modeled in IndexedModel. Applies only
518 // when the problem is an LP.
519 //
520 // For details, see go/mathopt-basis#basis.
521 // TODO(b/171883688): consider improving consistency for matchers in
522 // solver_matchers.h/cc (e.g. removing PrimalDualPair from that file)
523 struct IndexedBasis {
524  absl::flat_hash_map<LinearConstraintId, BasisStatus> constraint_status;
525  absl::flat_hash_map<VariableId, BasisStatus> variable_status;
526 };
527 
528 // The solution (or potentially multiple solutions) to an LP or MIP. For LP,
529 // if the problem is solved to completion (i.e. we don't have an error or hit a
530 // limit), then at least one of these should be populated.
532  std::vector<IndexedPrimalSolution> primal_solutions;
533  std::vector<IndexedPrimalRay> primal_rays;
534  std::vector<IndexedDualSolution> dual_solutions;
535  std::vector<IndexedDualRay> dual_rays;
536  std::vector<IndexedBasis> basis;
537 };
538 
540  const SolveResultProto& solve_result);
541 
544 // Inlined function implementations
547 
549 // Variables
551 
552 VariableId IndexedModel::AddVariable(absl::string_view name) {
553  return AddVariable(-std::numeric_limits<double>::infinity(),
554  std::numeric_limits<double>::infinity(), false, name);
555 }
556 
557 double IndexedModel::variable_lower_bound(const VariableId id) const {
558  return variables_.at(id).lower_bound;
559 }
560 
561 double IndexedModel::variable_upper_bound(const VariableId id) const {
562  return variables_.at(id).upper_bound;
563 }
564 
565 bool IndexedModel::is_variable_integer(VariableId id) const {
566  return variables_.at(id).is_integer;
567 }
568 
569 const std::string& IndexedModel::variable_name(const VariableId id) const {
570  return variables_.at(id).name;
571 }
572 
573 template <typename T>
574 void IndexedModel::set_variable_property(
575  const VariableId id, const T value, T VariableData::*const field,
576  absl::flat_hash_set<VariableId>& dirty_set) {
577  VariableData& var_data = variables_.at(id);
578  if (var_data.*field != value) {
579  var_data.*field = value;
580  if (id < variables_checkpoint_) {
581  dirty_set.insert(id);
582  }
583  }
584 }
585 
586 void IndexedModel::set_variable_lower_bound(const VariableId id,
587  const double lower_bound) {
588  set_variable_property(id, lower_bound, &VariableData::lower_bound,
589  dirty_variable_lower_bounds_);
590 }
591 
592 void IndexedModel::set_variable_upper_bound(const VariableId id,
593  const double upper_bound) {
594  set_variable_property(id, upper_bound, &VariableData::upper_bound,
595  dirty_variable_upper_bounds_);
596 }
597 
598 void IndexedModel::set_variable_is_integer(const VariableId id,
599  const bool is_integer) {
600  set_variable_property(id, is_integer, &VariableData::is_integer,
601  dirty_variable_is_integer_);
602 }
603 
605  set_variable_is_integer(id, true);
606 }
607 
609  set_variable_is_integer(id, false);
610 }
611 
612 int IndexedModel::num_variables() const { return variables_.size(); }
613 
614 VariableId IndexedModel::next_variable_id() const { return next_variable_id_; }
615 
616 bool IndexedModel::has_variable(const VariableId id) const {
617  return variables_.contains(id);
618 }
619 
621 // Linear Constraints
623 
624 LinearConstraintId IndexedModel::AddLinearConstraint(absl::string_view name) {
625  return AddLinearConstraint(-std::numeric_limits<double>::infinity(),
626  std::numeric_limits<double>::infinity(), name);
627 }
628 
630  const LinearConstraintId id) const {
631  return linear_constraints_.at(id).lower_bound;
632 }
633 
635  const LinearConstraintId id) const {
636  return linear_constraints_.at(id).upper_bound;
637 }
638 
640  const LinearConstraintId id) const {
641  return linear_constraints_.at(id).name;
642 }
643 
644 void IndexedModel::set_linear_constraint_property(
645  const LinearConstraintId id, const double value,
646  double LinearConstraintData::*const field,
647  absl::flat_hash_set<LinearConstraintId>& dirty_set) {
648  LinearConstraintData& lin_con_data = linear_constraints_.at(id);
649  if (lin_con_data.*field != value) {
650  lin_con_data.*field = value;
651  if (id < linear_constraints_checkpoint_) {
652  dirty_set.insert(id);
653  }
654  }
655 }
656 
658  const LinearConstraintId id, const double lower_bound) {
659  set_linear_constraint_property(id, lower_bound,
661  dirty_linear_constraint_lower_bounds_);
662 }
663 
665  const LinearConstraintId id, const double upper_bound) {
666  set_linear_constraint_property(id, upper_bound,
668  dirty_linear_constraint_upper_bounds_);
669 }
670 
672  return linear_constraints_.size();
673 }
674 
675 LinearConstraintId IndexedModel::next_linear_constraint_id() const {
676  return next_linear_constraint_id_;
677 }
678 
679 bool IndexedModel::has_linear_constraint(const LinearConstraintId id) const {
680  return linear_constraints_.contains(id);
681 }
682 
684 // Linear Constraint Matrix
686 
688  LinearConstraintId constraint, VariableId variable) const {
689  return gtl::FindWithDefault(linear_constraint_matrix_,
690  {constraint, variable});
691 }
692 
694  LinearConstraintId constraint, VariableId variable) const {
695  return linear_constraint_matrix_.contains({constraint, variable});
696 }
697 
699  LinearConstraintId constraint, VariableId variable, double value) {
700  bool was_updated = false;
701  if (value == 0.0) {
702  if (linear_constraint_matrix_.erase({constraint, variable}) > 0) {
703  was_updated = true;
704  if (!lazy_matrix_columns_.empty()) {
705  lazy_matrix_columns_.at(variable).erase(constraint);
706  }
707  if (!lazy_matrix_rows_.empty()) {
708  lazy_matrix_rows_.at(constraint).erase(variable);
709  }
710  }
711  } else {
712  const auto [iterator, inserted] =
713  linear_constraint_matrix_.try_emplace({constraint, variable}, value);
714  if (inserted) {
715  was_updated = true;
716  } else if (iterator->second != value) {
717  iterator->second = value;
718  was_updated = true;
719  }
720  if (!lazy_matrix_columns_.empty()) {
721  lazy_matrix_columns_.at(variable).insert(constraint);
722  }
723  if (!lazy_matrix_rows_.empty()) {
724  lazy_matrix_rows_.at(constraint).insert(variable);
725  }
726  }
727  if (was_updated && constraint < linear_constraints_checkpoint_ &&
728  variable < variables_checkpoint_) {
729  dirty_linear_constraint_matrix_keys_.emplace(constraint, variable);
730  }
731 }
732 
733 const absl::flat_hash_map<std::pair<LinearConstraintId, VariableId>, double>&
735  return linear_constraint_matrix_;
736 }
737 
738 const absl::flat_hash_set<VariableId>&
739 IndexedModel::variables_in_linear_constraint(LinearConstraintId constraint) {
740  EnsureLazyMatrixRows();
741  return lazy_matrix_rows_.at(constraint);
742 }
743 
744 const absl::flat_hash_set<LinearConstraintId>&
746  EnsureLazyMatrixColumns();
747  return lazy_matrix_columns_.at(variable);
748 }
749 
751 // Objective
753 
754 bool IndexedModel::is_maximize() const { return is_maximize_; }
755 
756 double IndexedModel::objective_offset() const { return objective_offset_; }
757 
758 double IndexedModel::linear_objective_coefficient(VariableId variable) const {
759  return gtl::FindWithDefault(linear_objective_, variable);
760 }
761 
763  VariableId variable) const {
764  return linear_objective_.contains(variable);
765 }
766 
767 void IndexedModel::set_is_maximize(bool is_maximize) {
768  if (is_maximize_ != is_maximize) {
769  dirty_objective_direction_ = true;
770  is_maximize_ = is_maximize;
771  }
772 }
773 
775 
777 
779  if (value != objective_offset_) {
780  dirty_objective_offset_ = true;
781  objective_offset_ = value;
782  }
783 }
784 
786  double value) {
787  bool was_updated = false;
788  if (value == 0.0) {
789  if (linear_objective_.erase(variable) > 0) {
790  was_updated = true;
791  }
792  } else {
793  const auto [iterator, inserted] =
794  linear_objective_.try_emplace(variable, value);
795  if (inserted) {
796  was_updated = true;
797  } else if (iterator->second != value) {
798  iterator->second = value;
799  was_updated = true;
800  }
801  }
802  if (was_updated && variable < variables_checkpoint_) {
803  dirty_linear_objective_coefficients_.insert(variable);
804  }
805 }
806 
809  while (!linear_objective_.empty()) {
810  set_linear_objective_coefficient(linear_objective_.begin()->first, 0.0);
811  }
812 }
813 
814 const absl::flat_hash_map<VariableId, double>& IndexedModel::linear_objective()
815  const {
816  return linear_objective_;
817 }
818 
819 } // namespace math_opt
820 } // namespace operations_research
821 
822 #endif // OR_TOOLS_MATH_OPT_INDEXED_MODEL_H_
IndexedModel(absl::string_view name="")
LinearConstraintId next_linear_constraint_id() const
std::vector< LinearConstraintId > linear_constraints() const
std::vector< VariableId > SortedVariables() const
double linear_objective_coefficient(VariableId variable) const
std::vector< VariableId > SortedLinearObjectiveNonzeroVariables() const
double linear_constraint_coefficient(LinearConstraintId constraint, VariableId variable) const
void DeleteLinearConstraint(LinearConstraintId id)
void set_linear_objective_coefficient(VariableId variable, double value)
const absl::flat_hash_map< std::pair< LinearConstraintId, VariableId >, double > & linear_constraint_matrix() const
std::vector< VariableId > variables() const
double linear_constraint_lower_bound(LinearConstraintId id) const
void set_linear_constraint_coefficient(LinearConstraintId constraint, VariableId variable, double value)
VariableId AddVariable(absl::string_view name="")
void set_variable_upper_bound(VariableId id, double upper_bound)
void set_variable_is_integer(VariableId id, bool is_integer)
bool has_linear_constraint(LinearConstraintId id) const
const std::string & variable_name(VariableId id) const
const absl::flat_hash_set< VariableId > & variables_in_linear_constraint(LinearConstraintId constraint)
void set_linear_constraint_upper_bound(LinearConstraintId id, double upper_bound)
void set_linear_constraint_lower_bound(LinearConstraintId id, double lower_bound)
double linear_constraint_upper_bound(LinearConstraintId id) const
double variable_lower_bound(VariableId id) const
const absl::flat_hash_set< LinearConstraintId > & linear_constraints_with_variable(VariableId variable)
bool is_linear_constraint_coefficient_nonzero(LinearConstraintId constraint, VariableId variable) const
bool is_variable_integer(VariableId id) const
const std::string & linear_constraint_name(LinearConstraintId id) const
LinearConstraintId AddLinearConstraint(absl::string_view name="")
const absl::flat_hash_map< VariableId, double > & linear_objective() const
std::vector< LinearConstraintId > SortedLinearConstraints() const
bool is_linear_objective_coefficient_nonzero(VariableId variable) const
double variable_upper_bound(VariableId id) const
void set_variable_lower_bound(VariableId id, double lower_bound)
const std::string name
int64_t value
double upper_bound
double lower_bound
const Collection::value_type::second_type & FindWithDefault(const Collection &collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
Definition: map_util.h:29
DEFINE_INT_TYPE(VariableId, int64_t)
IndexedSolutions IndexedSolutionsFromProto(const SolveResultProto &solve_result)
Collection of objects used to extend the Constraint Solver library.
absl::flat_hash_map< VariableId, BasisStatus > variable_status
absl::flat_hash_map< LinearConstraintId, BasisStatus > constraint_status
absl::flat_hash_map< VariableId, double > reduced_costs
absl::flat_hash_map< LinearConstraintId, double > dual_values
absl::flat_hash_map< VariableId, double > reduced_costs
absl::flat_hash_map< LinearConstraintId, double > dual_values
absl::flat_hash_map< VariableId, double > variable_values
absl::flat_hash_map< VariableId, double > variable_values
std::vector< IndexedDualSolution > dual_solutions
std::vector< IndexedPrimalSolution > primal_solutions
std::vector< IndexedPrimalRay > primal_rays