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