Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
model_storage.h
Go to the documentation of this file.
1// Copyright 2010-2025 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#ifdef MATHOPT_STORAGE_V2
18
20
22
23using ModelStorage = ModelStorageV2;
24
25} // namespace operations_research::math_opt
26
27#else
28
29#include <cstdint>
30#include <limits>
31#include <memory>
32#include <optional>
33#include <string>
34#include <tuple>
35#include <vector>
36
37#include "absl/base/nullability.h"
38#include "absl/container/flat_hash_map.h"
39#include "absl/container/flat_hash_set.h"
40#include "absl/log/check.h"
41#include "absl/status/status.h"
42#include "absl/status/statusor.h"
43#include "absl/strings/string_view.h"
44#include "ortools/math_opt/constraints/indicator/storage.h" // IWYU pragma: export
45#include "ortools/math_opt/constraints/quadratic/storage.h" // IWYU pragma: export
47#include "ortools/math_opt/constraints/sos/storage.h" // IWYU pragma: export
51#include "ortools/math_opt/storage/atomic_constraint_storage.h" // IWYU pragma: export
58
59namespace operations_research {
60namespace math_opt {
61
62// An index based C++ API for building & storing optimization problems.
63//
64// Note that this API should usually not be used by C++ users that should prefer
65// the math_opt/cpp/model.h API.
66//
67// It supports the efficient creation and modification of an optimization model,
68// and the export of ModelProto and ModelUpdateProto protos.
69//
70// All methods run in amortized O(1) (as amortized over calls to that exact
71// function) unless otherwise specified.
72//
73// Models problems of the form:
74// min sum_{j in J} c_j * x_j + d
75// s.t. lb^c_i <= sum_{j in J} A_ij * x_j <= ub^c_i for all i in I,
76// lb^v_j <= x_j <= ub^v_j for all j in J,
77// x_j integer for all j in Z,
78// where above:
79// * I: the set of linear constraints,
80// * J: the set of variables,
81// * Z: a subset of J, the integer variables,
82// * x: the decision variables (indexed by J),
83// * c: the linear objective, one double per variable,
84// * d: the objective offset, a double scalar,
85// * lb^c: the constraint lower bounds, one double per linear constraint,
86// * ub^c: the constraint upper bounds, one double per linear constraint,
87// * lb^v: the variable lower bounds, one double per variable,
88// * ub^v: the variable upper bounds, one double per variable,
89// * A: the linear constraint matrix, a double per variable/constraint pair.
90//
91// The min in the objective can also be changed to a max.
92//
93// A simple example:
94//
95// Model the problem:
96// max 2.0 * x + y
97// s.t. x + y <= 1.5
98// x in {0.0, 1.0}
99// 0 <= y <= 2.5
100//
101// using ::operations_research::math_opt::ModelStorage;
102// using ::operations_research::math_opt::VariableId;
103// using ::operations_research::math_opt::LinearConstraintId;
104// using ::operations_research::math_opt::ModelProto;
105// using ::operations_research::math_opt::ModelProtoUpdate;
106//
107// ModelStorage model("my_model");
108// const VariableId x = model.AddVariable(0.0, 1.0, true, "x");
109// const VariableId y = model.AddVariable(0.0, 2.5, false, "y");
110// const LinearConstraintId c = model.AddLinearConstraint(
111// -std::numeric_limits<double>::infinity, 1.5, "c");
112// model.set_linear_constraint_coefficient(x, c, 1.0);
113// model.set_linear_constraint_coefficient(y, c, 1.0);
114// model.set_linear_objective_coefficient(kPrimaryObjectiveId, x, 2.0);
115// model.set_linear_objective_coefficient(kPrimaryObjectiveId, y, 1.0);
116// model.set_maximize(kPrimaryObjectiveId);
117//
118// Now, export to a proto describing the model:
119//
120// const ModelProto model_proto = model.ExportModel();
121//
122// Modify the problem and get a model update proto:
123//
124// const UpdateTrackerId update_tracker = model.NewUpdateTracker();
125// c.set_upper_bound(2.0);
126// const std::optional<ModelUpdateProto> update_proto =
127// model.ExportModelUpdate(update_tracker);
128// model.AdvanceCheckpoint(update_tracker);
129//
130// Reading and writing model properties:
131//
132// Properties of the model (e.g. variable/constraint bounds) can be written
133// and read in amortized O(1) time. Deleting a variable will take time
134// O(#constraints containing the variable), and likewise deleting a constraint
135// will take time O(#variables in the constraint). The constraint matrix is
136// stored as hash map where the key is a {LinearConstraintId, VariableId}
137// pair and the value is the coefficient. The nonzeros of the matrix are
138// additionally stored by row and by column.
139//
140// Exporting the Model proto:
141//
142// The Model proto is an equivalent representation to ModelStorage. It has a
143// smaller memory footprint and optimized for storage/transport, rather than
144// efficient modification. It is also the format consumed by solvers in this
145// library. The Model proto can be generated by calling
146// ModelStorage::ExportModel().
147//
148// Incrementalism, the ModelUpdate proto, and Checkpoints:
149//
150// To update an existing model as specified by a Model proto, solvers consume a
151// ModelUpdate proto, which describes the changes to a model (e.g. new variables
152// or a change in a variable bound). ModelStorage::NewUpdateTracker() tracks the
153// changes made and produces a ModelUpdate proto describing these changes with
154// the method ModelStorage::ExportModelUpdate(). The changes returned will be
155// the modifications since the previous call to
156// ModelStorage::AdvanceCheckpoint(). Note that, for newly initialized models,
157// before the first checkpoint, there is no additional memory overhead from
158// tracking changes. See
159// g3doc/ortools/math_opt/g3doc/model_building_complexity.md
160// for details.
161//
162// On bad input:
163//
164// Using a bad variable id or constraint id (an id not in the current model,
165// which includes ids that have been deleted) on any method will result in an
166// immediate failure (either a CHECK failure or an exception, which is an
167// implementation detail you should not rely on). We make no attempt to say if a
168// model is invalid (e.g. a variable lower bound is infinite, exceeds an upper
169// bound, or is NaN). The exported models are validated instead, see
170// model_validator.h.
171class ModelStorage {
172 public:
173 // Returns a storage from the input proto. Returns a failure status if the
174 // input proto is invalid.
175 //
176 // Variable/constraint names can be repeated in the input proto but will be
177 // considered invalid when solving.
178 //
179 // See ApplyUpdateProto() for dealing with subsequent updates.
180 static absl::StatusOr<absl::Nonnull<std::unique_ptr<ModelStorage> > >
181 FromModelProto(const ModelProto& model_proto);
182
183 // Creates an empty minimization problem.
184 inline explicit ModelStorage(absl::string_view model_name = "",
185 absl::string_view primary_objective_name = "");
186
187 ModelStorage& operator=(const ModelStorage&) = delete;
188
189 // Returns a clone of the model, optionally changing model's name.
190 //
191 // The variables and constraints have the same ids. The clone will also not
192 // reused any id of variable/constraint that was deleted in the original.
193 //
194 // Note that the returned model does not have any update tracker.
195 absl::Nonnull<std::unique_ptr<ModelStorage> > Clone(
196 std::optional<absl::string_view> new_name = std::nullopt) const;
197
198 inline const std::string& name() const { return copyable_data_.name; }
199
201 // Variables
203
204 // Adds a continuous unbounded variable to the model and returns its id.
205 //
206 // See AddVariable(double, double, bool, absl::string_view) for details.
207 inline VariableId AddVariable(absl::string_view name = "");
208
209 // Adds a variable to the model and returns its id.
210 //
211 // The returned ids begin at zero and increase by one with each call to
212 // AddVariable. Deleted ids are NOT reused. If no variables are deleted,
213 // the ids in the model will be consecutive.
214 VariableId AddVariable(double lower_bound, double upper_bound,
215 bool is_integer, absl::string_view name = "");
216
217 inline double variable_lower_bound(VariableId id) const;
218 inline double variable_upper_bound(VariableId id) const;
219 inline bool is_variable_integer(VariableId id) const;
220 inline const std::string& variable_name(VariableId id) const;
221
222 inline void set_variable_lower_bound(VariableId id, double lower_bound);
223 inline void set_variable_upper_bound(VariableId id, double upper_bound);
224 inline void set_variable_is_integer(VariableId id, bool is_integer);
225 inline void set_variable_as_integer(VariableId id);
226 inline void set_variable_as_continuous(VariableId id);
227
228 // Removes a variable from the model.
229 //
230 // It is an error to use a deleted variable id as input to any subsequent
231 // function calls on the model. Runs in O(#constraints containing the
232 // variable).
233 void DeleteVariable(VariableId id);
234
235 // The number of variables in the model.
236 //
237 // Equal to the number of variables created minus the number of variables
238 // deleted.
239 inline int num_variables() const;
240
241 // The returned id of the next call to AddVariable.
242 //
243 // Equal to the number of variables created.
244 inline VariableId next_variable_id() const;
245
246 // Sets the next variable id to be the maximum of next_variable_id() and id.
247 inline void ensure_next_variable_id_at_least(VariableId id);
248
249 // Returns true if this id has been created and not yet deleted.
250 inline bool has_variable(VariableId id) const;
251
252 // The VariableIds in use (not deleted), order not defined.
253 std::vector<VariableId> variables() const;
254
255 // Returns a sorted vector of all existing (not deleted) variables in the
256 // model.
257 //
258 // Runs in O(n log(n)), where n is the number of variables returned.
259 std::vector<VariableId> SortedVariables() const;
260
262 // Linear Constraints
264
265 // Adds a linear constraint to the model with a lower bound of -inf and an
266 // upper bound of +inf and returns its id.
267 //
268 // See AddLinearConstraint(double, double, absl::string_view) for details.
269 inline LinearConstraintId AddLinearConstraint(absl::string_view name = "");
270
271 // Adds a linear constraint to the model returns its id.
272 //
273 // The returned ids begin at zero and increase by one with each call to
274 // AddLinearConstraint. Deleted ids are NOT reused. If no linear
275 // constraints are deleted, the ids in the model will be consecutive.
276 LinearConstraintId AddLinearConstraint(double lower_bound, double upper_bound,
277 absl::string_view name = "");
278
279 inline double linear_constraint_lower_bound(LinearConstraintId id) const;
280 inline double linear_constraint_upper_bound(LinearConstraintId id) const;
281 inline const std::string& linear_constraint_name(LinearConstraintId id) const;
282
283 inline void set_linear_constraint_lower_bound(LinearConstraintId id,
284 double lower_bound);
285 inline void set_linear_constraint_upper_bound(LinearConstraintId id,
286 double upper_bound);
287
288 // Removes a linear constraint from the model.
289 //
290 // It is an error to use a deleted linear constraint id as input to any
291 // subsequent function calls on the model. Runs in O(#variables in the linear
292 // constraint).
293 void DeleteLinearConstraint(LinearConstraintId id);
294
295 // The number of linear constraints in the model.
296 //
297 // Equal to the number of linear constraints created minus the number of
298 // linear constraints deleted.
299 inline int num_linear_constraints() const;
300
301 // The returned id of the next call to AddLinearConstraint.
302 //
303 // Equal to the number of linear constraints created.
304 inline LinearConstraintId next_linear_constraint_id() const;
305
306 // Sets the next linear constraint id to be the maximum of
307 // next_linear_constraint_id() and id.
308 inline void ensure_next_linear_constraint_id_at_least(LinearConstraintId id);
309
310 // Returns true if this id has been created and not yet deleted.
311 inline bool has_linear_constraint(LinearConstraintId id) const;
312
313 // The LinearConstraintsIds in use (not deleted), order not defined.
314 std::vector<LinearConstraintId> LinearConstraints() const;
315
316 // Returns a sorted vector of all existing (not deleted) linear constraints in
317 // the model.
318 //
319 // Runs in O(n log(n)), where n is the number of linear constraints returned.
320 std::vector<LinearConstraintId> SortedLinearConstraints() const;
321
323 // Linear constraint matrix
325
326 // Returns 0.0 if the entry is not in matrix.
327 inline double linear_constraint_coefficient(LinearConstraintId constraint,
328 VariableId variable) const;
329 inline bool is_linear_constraint_coefficient_nonzero(
330 LinearConstraintId constraint, VariableId variable) const;
331
332 // Setting a value to 0.0 will delete the {constraint, variable} pair from the
333 // underlying sparse matrix representation (and has no effect if the pair is
334 // not present).
335 inline void set_linear_constraint_coefficient(LinearConstraintId constraint,
336 VariableId variable,
337 double value);
338
339 // The {linear constraint, variable, coefficient} tuples with nonzero linear
340 // constraint matrix coefficients.
341 inline std::vector<std::tuple<LinearConstraintId, VariableId, double> >
342 linear_constraint_matrix() const;
343
344 // Returns the variables with nonzero coefficients in a linear constraint.
345 inline std::vector<VariableId> variables_in_linear_constraint(
346 LinearConstraintId constraint) const;
347
348 // Returns the linear constraints with nonzero coefficients on a variable.
349 inline std::vector<LinearConstraintId> linear_constraints_with_variable(
350 VariableId variable) const;
351
353 // Objectives
354 //
355 // The primary ObjectiveId is `PrimaryObjectiveId`. All auxiliary objectives
356 // are referenced by their corresponding `AuxiliaryObjectiveId`.
358
359 inline bool is_maximize(ObjectiveId id) const;
360 inline int64_t objective_priority(ObjectiveId id) const;
361 inline double objective_offset(ObjectiveId id) const;
362 // Returns 0.0 if this variable has no linear objective coefficient.
363 inline double linear_objective_coefficient(ObjectiveId id,
364 VariableId variable) const;
365 // The ordering of the input variables does not matter.
366 inline double quadratic_objective_coefficient(
367 ObjectiveId id, VariableId first_variable,
368 VariableId second_variable) const;
369 inline bool is_linear_objective_coefficient_nonzero(
370 ObjectiveId id, VariableId variable) const;
371 // The ordering of the input variables does not matter.
372 inline bool is_quadratic_objective_coefficient_nonzero(
373 ObjectiveId id, VariableId first_variable,
374 VariableId second_variable) const;
375 inline const std::string& objective_name(ObjectiveId id) const;
376
377 inline void set_is_maximize(ObjectiveId id, bool is_maximize);
378 inline void set_maximize(ObjectiveId id);
379 inline void set_minimize(ObjectiveId id);
380 inline void set_objective_priority(ObjectiveId id, int64_t value);
381 inline void set_objective_offset(ObjectiveId id, double value);
382
383 // Setting a value to 0.0 will delete the variable from the underlying sparse
384 // representation (and has no effect if the variable is not present).
385 inline void set_linear_objective_coefficient(ObjectiveId id,
386 VariableId variable,
387 double value);
388 // Setting a value to 0.0 will delete the variable pair from the underlying
389 // sparse representation (and has no effect if the pair is not present).
390 // The ordering of the input variables does not matter.
391 inline void set_quadratic_objective_coefficient(ObjectiveId id,
392 VariableId first_variable,
393 VariableId second_variable,
394 double value);
395
396 // Equivalent to calling set_linear_objective_coefficient(v, 0.0) for every
397 // variable with nonzero objective coefficient.
398 //
399 // Runs in O(# nonzero linear/quadratic objective terms).
400 inline void clear_objective(ObjectiveId id);
401
402 // The variables with nonzero linear objective coefficients.
403 inline const absl::flat_hash_map<VariableId, double>& linear_objective(
404 ObjectiveId id) const;
405
406 inline int64_t num_linear_objective_terms(ObjectiveId id) const;
407
408 inline int64_t num_quadratic_objective_terms(ObjectiveId id) const;
409
410 // The variable pairs with nonzero quadratic objective coefficients. The keys
411 // are ordered such that .first <= .second. All values are nonempty.
412 //
413 // TODO(b/233630053) do no allocate the result, expose an iterator API.
414 inline std::vector<std::tuple<VariableId, VariableId, double> >
415 quadratic_objective_terms(ObjectiveId id) const;
416
418 // Auxiliary objectives
420
421 // Adds an auxiliary objective to the model and returns its id.
422 //
423 // The returned ids begin at zero and increase by one with each call to
424 // AddAuxiliaryObjective. Deleted ids are NOT reused. If no auxiliary
425 // objectives are deleted, the ids in the model will be consecutive.
426 //
427 // Objectives are minimized by default; you can change the sense via, e.g.,
428 // `set_is_maximize()`.
429 inline AuxiliaryObjectiveId AddAuxiliaryObjective(
430 int64_t priority, absl::string_view name = "");
431
432 // Removes an auxiliary objective from the model.
433 //
434 // It is an error to use a deleted auxiliary objective id as input to any
435 // subsequent function calls on the model. Runs in O(#variables in the
436 // auxiliary objective).
437 inline void DeleteAuxiliaryObjective(AuxiliaryObjectiveId id);
438
439 // The number of auxiliary objectives in the model.
440 //
441 // Equal to the number of auxiliary objectives created minus the number of
442 // auxiliary objectives deleted.
443 inline int num_auxiliary_objectives() const;
444
445 // The returned id of the next call to AddAuxiliaryObjective.
446 //
447 // Equal to the number of auxiliary objectives created.
448 inline AuxiliaryObjectiveId next_auxiliary_objective_id() const;
449
450 // Sets the next auxiliary objective id to be the maximum of
451 // next_auxiliary_objective_id() and id.
452 inline void ensure_next_auxiliary_objective_id_at_least(
453 AuxiliaryObjectiveId id);
454
455 // Returns true if this id has been created and not yet deleted.
456 inline bool has_auxiliary_objective(AuxiliaryObjectiveId id) const;
457
458 // The AuxiliaryObjectiveIds in use (not deleted), order not defined.
459 inline std::vector<AuxiliaryObjectiveId> AuxiliaryObjectives() const;
460
461 // Returns a sorted vector of all existing (not deleted) auxiliary objectives
462 // in the model.
463 //
464 // Runs in O(n log(n)), where n is the number of auxiliary objectives
465 // returned.
466 inline std::vector<AuxiliaryObjectiveId> SortedAuxiliaryObjectives() const;
467
469 // Atomic Constraints
470 //
471 // These methods do not directly require template specializations to add
472 // support for new constraint families; this should be handled automatically
473 // upon adding a specialization for `AtomicConstraintTraits`.
475
476 // Adds an atomic constraint to the model and returns its id.
477 //
478 // The returned ids begin at zero and increase by one with each call to
479 // `AddAtomicConstraint<ConstraintData>`. Deleted ids are NOT reused. Callers
480 // may use `ensure_next_constraint_id_at_least<ConstraintData>` to configure
481 // custom indices.
482 template <typename ConstraintData>
483 inline typename ConstraintData::IdType AddAtomicConstraint(
484 ConstraintData data);
485
486 // Removes an atomic constraint from the model.
487 //
488 // It is an error to use a deleted constraint id as input to any subsequent
489 // function calls on the model. Runs in O(#variables in the constraint).
490 template <typename IdType>
491 inline void DeleteAtomicConstraint(IdType id);
492
493 // Accesses the data object that fully represents a single atomic constraint.
494 template <typename IdType>
495 inline const typename AtomicConstraintTraits<IdType>::ConstraintData&
496 constraint_data(IdType id) const;
497
498 // Returns the number of atomic constraints in the model of the family
499 // corresponding to `ConstraintData`.
500 //
501 // Equal to the number of such constraints created minus the number of such
502 // constraints deleted.
503 template <typename IdType>
504 inline int64_t num_constraints() const;
505
506 // Returns the smallest valid ID for a new atomic constraint of the family
507 // corresponding to `ConstraintData`.
508 template <typename IdType>
509 inline IdType next_constraint_id() const;
510
511 // Sets the next atomic constraint id of the family corresponding to
512 // `ConstraintData` to be the maximum of
513 // `next_constraint_id<ConstraintData>()` and `id`.
514 template <typename IdType>
515 inline void ensure_next_constraint_id_at_least(IdType id);
516
517 // Returns true if this id has been created and not yet deleted.
518 template <typename IdType>
519 inline bool has_constraint(IdType id) const;
520
521 // Returns the constraint IDs in use (not deleted); order is not defined.
522 template <typename IdType>
523 std::vector<IdType> Constraints() const;
524
525 // Returns a sorted vector of all existing (not deleted) atomic constraints
526 // in the model of the family corresponding to `ConstraintData`.
527 //
528 // Runs in O(n log(n)), where n is the number of constraints returned.
529 template <typename IdType>
530 std::vector<IdType> SortedConstraints() const;
531
532 // Returns the constraint in the given family in which the variable appears
533 // structurally (i.e., has a coefficient, possibly zero). Order is not
534 // defined.
535 template <typename IdType>
536 inline std::vector<IdType> ConstraintsWithVariable(
537 VariableId variable_id) const;
538
539 // Returns the variables appearing in the constraint. Order is not defined.
540 template <typename IdType>
541 inline std::vector<VariableId> VariablesInConstraint(IdType id) const;
542
544 // Export
546
547 // Returns a proto representation of the optimization model.
548 //
549 // See FromModelProto() to build a ModelStorage from a proto.
550 ModelProto ExportModel(bool remove_names = false) const;
551
552 // Creates a tracker that can be used to generate a ModelUpdateProto with the
553 // updates that happened since the last checkpoint. The tracker initial
554 // checkpoint corresponds to the current state of the model.
555 //
556 // Thread-safety: this method must not be used while modifying the
557 // ModelStorage. The user is expected to use proper synchronization primitive
558 // to serialize changes to the model and trackers creations. That said
559 // multiple trackers can be created concurrently.
560 //
561 // For each update tracker we define a checkpoint that is the starting point
562 // used to compute the ModelUpdateProto.
563 //
564 // Example:
565 // ModelStorage model;
566 // ...
567 // ASSIGN_OR_RETURN(const auto solver,
568 // Solver::New(solver_type, model.ExportModel(),
569 // /*initializer=*/{}));
570 // const UpdateTrackerId update_tracker = model.NewUpdatesTracker();
571 //
572 // ASSIGN_OR_RETURN(const auto result_1,
573 // solver->Solve(/*parameters=*/{});
574 //
575 // model.AddVariable(0.0, 1.0, true, "y");
576 // model.set_maximize(true);
577 //
578 // const std::optional<ModelUpdateProto> update_proto =
579 // model.ExportModelUpdate(update_tracker);
580 // model.AdvanceCheckpoint(update_tracker);
581 //
582 // if (update_proto) {
583 // ASSIGN_OR_RETURN(const bool updated, solver->Update(*update_proto));
584 // if (!updated) {
585 // // The update is not supported by the solver, we create a new one.
586 // ASSIGN_OR_RETURN(const auto new_model_proto, model.ExportModel());
587 // ASSIGN_OR_RETURN(solver,
588 // Solver::New(solver_type, new_model_proto,
589 // /*initializer=*/{}));
590 // }
591 // }
592 // ASSIGN_OR_RETURN(const auto result_2,
593 // solver->Solve(/*parameters=*/{});
594 //
595 UpdateTrackerId NewUpdateTracker();
596
597 // Deletes the input tracker.
598 //
599 // It must not be used anymore after its destruction. It can be deleted once,
600 // trying to delete it a second time or use it will raise an assertion
601 // (CHECK).
602 //
603 // The update trackers are automatically deleted when the ModelStorage is
604 // destroyed. Calling this function is thus only useful for performance
605 // reasons, to ensure the ModelStorage does not keep data for update trackers
606 // that are not needed anymore.
607 //
608 // Thread-safety: this method can be called at any time, even during the
609 // creation of other trackers or during model modification. It must not be
610 // called concurrently with ExportModelUpdate() or AdvanceCheckpoint() though.
611 void DeleteUpdateTracker(UpdateTrackerId update_tracker);
612
613 // Returns a proto representation of the changes to the model since the most
614 // recent checkpoint (i.e. last time AdvanceCheckpoint() was called); nullopt
615 // if the update would have been empty.
616 //
617 // Thread-safety: this method must not be used while modifying the
618 // ModelStorage or after calling DeleteUpdateTracker(). The user is expected
619 // to use proper synchronization primitive to serialize changes to the model
620 // and the use of this method.
621 //
622 // It can be called concurrently for different update trackers though.
623 std::optional<ModelUpdateProto> ExportModelUpdate(
624 UpdateTrackerId update_tracker, bool remove_names = false) const;
625
626 // Uses the current model state as the starting point to calculate the
627 // ModelUpdateProto next time ExportModelUpdate() is called.
628 //
629 // Thread-safety: this method must not be used while modifying the
630 // ModelStorage or after calling DeleteUpdateTracker(). The user is expected
631 // to use proper synchronization primitive to serialize changes to the model
632 // and the use of this method.
633 //
634 // It can be called concurrently for different update trackers though.
635 void AdvanceCheckpoint(UpdateTrackerId update_tracker);
636
637 // Apply the provided update to this model. Returns a failure if the update is
638 // not valid.
639 //
640 // As with FromModelProto(), duplicated names are ignored.
641 //
642 // It takes O(num_variables + num_constraints) extra memory and execution to
643 // apply the update (due to the need to build a ModelSummary). So even a small
644 // update will have some cost.
645 absl::Status ApplyUpdateProto(const ModelUpdateProto& update_proto);
646
647 private:
648 struct UpdateTrackerData {
649 UpdateTrackerData(
650 const VariableStorage& variables, const ObjectiveStorage& objectives,
651 const LinearConstraintStorage& linear_constraints,
652 const AtomicConstraintStorage<QuadraticConstraintData>&
653 quadratic_constraints,
654 const AtomicConstraintStorage<SecondOrderConeConstraintData>
655 soc_constraints,
656 const AtomicConstraintStorage<Sos1ConstraintData>& sos1_constraints,
657 const AtomicConstraintStorage<Sos2ConstraintData>& sos2_constraints,
658 const AtomicConstraintStorage<IndicatorConstraintData>&
659 indicator_constraints)
660 : dirty_variables(variables),
661 dirty_objective(objectives, variables.next_id()),
662 dirty_linear_constraints(linear_constraints,
663 dirty_variables.checkpoint),
664 dirty_quadratic_constraints(quadratic_constraints),
665 dirty_soc_constraints(soc_constraints),
666 dirty_sos1_constraints(sos1_constraints),
667 dirty_sos2_constraints(sos2_constraints),
668 dirty_indicator_constraints(indicator_constraints) {}
669
670 // Returns a proto representation of the changes to the model since the most
671 // recent call to SharedCheckpoint() or nullopt if no changes happened.
672 //
673 // Thread-safety: this method is threadsafe.
674 std::optional<ModelUpdateProto> ExportModelUpdate(
675 const ModelStorage& storage, bool remove_names = false) const;
676
677 // Use the current model state as the starting point to calculate the
678 // ModelUpdateProto next time ExportSharedModelUpdate() is called.
679 void AdvanceCheckpoint(const ModelStorage& storage);
680
681 // Implementers of new constraint types should provide a specialization that
682 // returns the address of the appropriate `UpdateTrackerData` field.
683 template <typename ConstraintData>
684 static constexpr typename AtomicConstraintStorage<ConstraintData>::Diff
685 UpdateTrackerData::*
686 AtomicConstraintDirtyFieldPtr();
687
688 // Update information
689 //
690 // Implicitly, all data for variables and constraints added after the last
691 // checkpoint are considered "new" and will NOT be stored in the "dirty"
692 // data structures below.
693
694 VariableStorage::Diff dirty_variables;
695 ObjectiveStorage::Diff dirty_objective;
696 LinearConstraintStorage::Diff dirty_linear_constraints;
697 AtomicConstraintStorage<QuadraticConstraintData>::Diff
698 dirty_quadratic_constraints;
699 AtomicConstraintStorage<SecondOrderConeConstraintData>::Diff
700 dirty_soc_constraints;
701 AtomicConstraintStorage<Sos1ConstraintData>::Diff dirty_sos1_constraints;
702 AtomicConstraintStorage<Sos2ConstraintData>::Diff dirty_sos2_constraints;
703 AtomicConstraintStorage<IndicatorConstraintData>::Diff
704 dirty_indicator_constraints;
705 };
706
707 // All data that is copied (by the C++ default copy constructor) when using
708 // Clone().
709 struct CopyableData {
710 CopyableData(const absl::string_view model_name,
711 const absl::string_view primary_objective_name)
712 : name(model_name), objectives(/*name=*/primary_objective_name) {}
713 std::string name;
714
715 VariableStorage variables;
716 ObjectiveStorage objectives;
717 LinearConstraintStorage linear_constraints;
718
719 AtomicConstraintStorage<QuadraticConstraintData> quadratic_constraints;
720 AtomicConstraintStorage<SecondOrderConeConstraintData> soc_constraints;
721 AtomicConstraintStorage<Sos1ConstraintData> sos1_constraints;
722 AtomicConstraintStorage<Sos2ConstraintData> sos2_constraints;
723 AtomicConstraintStorage<IndicatorConstraintData> indicator_constraints;
724 };
725
726 // Private copy constructor that copies only copyable_data_, not
727 // update_trackers_. It is used internally by Clone().
728 ModelStorage(const ModelStorage& other)
729 : copyable_data_(other.copyable_data_) {}
730
731 auto UpdateAndGetVariableDiffs() {
732 return MakeUpdateDataFieldRange<&UpdateTrackerData::dirty_variables>(
733 update_trackers_.GetUpdatedTrackers());
734 }
735
736 auto UpdateAndGetObjectiveDiffs() {
737 return MakeUpdateDataFieldRange<&UpdateTrackerData::dirty_objective>(
738 update_trackers_.GetUpdatedTrackers());
739 }
740
741 auto UpdateAndGetLinearConstraintDiffs() {
743 &UpdateTrackerData::dirty_linear_constraints>(
744 update_trackers_.GetUpdatedTrackers());
745 }
746
747 // Ids must be greater or equal to `next_variable_id()`.
748 void AddVariables(const VariablesProto& variables);
749
750 // Ids must be greater or equal to `next_auxiliary_objective_id()`.
751 void AddAuxiliaryObjectives(
752 const google::protobuf::Map<int64_t, ObjectiveProto>& objectives);
753
754 // Ids must be greater or equal to `next_linear_constraint_id()`.
755 void AddLinearConstraints(const LinearConstraintsProto& linear_constraints);
756
757 void UpdateObjective(ObjectiveId id, const ObjectiveUpdatesProto& update);
758
759 // Updates the objective linear coefficients. The coefficients of variables
760 // not in the input are kept as-is.
761 void UpdateLinearObjectiveCoefficients(
762 ObjectiveId id, const SparseDoubleVectorProto& coefficients);
763
764 // Updates the objective quadratic coefficients. The coefficients of the pairs
765 // of variables not in the input are kept as-is.
766 void UpdateQuadraticObjectiveCoefficients(
767 ObjectiveId id, const SparseDoubleMatrixProto& coefficients);
768
769 // Updates the linear constraints' coefficients. The coefficients of
770 // (constraint, variable) pairs not in the input are kept as-is.
771 void UpdateLinearConstraintCoefficients(
772 const SparseDoubleMatrixProto& coefficients);
773
774 // Implementers of new constraint types should provide a specialization that
775 // returns a non-const reference to the appropriate `ModelStorage` field.
776 template <typename ConstraintData>
777 AtomicConstraintStorage<ConstraintData>& constraint_storage();
778
779 // Implementers of new constraint types should provide a specialization that
780 // returns a const reference to the appropriate `ModelStorage` field.
781 template <typename ConstraintData>
782 const AtomicConstraintStorage<ConstraintData>& constraint_storage() const;
783
784 CopyableData copyable_data_;
785 UpdateTrackers<UpdateTrackerData> update_trackers_;
786};
787
790// Inlined function implementations
793
794ModelStorage::ModelStorage(const absl::string_view model_name,
795 const absl::string_view primary_objective_name)
796 : copyable_data_(/*model_name=*/model_name,
797 /*primary_objective_name=*/primary_objective_name) {}
798
800// Variables
802
803VariableId ModelStorage::AddVariable(absl::string_view name) {
804 return AddVariable(-std::numeric_limits<double>::infinity(),
805 std::numeric_limits<double>::infinity(), false, name);
806}
807
808double ModelStorage::variable_lower_bound(const VariableId id) const {
809 return copyable_data_.variables.lower_bound(id);
810}
811
812double ModelStorage::variable_upper_bound(const VariableId id) const {
813 return copyable_data_.variables.upper_bound(id);
814}
815
816bool ModelStorage::is_variable_integer(VariableId id) const {
817 return copyable_data_.variables.is_integer(id);
818}
819
820const std::string& ModelStorage::variable_name(const VariableId id) const {
821 return copyable_data_.variables.name(id);
822}
823
824void ModelStorage::set_variable_lower_bound(const VariableId id,
825 const double lower_bound) {
826 copyable_data_.variables.set_lower_bound(id, lower_bound,
827 UpdateAndGetVariableDiffs());
828}
829
830void ModelStorage::set_variable_upper_bound(const VariableId id,
831 const double upper_bound) {
832 copyable_data_.variables.set_upper_bound(id, upper_bound,
833 UpdateAndGetVariableDiffs());
834}
835
836void ModelStorage::set_variable_is_integer(const VariableId id,
837 const bool is_integer) {
838 copyable_data_.variables.set_integer(id, is_integer,
839 UpdateAndGetVariableDiffs());
840}
841
842void ModelStorage::set_variable_as_integer(VariableId id) {
843 set_variable_is_integer(id, true);
844}
845
846void ModelStorage::set_variable_as_continuous(VariableId id) {
847 set_variable_is_integer(id, false);
848}
849
850int ModelStorage::num_variables() const {
851 return static_cast<int>(copyable_data_.variables.size());
852}
853
854VariableId ModelStorage::next_variable_id() const {
855 return copyable_data_.variables.next_id();
856}
857
858void ModelStorage::ensure_next_variable_id_at_least(const VariableId id) {
859 copyable_data_.variables.ensure_next_id_at_least(id);
860}
861
862bool ModelStorage::has_variable(const VariableId id) const {
863 return copyable_data_.variables.contains(id);
864}
865
867// Linear Constraints
869
870LinearConstraintId ModelStorage::AddLinearConstraint(absl::string_view name) {
871 return AddLinearConstraint(-std::numeric_limits<double>::infinity(),
872 std::numeric_limits<double>::infinity(), name);
873}
874
875double ModelStorage::linear_constraint_lower_bound(
876 const LinearConstraintId id) const {
877 return copyable_data_.linear_constraints.lower_bound(id);
878}
879
880double ModelStorage::linear_constraint_upper_bound(
881 const LinearConstraintId id) const {
882 return copyable_data_.linear_constraints.upper_bound(id);
883}
884
885const std::string& ModelStorage::linear_constraint_name(
886 const LinearConstraintId id) const {
887 return copyable_data_.linear_constraints.name(id);
888}
889
890void ModelStorage::set_linear_constraint_lower_bound(
891 const LinearConstraintId id, const double lower_bound) {
892 copyable_data_.linear_constraints.set_lower_bound(
893 id, lower_bound, UpdateAndGetLinearConstraintDiffs());
894}
895
896void ModelStorage::set_linear_constraint_upper_bound(
897 const LinearConstraintId id, const double upper_bound) {
898 copyable_data_.linear_constraints.set_upper_bound(
899 id, upper_bound, UpdateAndGetLinearConstraintDiffs());
900}
901
902int ModelStorage::num_linear_constraints() const {
903 return static_cast<int>(copyable_data_.linear_constraints.size());
904}
905
906LinearConstraintId ModelStorage::next_linear_constraint_id() const {
907 return copyable_data_.linear_constraints.next_id();
908}
909
910void ModelStorage::ensure_next_linear_constraint_id_at_least(
911 LinearConstraintId id) {
912 copyable_data_.linear_constraints.ensure_next_id_at_least(id);
913}
914
915bool ModelStorage::has_linear_constraint(const LinearConstraintId id) const {
916 return copyable_data_.linear_constraints.contains(id);
917}
918
920// Linear Constraint Matrix
922
923double ModelStorage::linear_constraint_coefficient(
924 LinearConstraintId constraint, VariableId variable) const {
925 return copyable_data_.linear_constraints.matrix().get(constraint, variable);
926}
927
928bool ModelStorage::is_linear_constraint_coefficient_nonzero(
929 LinearConstraintId constraint, VariableId variable) const {
930 return copyable_data_.linear_constraints.matrix().contains(constraint,
931 variable);
932}
933
934void ModelStorage::set_linear_constraint_coefficient(
935 const LinearConstraintId constraint, const VariableId variable,
936 const double value) {
937 copyable_data_.linear_constraints.set_term(
938 constraint, variable, value, UpdateAndGetLinearConstraintDiffs());
939}
940
941std::vector<std::tuple<LinearConstraintId, VariableId, double> >
942ModelStorage::linear_constraint_matrix() const {
943 return copyable_data_.linear_constraints.matrix().Terms();
944}
945
946std::vector<VariableId> ModelStorage::variables_in_linear_constraint(
947 LinearConstraintId constraint) const {
948 return copyable_data_.linear_constraints.matrix().row(constraint);
949}
950
951std::vector<LinearConstraintId> ModelStorage::linear_constraints_with_variable(
952 VariableId variable) const {
953 return copyable_data_.linear_constraints.matrix().column(variable);
954}
955
957// Objectives
959
960bool ModelStorage::is_maximize(const ObjectiveId id) const {
961 return copyable_data_.objectives.maximize(id);
962}
963
964int64_t ModelStorage::objective_priority(const ObjectiveId id) const {
965 return copyable_data_.objectives.priority(id);
966}
967
968double ModelStorage::objective_offset(const ObjectiveId id) const {
969 return copyable_data_.objectives.offset(id);
970}
971
972double ModelStorage::linear_objective_coefficient(
973 const ObjectiveId id, const VariableId variable) const {
974 return copyable_data_.objectives.linear_term(id, variable);
975}
976
977double ModelStorage::quadratic_objective_coefficient(
978 const ObjectiveId id, const VariableId first_variable,
979 const VariableId second_variable) const {
980 return copyable_data_.objectives.quadratic_term(id, first_variable,
981 second_variable);
982}
983
984bool ModelStorage::is_linear_objective_coefficient_nonzero(
985 const ObjectiveId id, const VariableId variable) const {
986 return copyable_data_.objectives.linear_terms(id).contains(variable);
987}
988
989bool ModelStorage::is_quadratic_objective_coefficient_nonzero(
990 const ObjectiveId id, const VariableId first_variable,
991 const VariableId second_variable) const {
992 return copyable_data_.objectives.quadratic_terms(id).get(
993 first_variable, second_variable) != 0.0;
994}
995
996const std::string& ModelStorage::objective_name(const ObjectiveId id) const {
997 return copyable_data_.objectives.name(id);
998}
999
1000void ModelStorage::set_is_maximize(const ObjectiveId id,
1001 const bool is_maximize) {
1002 copyable_data_.objectives.set_maximize(id, is_maximize,
1003 UpdateAndGetObjectiveDiffs());
1004}
1005
1006void ModelStorage::set_maximize(const ObjectiveId id) {
1007 set_is_maximize(id, true);
1008}
1009
1010void ModelStorage::set_minimize(const ObjectiveId id) {
1011 set_is_maximize(id, false);
1012}
1013
1014void ModelStorage::set_objective_priority(const ObjectiveId id,
1015 const int64_t value) {
1016 copyable_data_.objectives.set_priority(id, value,
1017 UpdateAndGetObjectiveDiffs());
1018}
1019
1020void ModelStorage::set_objective_offset(const ObjectiveId id,
1021 const double value) {
1022 copyable_data_.objectives.set_offset(id, value, UpdateAndGetObjectiveDiffs());
1023}
1024
1025void ModelStorage::set_linear_objective_coefficient(const ObjectiveId id,
1026 const VariableId variable,
1027 const double value) {
1028 copyable_data_.objectives.set_linear_term(id, variable, value,
1029 UpdateAndGetObjectiveDiffs());
1030}
1031
1032void ModelStorage::set_quadratic_objective_coefficient(
1033 const ObjectiveId id, const VariableId first_variable,
1034 const VariableId second_variable, const double value) {
1035 copyable_data_.objectives.set_quadratic_term(
1036 id, first_variable, second_variable, value, UpdateAndGetObjectiveDiffs());
1037}
1038
1039void ModelStorage::clear_objective(const ObjectiveId id) {
1040 copyable_data_.objectives.Clear(id, UpdateAndGetObjectiveDiffs());
1041}
1042
1043const absl::flat_hash_map<VariableId, double>& ModelStorage::linear_objective(
1044 const ObjectiveId id) const {
1045 return copyable_data_.objectives.linear_terms(id);
1046}
1047
1048int64_t ModelStorage::num_linear_objective_terms(const ObjectiveId id) const {
1049 return copyable_data_.objectives.linear_terms(id).size();
1050}
1051
1052int64_t ModelStorage::num_quadratic_objective_terms(
1053 const ObjectiveId id) const {
1054 return copyable_data_.objectives.quadratic_terms(id).nonzeros();
1055}
1056
1057std::vector<std::tuple<VariableId, VariableId, double> >
1058ModelStorage::quadratic_objective_terms(const ObjectiveId id) const {
1059 return copyable_data_.objectives.quadratic_terms(id).Terms();
1060}
1061
1063// Auxiliary objectives
1065
1066AuxiliaryObjectiveId ModelStorage::AddAuxiliaryObjective(
1067 const int64_t priority, const absl::string_view name) {
1068 return copyable_data_.objectives.AddAuxiliaryObjective(priority, name);
1069}
1070
1071void ModelStorage::DeleteAuxiliaryObjective(const AuxiliaryObjectiveId id) {
1072 copyable_data_.objectives.Delete(id, UpdateAndGetObjectiveDiffs());
1073}
1074
1075int ModelStorage::num_auxiliary_objectives() const {
1076 return static_cast<int>(copyable_data_.objectives.num_auxiliary_objectives());
1077}
1078
1079AuxiliaryObjectiveId ModelStorage::next_auxiliary_objective_id() const {
1080 return copyable_data_.objectives.next_id();
1081}
1082
1083void ModelStorage::ensure_next_auxiliary_objective_id_at_least(
1084 const AuxiliaryObjectiveId id) {
1085 copyable_data_.objectives.ensure_next_id_at_least(id);
1086}
1087
1088bool ModelStorage::has_auxiliary_objective(
1089 const AuxiliaryObjectiveId id) const {
1090 return copyable_data_.objectives.contains(id);
1091}
1092
1093std::vector<AuxiliaryObjectiveId> ModelStorage::AuxiliaryObjectives() const {
1094 return copyable_data_.objectives.AuxiliaryObjectives();
1095}
1096
1097std::vector<AuxiliaryObjectiveId> ModelStorage::SortedAuxiliaryObjectives()
1098 const {
1099 return copyable_data_.objectives.SortedAuxiliaryObjectives();
1100}
1101
1103// Atomic constraint template inline implementations.
1105
1106template <typename ConstraintData>
1107typename ConstraintData::IdType ModelStorage::AddAtomicConstraint(
1108 ConstraintData data) {
1109 return constraint_storage<ConstraintData>().AddConstraint(data);
1110}
1111
1112template <typename IdType>
1113void ModelStorage::DeleteAtomicConstraint(const IdType id) {
1114 using ConstraintData =
1115 typename AtomicConstraintTraits<IdType>::ConstraintData;
1116 auto& storage = constraint_storage<ConstraintData>();
1117 CHECK(storage.contains(id));
1118 storage.Delete(
1119 id,
1120 MakeUpdateDataFieldRange<
1121 UpdateTrackerData::AtomicConstraintDirtyFieldPtr<ConstraintData>()>(
1122 update_trackers_.GetUpdatedTrackers()));
1123}
1124
1125template <typename IdType>
1126const typename AtomicConstraintTraits<IdType>::ConstraintData&
1127ModelStorage::constraint_data(const IdType id) const {
1128 using ConstraintData =
1129 typename AtomicConstraintTraits<IdType>::ConstraintData;
1130 return constraint_storage<ConstraintData>().data(id);
1131}
1132
1133template <typename IdType>
1134int64_t ModelStorage::num_constraints() const {
1135 using ConstraintData =
1136 typename AtomicConstraintTraits<IdType>::ConstraintData;
1137 return constraint_storage<ConstraintData>().size();
1138}
1139
1140template <typename IdType>
1141IdType ModelStorage::next_constraint_id() const {
1142 using ConstraintData =
1143 typename AtomicConstraintTraits<IdType>::ConstraintData;
1144 return constraint_storage<ConstraintData>().next_id();
1145}
1146
1147template <typename IdType>
1148void ModelStorage::ensure_next_constraint_id_at_least(const IdType id) {
1149 using ConstraintData =
1150 typename AtomicConstraintTraits<IdType>::ConstraintData;
1151 return constraint_storage<ConstraintData>().ensure_next_id_at_least(id);
1152}
1153
1154template <typename IdType>
1155bool ModelStorage::has_constraint(const IdType id) const {
1156 using ConstraintData =
1157 typename AtomicConstraintTraits<IdType>::ConstraintData;
1158 return constraint_storage<ConstraintData>().contains(id);
1159}
1160
1161template <typename IdType>
1162std::vector<IdType> ModelStorage::Constraints() const {
1163 using ConstraintData =
1164 typename AtomicConstraintTraits<IdType>::ConstraintData;
1165 return constraint_storage<ConstraintData>().Constraints();
1166}
1167
1168template <typename IdType>
1169std::vector<IdType> ModelStorage::SortedConstraints() const {
1170 using ConstraintData =
1171 typename AtomicConstraintTraits<IdType>::ConstraintData;
1172 return constraint_storage<ConstraintData>().SortedConstraints();
1173}
1174
1175template <typename IdType>
1176std::vector<IdType> ModelStorage::ConstraintsWithVariable(
1177 const VariableId variable_id) const {
1178 using ConstraintData =
1179 typename AtomicConstraintTraits<IdType>::ConstraintData;
1180 const absl::flat_hash_set<IdType> constraints =
1181 constraint_storage<ConstraintData>().RelatedConstraints(variable_id);
1182 return {constraints.begin(), constraints.end()};
1183}
1184
1185template <typename IdType>
1186std::vector<VariableId> ModelStorage::VariablesInConstraint(
1187 const IdType id) const {
1188 return constraint_data(id).RelatedVariables();
1189}
1190
1192// Atomic constraint template specializations.
1194
1195// --------------------------- Quadratic constraints ---------------------------
1196
1197template <>
1198inline AtomicConstraintStorage<QuadraticConstraintData>&
1199ModelStorage::constraint_storage() {
1200 return copyable_data_.quadratic_constraints;
1201}
1202
1203template <>
1204inline const AtomicConstraintStorage<QuadraticConstraintData>&
1205ModelStorage::constraint_storage() const {
1206 return copyable_data_.quadratic_constraints;
1207}
1208
1209template <>
1210constexpr typename AtomicConstraintStorage<QuadraticConstraintData>::Diff
1211 ModelStorage::UpdateTrackerData::*
1212 ModelStorage::UpdateTrackerData::AtomicConstraintDirtyFieldPtr<
1213 QuadraticConstraintData>() {
1214 return &UpdateTrackerData::dirty_quadratic_constraints;
1215}
1216
1217// ----------------------- Second-order cone constraints -----------------------
1218
1219template <>
1220inline AtomicConstraintStorage<SecondOrderConeConstraintData>&
1221ModelStorage::constraint_storage() {
1222 return copyable_data_.soc_constraints;
1223}
1224
1225template <>
1226inline const AtomicConstraintStorage<SecondOrderConeConstraintData>&
1227ModelStorage::constraint_storage() const {
1228 return copyable_data_.soc_constraints;
1229}
1230
1231template <>
1232constexpr typename AtomicConstraintStorage<SecondOrderConeConstraintData>::Diff
1233 ModelStorage::UpdateTrackerData::*
1234 ModelStorage::UpdateTrackerData::AtomicConstraintDirtyFieldPtr<
1235 SecondOrderConeConstraintData>() {
1236 return &UpdateTrackerData::dirty_soc_constraints;
1237}
1238
1239// ----------------------------- SOS1 constraints ------------------------------
1240
1241template <>
1242inline AtomicConstraintStorage<Sos1ConstraintData>&
1243ModelStorage::constraint_storage() {
1244 return copyable_data_.sos1_constraints;
1245}
1246
1247template <>
1248inline const AtomicConstraintStorage<Sos1ConstraintData>&
1249ModelStorage::constraint_storage() const {
1250 return copyable_data_.sos1_constraints;
1251}
1252
1253template <>
1254constexpr typename AtomicConstraintStorage<Sos1ConstraintData>::Diff
1255 ModelStorage::UpdateTrackerData::*
1256 ModelStorage::UpdateTrackerData::AtomicConstraintDirtyFieldPtr<
1258 return &UpdateTrackerData::dirty_sos1_constraints;
1259}
1260
1261// ----------------------------- SOS2 constraints ------------------------------
1262
1263template <>
1264inline AtomicConstraintStorage<Sos2ConstraintData>&
1265ModelStorage::constraint_storage() {
1266 return copyable_data_.sos2_constraints;
1267}
1268
1269template <>
1270inline const AtomicConstraintStorage<Sos2ConstraintData>&
1271ModelStorage::constraint_storage() const {
1272 return copyable_data_.sos2_constraints;
1273}
1274
1275template <>
1276constexpr typename AtomicConstraintStorage<Sos2ConstraintData>::Diff
1277 ModelStorage::UpdateTrackerData::*
1278 ModelStorage::UpdateTrackerData::AtomicConstraintDirtyFieldPtr<
1280 return &UpdateTrackerData::dirty_sos2_constraints;
1281}
1282
1283// --------------------------- Indicator constraints ---------------------------
1284
1285template <>
1286inline AtomicConstraintStorage<IndicatorConstraintData>&
1287ModelStorage::constraint_storage() {
1288 return copyable_data_.indicator_constraints;
1289}
1290
1291template <>
1292inline const AtomicConstraintStorage<IndicatorConstraintData>&
1293ModelStorage::constraint_storage() const {
1294 return copyable_data_.indicator_constraints;
1295}
1296
1297template <>
1298constexpr typename AtomicConstraintStorage<IndicatorConstraintData>::Diff
1299 ModelStorage::UpdateTrackerData::*
1300 ModelStorage::UpdateTrackerData::AtomicConstraintDirtyFieldPtr<
1301 IndicatorConstraintData>() {
1302 return &UpdateTrackerData::dirty_indicator_constraints;
1303}
1304
1305} // namespace math_opt
1306} // namespace operations_research
1307
1308#endif
1309
1311
1312// Aliases for non-nullable and nullable pointers to a `ModelStorage`.
1313// We should mostly be using the former, but in some cases we need the latter.
1314using ModelStoragePtr = absl::Nonnull<ModelStorage*>;
1315using NullableModelStoragePtr = absl::Nullable<ModelStorage*>;
1316using ModelStorageCPtr = absl::Nonnull<const ModelStorage*>;
1317using NullableModelStorageCPtr = absl::Nullable<const ModelStorage*>;
1318
1319} // namespace operations_research::math_opt
1320
1321#endif // OR_TOOLS_MATH_OPT_STORAGE_MODEL_STORAGE_H_
ConstraintData::IdType AddAtomicConstraint(const ConstraintData &data, Elemental &elemental)
An object oriented wrapper for quadratic constraints in ModelStorage.
Definition gurobi_isv.cc:28
absl::Nonnull< const ModelStorage * > ModelStorageCPtr
ElementId< ElementType::kAuxiliaryObjective > AuxiliaryObjectiveId
Definition elements.h:266
internal::SosConstraintData< Sos1ConstraintId > Sos1ConstraintData
Definition storage.h:99
ElementId< ElementType::kVariable > VariableId
Definition elements.h:264
absl::Nonnull< ModelStorage * > ModelStoragePtr
ElementId< ElementType::kLinearConstraint > LinearConstraintId
Definition elements.h:265
auto MakeUpdateDataFieldRange(const UpdateTrackers &trackers)
Definition iterators.h:121
absl::Nullable< ModelStorage * > NullableModelStoragePtr
internal::SosConstraintData< Sos2ConstraintId > Sos2ConstraintData
Definition storage.h:100
absl::Nullable< const ModelStorage * > NullableModelStorageCPtr
In SWIG mode, we don't want anything besides these top-level includes.