OR-Tools  9.6
model_storage.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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_MATH_OPT_STORAGE_MODEL_STORAGE_H_
15 #define OR_TOOLS_MATH_OPT_STORAGE_MODEL_STORAGE_H_
16 
17 #include <cstdint>
18 #include <limits>
19 #include <memory>
20 #include <optional>
21 #include <string>
22 #include <tuple>
23 #include <utility>
24 #include <vector>
25 
26 #include "absl/container/flat_hash_map.h"
27 #include "absl/container/flat_hash_set.h"
28 #include "absl/meta/type_traits.h"
29 #include "absl/status/status.h"
30 #include "absl/status/statusor.h"
31 #include "absl/strings/string_view.h"
32 #include "absl/log/check.h"
33 #include "ortools/base/map_util.h"
35 #include "ortools/math_opt/constraints/indicator/storage.h" // IWYU pragma: export
36 #include "ortools/math_opt/constraints/quadratic/storage.h" // IWYU pragma: export
37 #include "ortools/math_opt/constraints/sos/storage.h" // IWYU pragma: export
38 #include "ortools/math_opt/model.pb.h"
39 #include "ortools/math_opt/model_update.pb.h"
40 #include "ortools/math_opt/sparse_containers.pb.h"
41 #include "ortools/math_opt/storage/atomic_constraint_storage.h" // IWYU pragma: export
48 
49 namespace operations_research {
50 namespace math_opt {
51 
52 // An index based C++ API for building & storing optimization problems.
53 //
54 // Note that this API should usually not be used by C++ users that should prefer
55 // the math_opt/cpp/model.h API.
56 //
57 // It supports the efficient creation and modification of an optimization model,
58 // and the export of ModelProto and ModelUpdateProto protos.
59 //
60 // All methods run in amortized O(1) (as amortized over calls to that exact
61 // function) unless otherwise specified.
62 //
63 // Models problems of the form:
64 // min sum_{j in J} c_j * x_j + d
65 // s.t. lb^c_i <= sum_{j in J} A_ij * x_j <= ub^c_i for all i in I,
66 // lb^v_j <= x_j <= ub^v_j for all j in J,
67 // x_j integer for all j in Z,
68 // where above:
69 // * I: the set of linear constraints,
70 // * J: the set of variables,
71 // * Z: a subset of J, the integer variables,
72 // * x: the decision variables (indexed by J),
73 // * c: the linear objective, one double per variable,
74 // * d: the objective offset, a double scalar,
75 // * lb^c: the constraint lower bounds, one double per linear constraint,
76 // * ub^c: the constraint upper bounds, one double per linear constraint,
77 // * lb^v: the variable lower bounds, one double per variable,
78 // * ub^v: the variable upper bounds, one double per variable,
79 // * A: the linear constraint matrix, a double per variable/constraint pair.
80 //
81 // The min in the objective can also be changed to a max.
82 //
83 // A simple example:
84 //
85 // Model the problem:
86 // max 2.0 * x + y
87 // s.t. x + y <= 1.5
88 // x in {0.0, 1.0}
89 // 0 <= y <= 2.5
90 //
91 // using ::operations_research::math_opt::ModelStorage;
92 // using ::operations_research::math_opt::VariableId;
93 // using ::operations_research::math_opt::LinearConstraintId;
94 // using ::operations_research::math_opt::ModelProto;
95 // using ::operations_research::math_opt::ModelProtoUpdate;
96 //
97 // ModelStorage model("my_model");
98 // const VariableId x = model.AddVariable(0.0, 1.0, true, "x");
99 // const VariableId y = model.AddVariable(0.0, 2.5, false, "y");
100 // const LinearConstraintId c = model.AddLinearConstraint(
101 // -std::numeric_limits<double>::infinity, 1.5, "c");
102 // model.set_linear_constraint_coefficient(x, c, 1.0);
103 // model.set_linear_constraint_coefficient(y, c, 1.0);
104 // model.set_linear_objective_coefficient(x, 2.0);
105 // model.set_linear_objective_coefficient(y, 1.0);
106 // model.set_maximize();
107 //
108 // Now, export to a proto describing the model:
109 //
110 // const ModelProto model_proto = model.ExportModel();
111 //
112 // Modify the problem and get a model update proto:
113 //
114 // const UpdateTrackerId update_tracker = model.NewUpdateTracker();
115 // c.set_upper_bound(2.0);
116 // const std::optional<ModelUpdateProto> update_proto =
117 // model.ExportModelUpdate(update_tracker);
118 // model.AdvanceCheckpoint(update_tracker);
119 //
120 // Reading and writing model properties:
121 //
122 // Properties of the model (e.g. variable/constraint bounds) can be written
123 // and read in amortized O(1) time. Deleting a variable will take time
124 // O(#constraints containing the variable), and likewise deleting a constraint
125 // will take time O(#variables in the constraint). The constraint matrix is
126 // stored as hash map where the key is a {LinearConstraintId, VariableId}
127 // pair and the value is the coefficient. The nonzeros of the matrix are
128 // additionally stored by row and by column.
129 //
130 // Exporting the Model proto:
131 //
132 // The Model proto is an equivalent representation to ModelStorage. It has a
133 // smaller memory footprint and optimized for storage/transport, rather than
134 // efficient modification. It is also the format consumed by solvers in this
135 // library. The Model proto can be generated by calling
136 // ModelStorage::ExportModel().
137 //
138 // Incrementalism, the ModelUpdate proto, and Checkpoints:
139 //
140 // To update an existing model as specified by a Model proto, solvers consume a
141 // ModelUpdate proto, which describes the changes to a model (e.g. new variables
142 // or a change in a variable bound). ModelStorage::NewUpdateTracker() tracks the
143 // changes made and produces a ModelUpdate proto describing these changes with
144 // the method ModelStorage::ExportModelUpdate(). The changes returned will be
145 // the modifications since the previous call to
146 // ModelStorage::AdvanceCheckpoint(). Note that, for newly initialized models,
147 // before the first checkpoint, there is no additional memory overhead from
148 // tracking changes. See
149 // docs/ortools/math_opt/docs/model_building_complexity.md
150 // for details.
151 //
152 // On bad input:
153 //
154 // Using a bad variable id or constraint id (an id not in the current model,
155 // which includes ids that have been deleted) on any method will result in an
156 // immediate failure (either a CHECK failure or an exception, which is an
157 // implementation detail you should not rely on). We make no attempt to say if a
158 // model is invalid (e.g. a variable lower bound is infinite, exceeds an upper
159 // bound, or is NaN). The exported models are validated instead, see
160 // model_validator.h.
162  public:
163  // Returns a storage from the input proto. Returns a failure status if the
164  // input proto is invalid.
165  //
166  // Variable/constraint names can be repeated in the input proto but will be
167  // considered invalid when solving.
168  //
169  // See ApplyUpdateProto() for dealing with subsequent updates.
170  static absl::StatusOr<std::unique_ptr<ModelStorage>> FromModelProto(
171  const ModelProto& model_proto);
172 
173  // Creates an empty minimization problem.
174  explicit ModelStorage(absl::string_view name = "") : name_(name) {}
175 
176  ModelStorage(const ModelStorage&) = delete;
178 
179  // Returns a clone of the model, optionally changing model's name.
180  //
181  // The variables and constraints have the same ids. The clone will also not
182  // reused any id of variable/constraint that was deleted in the original.
183  //
184  // Note that the returned model does not have any update tracker.
185  std::unique_ptr<ModelStorage> Clone(
186  std::optional<absl::string_view> new_name = std::nullopt) const;
187 
188  inline const std::string& name() const { return name_; }
189 
191  // Variables
193 
194  // Adds a continuous unbounded variable to the model and returns its id.
195  //
196  // See AddVariable(double, double, bool, absl::string_view) for details.
197  inline VariableId AddVariable(absl::string_view name = "");
198 
199  // Adds a variable to the model and returns its id.
200  //
201  // The returned ids begin at zero and increase by one with each call to
202  // AddVariable. Deleted ids are NOT reused. If no variables are deleted,
203  // the ids in the model will be consecutive.
204  VariableId AddVariable(double lower_bound, double upper_bound,
205  bool is_integer, absl::string_view name = "");
206 
207  inline double variable_lower_bound(VariableId id) const;
208  inline double variable_upper_bound(VariableId id) const;
209  inline bool is_variable_integer(VariableId id) const;
210  inline const std::string& variable_name(VariableId id) const;
211 
212  inline void set_variable_lower_bound(VariableId id, double lower_bound);
213  inline void set_variable_upper_bound(VariableId id, double upper_bound);
214  inline void set_variable_is_integer(VariableId id, bool is_integer);
215  inline void set_variable_as_integer(VariableId id);
216  inline void set_variable_as_continuous(VariableId id);
217 
218  // Removes a variable from the model.
219  //
220  // It is an error to use a deleted variable id as input to any subsequent
221  // function calls on the model. Runs in O(#constraints containing the
222  // variable).
223  void DeleteVariable(VariableId id);
224 
225  // The number of variables in the model.
226  //
227  // Equal to the number of variables created minus the number of variables
228  // deleted.
229  inline int num_variables() const;
230 
231  // The returned id of the next call to AddVariable.
232  //
233  // Equal to the number of variables created.
234  inline VariableId next_variable_id() const;
235 
236  // Sets the next variable id to be the maximum of next_variable_id() and id.
237  inline void ensure_next_variable_id_at_least(VariableId id);
238 
239  // Returns true if this id has been created and not yet deleted.
240  inline bool has_variable(VariableId id) const;
241 
242  // The VariableIds in use (not deleted), order not defined.
243  std::vector<VariableId> variables() const;
244 
245  // Returns a sorted vector of all existing (not deleted) variables in the
246  // model.
247  //
248  // Runs in O(n log(n)), where n is the number of variables returned.
249  std::vector<VariableId> SortedVariables() const;
250 
252  // Linear Constraints
254 
255  // Adds a linear constraint to the model with a lower bound of -inf and an
256  // upper bound of +inf and returns its id.
257  //
258  // See AddLinearConstraint(double, double, absl::string_view) for details.
259  inline LinearConstraintId AddLinearConstraint(absl::string_view name = "");
260 
261  // Adds a linear constraint to the model returns its id.
262  //
263  // The returned ids begin at zero and increase by one with each call to
264  // AddLinearConstraint. Deleted ids are NOT reused. If no linear
265  // constraints are deleted, the ids in the model will be consecutive.
266  LinearConstraintId AddLinearConstraint(double lower_bound, double upper_bound,
267  absl::string_view name = "");
268 
269  inline double linear_constraint_lower_bound(LinearConstraintId id) const;
270  inline double linear_constraint_upper_bound(LinearConstraintId id) const;
271  inline const std::string& linear_constraint_name(LinearConstraintId id) const;
272 
273  inline void set_linear_constraint_lower_bound(LinearConstraintId id,
274  double lower_bound);
275  inline void set_linear_constraint_upper_bound(LinearConstraintId id,
276  double upper_bound);
277 
278  // Removes a linear constraint from the model.
279  //
280  // It is an error to use a deleted linear constraint id as input to any
281  // subsequent function calls on the model. Runs in O(#variables in the linear
282  // constraint).
283  void DeleteLinearConstraint(LinearConstraintId id);
284 
285  // The number of linear constraints in the model.
286  //
287  // Equal to the number of linear constraints created minus the number of
288  // linear constraints deleted.
289  inline int num_linear_constraints() const;
290 
291  // The returned id of the next call to AddLinearConstraint.
292  //
293  // Equal to the number of linear constraints created.
294  inline LinearConstraintId next_linear_constraint_id() const;
295 
296  // Sets the next linear constraint id to be the maximum of
297  // next_linear_constraint_id() and id.
298  inline void ensure_next_linear_constraint_id_at_least(LinearConstraintId id);
299 
300  // Returns true if this id has been created and not yet deleted.
301  inline bool has_linear_constraint(LinearConstraintId id) const;
302 
303  // The LinearConstraintsIds in use (not deleted), order not defined.
304  std::vector<LinearConstraintId> LinearConstraints() const;
305 
306  // Returns a sorted vector of all existing (not deleted) linear constraints in
307  // the model.
308  //
309  // Runs in O(n log(n)), where n is the number of linear constraints returned.
310  std::vector<LinearConstraintId> SortedLinearConstraints() const;
311 
313  // Linear constraint matrix
315 
316  // Returns 0.0 if the entry is not in matrix.
317  inline double linear_constraint_coefficient(LinearConstraintId constraint,
318  VariableId variable) const;
320  LinearConstraintId constraint, VariableId variable) const;
321 
322  // Setting a value to 0.0 will delete the {constraint, variable} pair from the
323  // underlying sparse matrix representation (and has no effect if the pair is
324  // not present).
325  inline void set_linear_constraint_coefficient(LinearConstraintId constraint,
326  VariableId variable,
327  double value);
328 
329  // The {linear constraint, variable, coefficient} tuples with nonzero linear
330  // constraint matrix coefficients.
331  inline std::vector<std::tuple<LinearConstraintId, VariableId, double>>
332  linear_constraint_matrix() const;
333 
334  // Returns the variables with nonzero coefficients in a linear constraint.
335  inline std::vector<VariableId> variables_in_linear_constraint(
336  LinearConstraintId constraint) const;
337 
338  // Returns the linear constraints with nonzero coefficients on a variable.
339  inline std::vector<LinearConstraintId> linear_constraints_with_variable(
340  VariableId variable) const;
341 
343  // Objective
345 
346  inline bool is_maximize() const;
347  inline double objective_offset() const;
348  // Returns 0.0 if this variable has no linear objective coefficient.
349  inline double linear_objective_coefficient(VariableId variable) const;
350  // The ordering of the input variables does not matter.
351  inline double quadratic_objective_coefficient(
352  VariableId first_variable, VariableId second_variable) const;
354  VariableId variable) const;
355  // The ordering of the input variables does not matter.
357  VariableId first_variable, VariableId second_variable) const;
358 
359  inline void set_is_maximize(bool is_maximize);
360  inline void set_maximize();
361  inline void set_minimize();
362  inline void set_objective_offset(double value);
363 
364  // Setting a value to 0.0 will delete the variable from the underlying sparse
365  // representation (and has no effect if the variable is not present).
366  inline void set_linear_objective_coefficient(VariableId variable,
367  double value);
368  // Setting a value to 0.0 will delete the variable pair from the underlying
369  // sparse representation (and has no effect if the pair is not present).
370  // The ordering of the input variables does not matter.
371  inline void set_quadratic_objective_coefficient(VariableId first_variable,
372  VariableId second_variable,
373  double value);
374 
375  // Equivalent to calling set_linear_objective_coefficient(v, 0.0) for every
376  // variable with nonzero objective coefficient.
377  //
378  // Runs in O(# nonzero linear/quadratic objective terms).
379  inline void clear_objective();
380 
381  // The variables with nonzero linear objective coefficients.
382  inline const absl::flat_hash_map<VariableId, double>& linear_objective()
383  const;
384 
385  inline int64_t num_quadratic_objective_terms() const;
386 
387  // The variable pairs with nonzero quadratic objective coefficients. The keys
388  // are ordered such that .first <= .second. All values are nonempty.
389  //
390  // TODO(b/233630053) do no allocate the result, expose an iterator API.
391  inline std::vector<std::tuple<VariableId, VariableId, double>>
393 
395  // Atomic Constraints
396  //
397  // These methods do not directly require template specializations to add
398  // support for new constraint families; this should be handled automatically
399  // upon adding a specialization for `AtomicConstraintTraits`.
401 
402  // Adds an atomic constraint to the model and returns its id.
403  //
404  // The returned ids begin at zero and increase by one with each call to
405  // `AddAtomicConstraint<ConstraintData>`. Deleted ids are NOT reused. Callers
406  // may use `ensure_next_constraint_id_at_least<ConstraintData>` to configure
407  // custom indices.
408  template <typename ConstraintData>
409  inline typename ConstraintData::IdType AddAtomicConstraint(
410  ConstraintData data);
411 
412  // Removes an atomic constraint from the model.
413  //
414  // It is an error to use a deleted constraint id as input to any subsequent
415  // function calls on the model. Runs in O(#variables in the constraint).
416  template <typename IdType>
417  inline void DeleteAtomicConstraint(IdType id);
418 
419  // Accesses the data object that fully represents a single atomic constraint.
420  template <typename IdType>
422  constraint_data(IdType id) const;
423 
424  // Returns the number of atomic constraints in the model of the family
425  // corresponding to `ConstraintData`.
426  //
427  // Equal to the number of such constraints created minus the number of such
428  // constraints deleted.
429  template <typename IdType>
430  inline int64_t num_constraints() const;
431 
432  // Returns the smallest valid ID for a new atomic constraint of the family
433  // corresponding to `ConstraintData`.
434  template <typename IdType>
435  inline IdType next_constraint_id() const;
436 
437  // Sets the next atomic constraint id of the family corresponding to
438  // `ConstraintData` to be the maximum of
439  // `next_constraint_id<ConstraintData>()` and `id`.
440  template <typename IdType>
441  inline void ensure_next_constraint_id_at_least(IdType id);
442 
443  // Returns true if this id has been created and not yet deleted.
444  template <typename IdType>
445  inline bool has_constraint(IdType id) const;
446 
447  // Returns the constraint IDs in use (not deleted); order is not defined.
448  template <typename IdType>
449  std::vector<IdType> Constraints() const;
450 
451  // Returns a sorted vector of all existing (not deleted) atomic constraints
452  // in the model of the family corresponding to `ConstraintData`.
453  //
454  // Runs in O(n log(n)), where n is the number of constraints returned.
455  template <typename IdType>
456  std::vector<IdType> SortedConstraints() const;
457 
458  // Returns the constraint in the given family in which the variable appears
459  // structurally (i.e., has a coefficient, possibly zero). Order is not
460  // defined.
461  template <typename IdType>
462  inline std::vector<IdType> ConstraintsWithVariable(
463  VariableId variable_id) const;
464 
465  // Returns the variables appearing in the constraint. Order is not defined.
466  template <typename IdType>
467  inline std::vector<VariableId> VariablesInConstraint(IdType id) const;
468 
470  // Export
472 
473  // Returns a proto representation of the optimization model.
474  //
475  // See FromModelProto() to build a ModelStorage from a proto.
476  ModelProto ExportModel() const;
477 
478  // Creates a tracker that can be used to generate a ModelUpdateProto with the
479  // updates that happened since the last checkpoint. The tracker initial
480  // checkpoint corresponds to the current state of the model.
481  //
482  // Thread-safety: this method must not be used while modifying the
483  // ModelStorage. The user is expected to use proper synchronization primitive
484  // to serialize changes to the model and trackers creations. That said
485  // multiple trackers can be created concurrently.
486  //
487  // For each update tracker we define a checkpoint that is the starting point
488  // used to compute the ModelUpdateProto.
489  //
490  // Example:
491  // ModelStorage model;
492  // ...
493  // ASSIGN_OR_RETURN(const auto solver,
494  // Solver::New(solver_type, model.ExportModel(),
495  // /*initializer=*/{}));
496  // const UpdateTrackerId update_tracker = model.NewUpdatesTracker();
497  //
498  // ASSIGN_OR_RETURN(const auto result_1,
499  // solver->Solve(/*parameters=*/{});
500  //
501  // model.AddVariable(0.0, 1.0, true, "y");
502  // model.set_maximize(true);
503  //
504  // const std::optional<ModelUpdateProto> update_proto =
505  // model.ExportModelUpdate(update_tracker);
506  // model.AdvanceCheckpoint(update_tracker);
507  //
508  // if (update_proto) {
509  // ASSIGN_OR_RETURN(const bool updated, solver->Update(*update_proto));
510  // if (!updated) {
511  // // The update is not supported by the solver, we create a new one.
512  // ASSIGN_OR_RETURN(const auto new_model_proto, model.ExportModel());
513  // ASSIGN_OR_RETURN(solver,
514  // Solver::New(solver_type, new_model_proto,
515  // /*initializer=*/{}));
516  // }
517  // }
518  // ASSIGN_OR_RETURN(const auto result_2,
519  // solver->Solve(/*parameters=*/{});
520  //
521  UpdateTrackerId NewUpdateTracker();
522 
523  // Deletes the input tracker.
524  //
525  // It must not be used anymore after its destruction. It can be deleted once,
526  // trying to delete it a second time or use it will raise an assertion
527  // (CHECK).
528  //
529  // The update trackers are automatically deleted when the ModelStorage is
530  // destroyed. Calling this function is thus only useful for performance
531  // reasons, to ensure the ModelStorage does not keep data for update trackers
532  // that are not needed anymore.
533  //
534  // Thread-safety: this method can be called at any time, even during the
535  // creation of other trackers or during model modification. It must not be
536  // called concurrently with ExportModelUpdate() or AdvanceCheckpoint() though.
537  void DeleteUpdateTracker(UpdateTrackerId update_tracker);
538 
539  // Returns a proto representation of the changes to the model since the most
540  // recent checkpoint (i.e. last time AdvanceCheckpoint() was called); nullopt
541  // if the update would have been empty.
542  //
543  // Thread-safety: this method must not be used while modifying the
544  // ModelStorage or after calling DeleteUpdateTracker(). The user is expected
545  // to use proper synchronization primitive to serialize changes to the model
546  // and the use of this method.
547  //
548  // It can be called concurrently for different update trackers though.
549  std::optional<ModelUpdateProto> ExportModelUpdate(
550  UpdateTrackerId update_tracker) const;
551 
552  // Uses the current model state as the starting point to calculate the
553  // ModelUpdateProto next time ExportModelUpdate() is called.
554  //
555  // Thread-safety: this method must not be used while modifying the
556  // ModelStorage or after calling DeleteUpdateTracker(). The user is expected
557  // to use proper synchronization primitive to serialize changes to the model
558  // and the use of this method.
559  //
560  // It can be called concurrently for different update trackers though.
561  void AdvanceCheckpoint(UpdateTrackerId update_tracker);
562 
563  // Apply the provided update to this model. Returns a failure if the update is
564  // not valid.
565  //
566  // As with FromModelProto(), duplicated names are ignored.
567  //
568  // It takes O(num_variables + num_constraints) extra memory and execution to
569  // apply the update (due to the need to build a ModelSummary). So even a small
570  // update will have some cost.
571  absl::Status ApplyUpdateProto(const ModelUpdateProto& update_proto);
572 
573  private:
574  struct UpdateTrackerData {
575  UpdateTrackerData(
576  const VariableStorage& variables,
577  const LinearConstraintStorage& linear_constraints,
579  quadratic_constraints,
580  const AtomicConstraintStorage<Sos1ConstraintData>& sos1_constraints,
581  const AtomicConstraintStorage<Sos2ConstraintData>& sos2_constraints,
583  indicator_constraints)
584  : dirty_variables(variables),
585  dirty_objective(variables.next_id()),
586  dirty_linear_constraints(linear_constraints,
587  dirty_variables.checkpoint),
588  dirty_quadratic_constraints(quadratic_constraints),
589  dirty_sos1_constraints(sos1_constraints),
590  dirty_sos2_constraints(sos2_constraints),
591  dirty_indicator_constraints(indicator_constraints) {}
592 
593  // Returns a proto representation of the changes to the model since the most
594  // recent call to SharedCheckpoint() or nullopt if no changes happened.
595  //
596  // Thread-safety: this method is threadsafe.
597  std::optional<ModelUpdateProto> ExportModelUpdate(
598  const ModelStorage& storage) const;
599 
600  // Use the current model state as the starting point to calculate the
601  // ModelUpdateProto next time ExportSharedModelUpdate() is called.
602  void AdvanceCheckpoint(const ModelStorage& storage);
603 
604  // Implementers of new constraint types should provide a specialization that
605  // returns the address of the appropriate `UpdateTrackerData` field.
606  template <typename ConstraintData>
607  static constexpr typename AtomicConstraintStorage<ConstraintData>::Diff
608  UpdateTrackerData::*
609  AtomicConstraintDirtyFieldPtr();
610 
611  // Update information
612  //
613  // Implicitly, all data for variables and constraints added after the last
614  // checkpoint are considered "new" and will NOT be stored in the "dirty"
615  // data structures below.
616 
617  VariableStorage::Diff dirty_variables;
618  ObjectiveStorage::Diff dirty_objective;
619  LinearConstraintStorage::Diff dirty_linear_constraints;
620  AtomicConstraintStorage<QuadraticConstraintData>::Diff
621  dirty_quadratic_constraints;
622  AtomicConstraintStorage<Sos1ConstraintData>::Diff dirty_sos1_constraints;
623  AtomicConstraintStorage<Sos2ConstraintData>::Diff dirty_sos2_constraints;
624  AtomicConstraintStorage<IndicatorConstraintData>::Diff
625  dirty_indicator_constraints;
626  };
627 
628  auto UpdateAndGetVariableDiffs() {
629  return MakeUpdateDataFieldRange<&UpdateTrackerData::dirty_variables>(
630  update_trackers_.GetUpdatedTrackers());
631  }
632 
633  auto UpdateAndGetObjectiveDiffs() {
634  return MakeUpdateDataFieldRange<&UpdateTrackerData::dirty_objective>(
635  update_trackers_.GetUpdatedTrackers());
636  }
637 
638  auto UpdateAndGetLinearConstraintDiffs() {
640  &UpdateTrackerData::dirty_linear_constraints>(
641  update_trackers_.GetUpdatedTrackers());
642  }
643 
644  // Ids must be greater or equal to next_variable_id_.
645  void AddVariables(const VariablesProto& variables);
646 
647  // Ids must be greater or equal to next_linear_constraint_id_.
648  void AddLinearConstraints(const LinearConstraintsProto& linear_constraints);
649 
650  // Updates the objective linear coefficients. The coefficients of variables
651  // not in the input are kept as-is.
652  void UpdateLinearObjectiveCoefficients(
653  const SparseDoubleVectorProto& coefficients);
654 
655  // Updates the objective quadratic coefficients. The coefficients of the pairs
656  // of variables not in the input are kept as-is.
657  void UpdateQuadraticObjectiveCoefficients(
658  const SparseDoubleMatrixProto& coefficients);
659 
660  // Updates the linear constraints' coefficients. The coefficients of
661  // (constraint, variable) pairs not in the input are kept as-is.
662  void UpdateLinearConstraintCoefficients(
663  const SparseDoubleMatrixProto& coefficients);
664 
665  // Implementers of new constraint types should provide a specialization that
666  // returns a non-const reference to the appropriate `ModelStorage` field.
667  template <typename ConstraintData>
668  AtomicConstraintStorage<ConstraintData>& constraint_storage();
669 
670  // Implementers of new constraint types should provide a specialization that
671  // returns a const reference to the appropriate `ModelStorage` field.
672  template <typename ConstraintData>
673  const AtomicConstraintStorage<ConstraintData>& constraint_storage() const;
674 
675  std::string name_;
676 
677  VariableStorage variables_;
678  ObjectiveStorage objective_;
679  LinearConstraintStorage linear_constraints_;
680 
681  AtomicConstraintStorage<QuadraticConstraintData> quadratic_constraints_;
682  AtomicConstraintStorage<Sos1ConstraintData> sos1_constraints_;
683  AtomicConstraintStorage<Sos2ConstraintData> sos2_constraints_;
684  AtomicConstraintStorage<IndicatorConstraintData> indicator_constraints_;
685 
686  UpdateTrackers<UpdateTrackerData> update_trackers_;
687 };
688 
691 // Inlined function implementations
694 
696 // Variables
698 
699 VariableId ModelStorage::AddVariable(absl::string_view name) {
700  return AddVariable(-std::numeric_limits<double>::infinity(),
701  std::numeric_limits<double>::infinity(), false, name);
702 }
703 
704 double ModelStorage::variable_lower_bound(const VariableId id) const {
705  return variables_.lower_bound(id);
706 }
707 
708 double ModelStorage::variable_upper_bound(const VariableId id) const {
709  return variables_.upper_bound(id);
710 }
711 
712 bool ModelStorage::is_variable_integer(VariableId id) const {
713  return variables_.is_integer(id);
714 }
715 
716 const std::string& ModelStorage::variable_name(const VariableId id) const {
717  return variables_.name(id);
718 }
719 
720 void ModelStorage::set_variable_lower_bound(const VariableId id,
721  const double lower_bound) {
722  variables_.set_lower_bound(id, lower_bound, UpdateAndGetVariableDiffs());
723 }
724 
725 void ModelStorage::set_variable_upper_bound(const VariableId id,
726  const double upper_bound) {
727  variables_.set_upper_bound(id, upper_bound, UpdateAndGetVariableDiffs());
728 }
729 
730 void ModelStorage::set_variable_is_integer(const VariableId id,
731  const bool is_integer) {
732  variables_.set_integer(id, is_integer, UpdateAndGetVariableDiffs());
733 }
734 
736  set_variable_is_integer(id, true);
737 }
738 
740  set_variable_is_integer(id, false);
741 }
742 
743 int ModelStorage::num_variables() const { return variables_.size(); }
744 
745 VariableId ModelStorage::next_variable_id() const {
746  return variables_.next_id();
747 }
748 
750  variables_.ensure_next_id_at_least(id);
751 }
752 
753 bool ModelStorage::has_variable(const VariableId id) const {
754  return variables_.contains(id);
755 }
756 
758 // Linear Constraints
760 
761 LinearConstraintId ModelStorage::AddLinearConstraint(absl::string_view name) {
762  return AddLinearConstraint(-std::numeric_limits<double>::infinity(),
763  std::numeric_limits<double>::infinity(), name);
764 }
765 
767  const LinearConstraintId id) const {
768  return linear_constraints_.lower_bound(id);
769 }
770 
772  const LinearConstraintId id) const {
773  return linear_constraints_.upper_bound(id);
774 }
775 
777  const LinearConstraintId id) const {
778  return linear_constraints_.name(id);
779 }
780 
782  const LinearConstraintId id, const double lower_bound) {
783  linear_constraints_.set_lower_bound(id, lower_bound,
784  UpdateAndGetLinearConstraintDiffs());
785 }
786 
788  const LinearConstraintId id, const double upper_bound) {
789  linear_constraints_.set_upper_bound(id, upper_bound,
790  UpdateAndGetLinearConstraintDiffs());
791 }
792 
794  return linear_constraints_.size();
795 }
796 
797 LinearConstraintId ModelStorage::next_linear_constraint_id() const {
798  return linear_constraints_.next_id();
799 }
800 
802  LinearConstraintId id) {
803  linear_constraints_.ensure_next_id_at_least(id);
804 }
805 
806 bool ModelStorage::has_linear_constraint(const LinearConstraintId id) const {
807  return linear_constraints_.contains(id);
808 }
809 
811 // Linear Constraint Matrix
813 
815  LinearConstraintId constraint, VariableId variable) const {
816  return linear_constraints_.matrix().get(constraint, variable);
817 }
818 
820  LinearConstraintId constraint, VariableId variable) const {
821  return linear_constraints_.matrix().contains(constraint, variable);
822 }
823 
825  const LinearConstraintId constraint, const VariableId variable,
826  const double value) {
827  linear_constraints_.set_term(constraint, variable, value,
828  UpdateAndGetLinearConstraintDiffs());
829 }
830 
831 std::vector<std::tuple<LinearConstraintId, VariableId, double>>
833  return linear_constraints_.matrix().Terms();
834 }
835 
837  LinearConstraintId constraint) const {
838  return linear_constraints_.matrix().row(constraint);
839 }
840 
841 std::vector<LinearConstraintId> ModelStorage::linear_constraints_with_variable(
842  VariableId variable) const {
843  return linear_constraints_.matrix().column(variable);
844 }
845 
847 // Objective
849 
850 bool ModelStorage::is_maximize() const { return objective_.maximize(); }
851 
852 double ModelStorage::objective_offset() const { return objective_.offset(); }
853 
855  const VariableId variable) const {
856  return objective_.linear_term(variable);
857 }
858 
860  const VariableId first_variable, const VariableId second_variable) const {
861  return objective_.quadratic_term(first_variable, second_variable);
862 }
863 
865  const VariableId variable) const {
866  return objective_.linear_terms().contains(variable);
867 }
868 
870  const VariableId first_variable, const VariableId second_variable) const {
871  return objective_.quadratic_terms().get(first_variable, second_variable) !=
872  0.0;
873 }
874 
875 void ModelStorage::set_is_maximize(const bool is_maximize) {
876  objective_.set_maximize(is_maximize, UpdateAndGetObjectiveDiffs());
877 }
878 
880 
882 
884  objective_.set_offset(value, UpdateAndGetObjectiveDiffs());
885 }
886 
887 void ModelStorage::set_linear_objective_coefficient(const VariableId variable,
888  const double value) {
889  objective_.set_linear_term(variable, value, UpdateAndGetObjectiveDiffs());
890 }
891 
893  const VariableId first_variable, const VariableId second_variable,
894  const double value) {
895  objective_.set_quadratic_term(first_variable, second_variable, value,
896  UpdateAndGetObjectiveDiffs());
897 }
898 
900  objective_.Clear(UpdateAndGetObjectiveDiffs());
901 }
902 
903 const absl::flat_hash_map<VariableId, double>& ModelStorage::linear_objective()
904  const {
905  return objective_.linear_terms();
906 }
907 
909  return objective_.quadratic_terms().nonzeros();
910 }
911 
912 std::vector<std::tuple<VariableId, VariableId, double>>
914  return objective_.quadratic_terms().Terms();
915 }
916 
918 // Atomic constraint template inline implementations.
920 
921 template <typename ConstraintData>
922 typename ConstraintData::IdType ModelStorage::AddAtomicConstraint(
923  ConstraintData data) {
924  return constraint_storage<ConstraintData>().AddConstraint(data);
925 }
926 
927 template <typename IdType>
929  using ConstraintData =
931  auto& storage = constraint_storage<ConstraintData>();
932  CHECK(storage.contains(id));
933  storage.Delete(
934  id,
936  UpdateTrackerData::AtomicConstraintDirtyFieldPtr<ConstraintData>()>(
937  update_trackers_.GetUpdatedTrackers()));
938 }
939 
940 template <typename IdType>
942 ModelStorage::constraint_data(const IdType id) const {
943  using ConstraintData =
945  return constraint_storage<ConstraintData>().data(id);
946 }
947 
948 template <typename IdType>
950  using ConstraintData =
952  return constraint_storage<ConstraintData>().size();
953 }
954 
955 template <typename IdType>
957  using ConstraintData =
959  return constraint_storage<ConstraintData>().next_id();
960 }
961 
962 template <typename IdType>
964  using ConstraintData =
966  return constraint_storage<ConstraintData>().ensure_next_id_at_least(id);
967 }
968 
969 template <typename IdType>
970 bool ModelStorage::has_constraint(const IdType id) const {
971  using ConstraintData =
973  return constraint_storage<ConstraintData>().contains(id);
974 }
975 
976 template <typename IdType>
977 std::vector<IdType> ModelStorage::Constraints() const {
978  using ConstraintData =
980  return constraint_storage<ConstraintData>().Constraints();
981 }
982 
983 template <typename IdType>
984 std::vector<IdType> ModelStorage::SortedConstraints() const {
985  using ConstraintData =
987  return constraint_storage<ConstraintData>().SortedConstraints();
988 }
989 
990 template <typename IdType>
992  const VariableId variable_id) const {
993  using ConstraintData =
995  const absl::flat_hash_set<IdType> constraints =
996  constraint_storage<ConstraintData>().RelatedConstraints(variable_id);
997  return {constraints.begin(), constraints.end()};
998 }
999 
1000 template <typename IdType>
1001 std::vector<VariableId> ModelStorage::VariablesInConstraint(
1002  const IdType id) const {
1003  return constraint_data(id).RelatedVariables();
1004 }
1005 
1007 // Atomic constraint template specializations.
1009 
1010 // --------------------------- Quadratic constraints ---------------------------
1011 
1012 template <>
1014 ModelStorage::constraint_storage() {
1015  return quadratic_constraints_;
1016 }
1017 
1018 template <>
1020 ModelStorage::constraint_storage() const {
1021  return quadratic_constraints_;
1022 }
1023 
1024 template <>
1026  ModelStorage::UpdateTrackerData::*
1027  ModelStorage::UpdateTrackerData::AtomicConstraintDirtyFieldPtr<
1029  return &UpdateTrackerData::dirty_quadratic_constraints;
1030 }
1031 
1032 // ----------------------------- SOS1 constraints ------------------------------
1033 
1034 template <>
1035 inline AtomicConstraintStorage<Sos1ConstraintData>&
1036 ModelStorage::constraint_storage() {
1037  return sos1_constraints_;
1038 }
1039 
1040 template <>
1041 inline const AtomicConstraintStorage<Sos1ConstraintData>&
1042 ModelStorage::constraint_storage() const {
1043  return sos1_constraints_;
1044 }
1045 
1046 template <>
1047 constexpr typename AtomicConstraintStorage<Sos1ConstraintData>::Diff
1048  ModelStorage::UpdateTrackerData::*
1049  ModelStorage::UpdateTrackerData::AtomicConstraintDirtyFieldPtr<
1050  Sos1ConstraintData>() {
1051  return &UpdateTrackerData::dirty_sos1_constraints;
1052 }
1053 
1054 // ----------------------------- SOS2 constraints ------------------------------
1055 
1056 template <>
1057 inline AtomicConstraintStorage<Sos2ConstraintData>&
1058 ModelStorage::constraint_storage() {
1059  return sos2_constraints_;
1060 }
1061 
1062 template <>
1063 inline const AtomicConstraintStorage<Sos2ConstraintData>&
1064 ModelStorage::constraint_storage() const {
1065  return sos2_constraints_;
1066 }
1067 
1068 template <>
1069 constexpr typename AtomicConstraintStorage<Sos2ConstraintData>::Diff
1070  ModelStorage::UpdateTrackerData::*
1071  ModelStorage::UpdateTrackerData::AtomicConstraintDirtyFieldPtr<
1072  Sos2ConstraintData>() {
1073  return &UpdateTrackerData::dirty_sos2_constraints;
1074 }
1075 
1076 // --------------------------- Indicator constraints ---------------------------
1077 
1078 template <>
1079 inline AtomicConstraintStorage<IndicatorConstraintData>&
1080 ModelStorage::constraint_storage() {
1081  return indicator_constraints_;
1082 }
1083 
1084 template <>
1085 inline const AtomicConstraintStorage<IndicatorConstraintData>&
1086 ModelStorage::constraint_storage() const {
1087  return indicator_constraints_;
1088 }
1089 
1090 template <>
1091 constexpr typename AtomicConstraintStorage<IndicatorConstraintData>::Diff
1092  ModelStorage::UpdateTrackerData::*
1093  ModelStorage::UpdateTrackerData::AtomicConstraintDirtyFieldPtr<
1094  IndicatorConstraintData>() {
1095  return &UpdateTrackerData::dirty_indicator_constraints;
1096 }
1097 
1098 } // namespace math_opt
1099 } // namespace operations_research
1100 
1101 #endif // OR_TOOLS_MATH_OPT_STORAGE_MODEL_STORAGE_H_
void set_upper_bound(LinearConstraintId id, double upper_bound, const iterator_range< DiffIter > &diffs)
const SparseMatrix< LinearConstraintId, VariableId > & matrix() const
void set_lower_bound(LinearConstraintId id, double lower_bound, const iterator_range< DiffIter > &diffs)
const std::string & name(LinearConstraintId id) const
void set_term(LinearConstraintId constraint, VariableId variable, double value, const iterator_range< DiffIter > &diffs)
LinearConstraintId next_linear_constraint_id() const
void set_quadratic_objective_coefficient(VariableId first_variable, VariableId second_variable, double value)
std::vector< VariableId > SortedVariables() const
std::vector< LinearConstraintId > linear_constraints_with_variable(VariableId variable) const
ModelStorage & operator=(const ModelStorage &)=delete
double linear_objective_coefficient(VariableId variable) const
static absl::StatusOr< std::unique_ptr< ModelStorage > > FromModelProto(const ModelProto &model_proto)
double linear_constraint_coefficient(LinearConstraintId constraint, VariableId variable) const
std::optional< ModelUpdateProto > ExportModelUpdate(UpdateTrackerId update_tracker) const
void DeleteLinearConstraint(LinearConstraintId id)
void set_linear_objective_coefficient(VariableId variable, double value)
const AtomicConstraintTraits< IdType >::ConstraintData & constraint_data(IdType id) const
void DeleteUpdateTracker(UpdateTrackerId update_tracker)
std::vector< VariableId > variables() const
ConstraintData::IdType AddAtomicConstraint(ConstraintData data)
double linear_constraint_lower_bound(LinearConstraintId id) const
bool is_quadratic_objective_coefficient_nonzero(VariableId first_variable, VariableId second_variable) const
ModelStorage(absl::string_view name="")
absl::Status ApplyUpdateProto(const ModelUpdateProto &update_proto)
void set_linear_constraint_coefficient(LinearConstraintId constraint, VariableId variable, double value)
VariableId AddVariable(absl::string_view name="")
void AdvanceCheckpoint(UpdateTrackerId update_tracker)
void set_variable_upper_bound(VariableId id, double upper_bound)
std::vector< VariableId > variables_in_linear_constraint(LinearConstraintId constraint) const
void set_variable_is_integer(VariableId id, bool is_integer)
void ensure_next_variable_id_at_least(VariableId id)
bool has_linear_constraint(LinearConstraintId id) const
const std::string & variable_name(VariableId id) const
std::vector< IdType > Constraints() const
void set_linear_constraint_upper_bound(LinearConstraintId id, double upper_bound)
double quadratic_objective_coefficient(VariableId first_variable, VariableId second_variable) const
void set_linear_constraint_lower_bound(LinearConstraintId id, double lower_bound)
double linear_constraint_upper_bound(LinearConstraintId id) const
std::vector< LinearConstraintId > LinearConstraints() const
std::vector< std::tuple< VariableId, VariableId, double > > quadratic_objective_terms() const
std::unique_ptr< ModelStorage > Clone(std::optional< absl::string_view > new_name=std::nullopt) const
std::vector< std::tuple< LinearConstraintId, VariableId, double > > linear_constraint_matrix() const
ModelStorage(const ModelStorage &)=delete
double variable_lower_bound(VariableId id) const
void ensure_next_linear_constraint_id_at_least(LinearConstraintId id)
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
std::vector< IdType > ConstraintsWithVariable(VariableId variable_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
std::vector< IdType > SortedConstraints() const
double variable_upper_bound(VariableId id) const
void set_variable_lower_bound(VariableId id, double lower_bound)
std::vector< VariableId > VariablesInConstraint(IdType id) const
const absl::flat_hash_map< VariableId, double > & linear_terms() const
void Clear(const iterator_range< DiffIter > &diffs)
double quadratic_term(const VariableId v1, const VariableId v2) const
void set_maximize(bool maximize, const iterator_range< DiffIter > &diffs)
void set_offset(double offset, const iterator_range< DiffIter > &diffs)
void set_linear_term(VariableId variable, double value, const iterator_range< DiffIter > &diffs)
void set_quadratic_term(VariableId v1, VariableId v2, double val, const iterator_range< DiffIter > &diffs)
const SparseSymmetricMatrix & quadratic_terms() const
std::vector< RowId > column(ColumnId column_id) const
std::vector< std::tuple< RowId, ColumnId, double > > Terms() const
bool contains(RowId row, ColumnId column) const
std::vector< ColumnId > row(RowId row_id) const
double get(RowId row, ColumnId column) const
double get(VariableId first, VariableId second) const
std::vector< std::pair< VariableId, double > > Terms(VariableId variable) const
const std::vector< IdDataPair > & GetUpdatedTrackers()
void set_integer(VariableId id, bool is_integer, const iterator_range< DiffIter > &diffs)
void set_lower_bound(VariableId id, double lower_bound, const iterator_range< DiffIter > &diffs)
void set_upper_bound(VariableId id, double upper_bound, const iterator_range< DiffIter > &diffs)
const std::string & name(VariableId id) const
CpModelProto const * model_proto
const std::string name
int64_t value
absl::Span< const double > coefficients
internal::SosConstraintData< Sos1ConstraintId > Sos1ConstraintData
Definition: sos/storage.h:105
internal::SosConstraintData< Sos2ConstraintId > Sos2ConstraintData
Definition: sos/storage.h:106
auto MakeUpdateDataFieldRange(const UpdateTrackers &trackers)
Collection of objects used to extend the Constraint Solver library.
IntVar * upper_bound
Definition: routing.cc:1087
IntVar * lower_bound
Definition: routing.cc:1086