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