Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
model_storage.cc
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
15
16#include <cstdint>
17#include <memory>
18#include <new>
19#include <optional>
20#include <string>
21#include <utility>
22#include <vector>
23
24#include "absl/log/check.h"
25#include "absl/memory/memory.h"
26#include "absl/status/status.h"
27#include "absl/status/statusor.h"
28#include "absl/strings/string_view.h"
29#include "absl/types/span.h"
36#include "ortools/math_opt/model.pb.h"
37#include "ortools/math_opt/model_update.pb.h"
38#include "ortools/math_opt/sparse_containers.pb.h"
44
45namespace operations_research {
46namespace math_opt {
47
48absl::StatusOr<std::unique_ptr<ModelStorage>> ModelStorage::FromModelProto(
49 const ModelProto& model_proto) {
50 // We don't check names since ModelStorage does not do so before exporting
51 // models. Thus a model built by ModelStorage can contain duplicated
52 // names. And since we use FromModelProto() to implement Clone(), we must make
53 // sure duplicated names don't fail.
54 RETURN_IF_ERROR(ValidateModel(model_proto, /*check_names=*/false).status());
55
56 auto storage = std::make_unique<ModelStorage>(model_proto.name(),
57 model_proto.objective().name());
58
59 // Add variables.
60 storage->AddVariables(model_proto.variables());
61
62 // Set the objective.
63 storage->set_is_maximize(kPrimaryObjectiveId,
64 model_proto.objective().maximize());
65 storage->set_objective_offset(kPrimaryObjectiveId,
66 model_proto.objective().offset());
67 storage->UpdateLinearObjectiveCoefficients(
68 kPrimaryObjectiveId, model_proto.objective().linear_coefficients());
69 storage->UpdateQuadraticObjectiveCoefficients(
70 kPrimaryObjectiveId, model_proto.objective().quadratic_coefficients());
71
72 // Set the auxiliary objectives.
73 storage->AddAuxiliaryObjectives(model_proto.auxiliary_objectives());
74
75 // Add linear constraints.
76 storage->AddLinearConstraints(model_proto.linear_constraints());
77
78 // Set the linear constraints coefficients.
79 storage->UpdateLinearConstraintCoefficients(
80 model_proto.linear_constraint_matrix());
81
82 // Add quadratic constraints.
83 storage->copyable_data_.quadratic_constraints.AddConstraints(
84 model_proto.quadratic_constraints());
85
86 // Add SOC constraints.
87 storage->copyable_data_.soc_constraints.AddConstraints(
88 model_proto.second_order_cone_constraints());
89
90 // Add SOS constraints.
91 storage->copyable_data_.sos1_constraints.AddConstraints(
92 model_proto.sos1_constraints());
93 storage->copyable_data_.sos2_constraints.AddConstraints(
94 model_proto.sos2_constraints());
95
96 // Add indicator constraints.
97 storage->copyable_data_.indicator_constraints.AddConstraints(
98 model_proto.indicator_constraints());
99
100 return storage;
101}
102
103void ModelStorage::UpdateObjective(const ObjectiveId id,
104 const ObjectiveUpdatesProto& update) {
105 if (update.has_direction_update()) {
106 set_is_maximize(id, update.direction_update());
107 }
108 if (update.has_priority_update()) {
109 set_objective_priority(id, update.priority_update());
110 }
111 if (update.has_offset_update()) {
112 set_objective_offset(id, update.offset_update());
113 }
114 UpdateLinearObjectiveCoefficients(id, update.linear_coefficients());
115 UpdateQuadraticObjectiveCoefficients(id, update.quadratic_coefficients());
116}
117
118void ModelStorage::UpdateLinearObjectiveCoefficients(
119 const ObjectiveId id, const SparseDoubleVectorProto& coefficients) {
120 for (const auto [var_id, value] : MakeView(coefficients)) {
121 set_linear_objective_coefficient(id, VariableId(var_id), value);
122 }
123}
124
125void ModelStorage::UpdateQuadraticObjectiveCoefficients(
126 const ObjectiveId id, const SparseDoubleMatrixProto& coefficients) {
127 for (int i = 0; i < coefficients.row_ids_size(); ++i) {
128 // This call is valid since this is an upper triangular matrix; there is no
129 // duplicated terms.
130 set_quadratic_objective_coefficient(id, VariableId(coefficients.row_ids(i)),
131 VariableId(coefficients.column_ids(i)),
132 coefficients.coefficients(i));
133 }
134}
135
136void ModelStorage::UpdateLinearConstraintCoefficients(
137 const SparseDoubleMatrixProto& coefficients) {
138 for (int i = 0; i < coefficients.row_ids_size(); ++i) {
139 // This call is valid since there are no duplicated pairs.
140 set_linear_constraint_coefficient(
141 LinearConstraintId(coefficients.row_ids(i)),
142 VariableId(coefficients.column_ids(i)), coefficients.coefficients(i));
143 }
144}
145
146std::unique_ptr<ModelStorage> ModelStorage::Clone(
147 const std::optional<absl::string_view> new_name) const {
148 // We leverage the private copy constructor that copies copyable_data_ but not
149 // update_trackers_ here.
150 std::unique_ptr<ModelStorage> clone =
151 absl::WrapUnique(new ModelStorage(*this));
152 if (new_name.has_value()) {
153 clone->copyable_data_.name = *new_name;
154 }
155 return clone;
156}
157
158VariableId ModelStorage::AddVariable(const double lower_bound,
159 const double upper_bound,
160 const bool is_integer,
161 const absl::string_view name) {
162 return copyable_data_.variables.Add(lower_bound, upper_bound, is_integer,
163 name);
164}
165
166void ModelStorage::AddVariables(const VariablesProto& variables) {
167 const bool has_names = !variables.names().empty();
168 for (int v = 0; v < variables.ids_size(); ++v) {
169 // Make sure the ids of the new Variables in the model match the proto,
170 // which are potentially non-consecutive (note that variables has been
171 // validated).
172 ensure_next_variable_id_at_least(VariableId(variables.ids(v)));
173 AddVariable(variables.lower_bounds(v),
174 /*upper_bound=*/variables.upper_bounds(v),
175 /*is_integer=*/variables.integers(v),
176 has_names ? variables.names(v) : absl::string_view());
177 }
178}
179
180void ModelStorage::DeleteVariable(const VariableId id) {
181 CHECK(copyable_data_.variables.contains(id));
182 const auto& trackers = update_trackers_.GetUpdatedTrackers();
183 // Reuse output of GetUpdatedTrackers() only once to ensure a consistent view,
184 // do not call UpdateAndGetLinearConstraintDiffs() etc.
185 copyable_data_.objectives.DeleteVariable(
186 id,
188 copyable_data_.linear_constraints.DeleteVariable(
189 id,
191 trackers));
192 copyable_data_.quadratic_constraints.DeleteVariable(id);
193 copyable_data_.soc_constraints.DeleteVariable(id);
194 copyable_data_.sos1_constraints.DeleteVariable(id);
195 copyable_data_.sos2_constraints.DeleteVariable(id);
196 copyable_data_.indicator_constraints.DeleteVariable(id);
197 copyable_data_.variables.Delete(
198 id,
200}
201
202std::vector<VariableId> ModelStorage::variables() const {
203 return copyable_data_.variables.Variables();
204}
205
206std::vector<VariableId> ModelStorage::SortedVariables() const {
207 return copyable_data_.variables.SortedVariables();
208}
209
210LinearConstraintId ModelStorage::AddLinearConstraint(
211 const double lower_bound, const double upper_bound,
212 const absl::string_view name) {
213 return copyable_data_.linear_constraints.Add(lower_bound, upper_bound, name);
214}
215
216void ModelStorage::AddLinearConstraints(
217 const LinearConstraintsProto& linear_constraints) {
218 const bool has_names = !linear_constraints.names().empty();
219 for (int c = 0; c < linear_constraints.ids_size(); ++c) {
220 // Make sure the ids of the new linear constraints in the model match the
221 // proto, which are potentially non-consecutive (note that
222 // linear_constraints has been validated).
223 ensure_next_linear_constraint_id_at_least(
224 LinearConstraintId(linear_constraints.ids(c)));
225 // This call is valid since ids are unique and increasing.
226 AddLinearConstraint(
227 /*lower_bound=*/linear_constraints.lower_bounds(c),
228 /*upper_bound=*/linear_constraints.upper_bounds(c),
229 has_names ? linear_constraints.names(c) : absl::string_view());
230 }
231}
232
233void ModelStorage::DeleteLinearConstraint(const LinearConstraintId id) {
234 CHECK(copyable_data_.linear_constraints.contains(id));
235 copyable_data_.linear_constraints.Delete(id,
236 UpdateAndGetLinearConstraintDiffs());
237}
238
239std::vector<LinearConstraintId> ModelStorage::LinearConstraints() const {
240 return copyable_data_.linear_constraints.LinearConstraints();
241}
242
243std::vector<LinearConstraintId> ModelStorage::SortedLinearConstraints() const {
244 return copyable_data_.linear_constraints.SortedLinearConstraints();
245}
246
247void ModelStorage::AddAuxiliaryObjectives(
248 const google::protobuf::Map<int64_t, ObjectiveProto>& objectives) {
249 for (const int64_t raw_id : SortedMapKeys(objectives)) {
250 const AuxiliaryObjectiveId id = AuxiliaryObjectiveId(raw_id);
251 ensure_next_auxiliary_objective_id_at_least(id);
252 const ObjectiveProto& proto = objectives.at(raw_id);
253 AddAuxiliaryObjective(proto.priority(), proto.name());
254 set_is_maximize(id, proto.maximize());
255 set_objective_offset(id, proto.offset());
256 for (const auto [raw_var_id, coeff] :
257 MakeView(proto.linear_coefficients())) {
258 set_linear_objective_coefficient(id, VariableId(raw_var_id), coeff);
259 }
260 }
261}
262
263// TODO: b/315974557 - Return an error if any of the Proto() methods called
264// tries to create a very long RepeatedField.
265ModelProto ModelStorage::ExportModel(const bool remove_names) const {
266 ModelProto result;
267 result.set_name(copyable_data_.name);
268 *result.mutable_variables() = copyable_data_.variables.Proto();
269 {
270 auto [primary, auxiliary] = copyable_data_.objectives.Proto();
271 *result.mutable_objective() = std::move(primary);
272 *result.mutable_auxiliary_objectives() = std::move(auxiliary);
273 }
274 {
275 auto [constraints, matrix] = copyable_data_.linear_constraints.Proto();
276 *result.mutable_linear_constraints() = std::move(constraints);
277 *result.mutable_linear_constraint_matrix() = std::move(matrix);
278 }
279 *result.mutable_quadratic_constraints() =
280 copyable_data_.quadratic_constraints.Proto();
281 *result.mutable_second_order_cone_constraints() =
282 copyable_data_.soc_constraints.Proto();
283 *result.mutable_sos1_constraints() = copyable_data_.sos1_constraints.Proto();
284 *result.mutable_sos2_constraints() = copyable_data_.sos2_constraints.Proto();
285 *result.mutable_indicator_constraints() =
286 copyable_data_.indicator_constraints.Proto();
287 // Performance can be improved when remove_names is true by just not
288 // extracting the names above instead of clearing them below, but this will
289 // be more code, see discussion on cl/549469633 and prototype in cl/549369764.
290 if (remove_names) {
291 RemoveNames(result);
292 }
293 return result;
294}
295
296std::optional<ModelUpdateProto>
297ModelStorage::UpdateTrackerData::ExportModelUpdate(
298 const ModelStorage& storage, const bool remove_names) const {
299 // We must detect the empty case to prevent unneeded copies and merging in
300 // ExportModelUpdate().
301
302 if (storage.copyable_data_.variables.diff_is_empty(dirty_variables) &&
303 storage.copyable_data_.objectives.diff_is_empty(dirty_objective) &&
304 storage.copyable_data_.linear_constraints.diff_is_empty(
305 dirty_linear_constraints) &&
306 storage.copyable_data_.quadratic_constraints.diff_is_empty(
307 dirty_quadratic_constraints) &&
308 storage.copyable_data_.soc_constraints.diff_is_empty(
309 dirty_soc_constraints) &&
310 storage.copyable_data_.sos1_constraints.diff_is_empty(
311 dirty_sos1_constraints) &&
312 storage.copyable_data_.sos2_constraints.diff_is_empty(
313 dirty_sos2_constraints) &&
314 storage.copyable_data_.indicator_constraints.diff_is_empty(
315 dirty_indicator_constraints)) {
316 return std::nullopt;
317 }
318
319 ModelUpdateProto result;
320
321 // Variable/constraint deletions.
322 {
323 VariableStorage::UpdateResult variable_update =
324 storage.copyable_data_.variables.Update(dirty_variables);
325 *result.mutable_deleted_variable_ids() = std::move(variable_update.deleted);
326 *result.mutable_variable_updates() = std::move(variable_update.updates);
327 *result.mutable_new_variables() = std::move(variable_update.creates);
328 }
329 const std::vector<VariableId> new_variables =
330 storage.copyable_data_.variables.VariablesFrom(
331 dirty_variables.checkpoint);
332
333 // Linear constraint updates
334 {
336 storage.copyable_data_.linear_constraints.Update(
337 dirty_linear_constraints, dirty_variables.deleted, new_variables);
338 *result.mutable_deleted_linear_constraint_ids() =
339 std::move(lin_con_update.deleted);
340 *result.mutable_linear_constraint_updates() =
341 std::move(lin_con_update.updates);
342 *result.mutable_new_linear_constraints() =
343 std::move(lin_con_update.creates);
344 *result.mutable_linear_constraint_matrix_updates() =
345 std::move(lin_con_update.matrix_updates);
346 }
347
348 // Quadratic constraint updates
349 *result.mutable_quadratic_constraint_updates() =
350 storage.copyable_data_.quadratic_constraints.Update(
351 dirty_quadratic_constraints);
352
353 // Second-order cone constraint updates
354 *result.mutable_second_order_cone_constraint_updates() =
355 storage.copyable_data_.soc_constraints.Update(dirty_soc_constraints);
356
357 // SOS constraint updates
358 *result.mutable_sos1_constraint_updates() =
359 storage.copyable_data_.sos1_constraints.Update(dirty_sos1_constraints);
360 *result.mutable_sos2_constraint_updates() =
361 storage.copyable_data_.sos2_constraints.Update(dirty_sos2_constraints);
362
363 // Indicator constraint updates
364 *result.mutable_indicator_constraint_updates() =
365 storage.copyable_data_.indicator_constraints.Update(
366 dirty_indicator_constraints);
367
368 // Update the objective
369 {
370 auto [primary, auxiliary] = storage.copyable_data_.objectives.Update(
371 dirty_objective, dirty_variables.deleted, new_variables);
372 *result.mutable_objective_updates() = std::move(primary);
373 *result.mutable_auxiliary_objectives_updates() = std::move(auxiliary);
374 }
375 if (remove_names) {
376 RemoveNames(result);
377 }
378 // Note: Named returned value optimization (NRVO) does not apply here.
379 return {std::move(result)};
380}
381
382void ModelStorage::UpdateTrackerData::AdvanceCheckpoint(
383 const ModelStorage& storage) {
384 storage.copyable_data_.variables.AdvanceCheckpointInDiff(dirty_variables);
385 storage.copyable_data_.objectives.AdvanceCheckpointInDiff(
386 dirty_variables.checkpoint, dirty_objective);
387 storage.copyable_data_.linear_constraints.AdvanceCheckpointInDiff(
388 dirty_variables.checkpoint, dirty_linear_constraints);
389 storage.copyable_data_.quadratic_constraints.AdvanceCheckpointInDiff(
390 dirty_quadratic_constraints);
391 storage.copyable_data_.soc_constraints.AdvanceCheckpointInDiff(
392 dirty_soc_constraints);
393 storage.copyable_data_.sos1_constraints.AdvanceCheckpointInDiff(
394 dirty_sos1_constraints);
395 storage.copyable_data_.sos2_constraints.AdvanceCheckpointInDiff(
396 dirty_sos2_constraints);
397 storage.copyable_data_.indicator_constraints.AdvanceCheckpointInDiff(
398 dirty_indicator_constraints);
399}
400
401UpdateTrackerId ModelStorage::NewUpdateTracker() {
402 return update_trackers_.NewUpdateTracker(
403 copyable_data_.variables, copyable_data_.objectives,
404 copyable_data_.linear_constraints, copyable_data_.quadratic_constraints,
405 copyable_data_.soc_constraints, copyable_data_.sos1_constraints,
406 copyable_data_.sos2_constraints, copyable_data_.indicator_constraints);
407}
408
409void ModelStorage::DeleteUpdateTracker(const UpdateTrackerId update_tracker) {
410 update_trackers_.DeleteUpdateTracker(update_tracker);
411}
412
413std::optional<ModelUpdateProto> ModelStorage::ExportModelUpdate(
414 const UpdateTrackerId update_tracker, const bool remove_names) const {
415 return update_trackers_.GetData(update_tracker)
416 .ExportModelUpdate(*this, remove_names);
417}
418
419void ModelStorage::AdvanceCheckpoint(UpdateTrackerId update_tracker) {
420 update_trackers_.GetData(update_tracker).AdvanceCheckpoint(*this);
421}
422
423absl::Status ModelStorage::ApplyUpdateProto(
424 const ModelUpdateProto& update_proto) {
425 // Check the update first.
426 {
427 // Do not check for duplicate names, as with FromModelProto();
428 ModelSummary summary(/*check_names=*/false);
429 // IdNameBiMap requires Insert() calls to be in sorted id order.
430 for (const VariableId id : SortedVariables()) {
431 RETURN_IF_ERROR(summary.variables.Insert(id.value(), variable_name(id)))
432 << "invalid variable id in model";
433 }
434 RETURN_IF_ERROR(summary.variables.SetNextFreeId(
435 copyable_data_.variables.next_id().value()));
436 for (const AuxiliaryObjectiveId id : SortedAuxiliaryObjectives()) {
438 summary.auxiliary_objectives.Insert(id.value(), objective_name(id)))
439 << "invalid auxiliary objective id in model";
440 }
441 RETURN_IF_ERROR(summary.auxiliary_objectives.SetNextFreeId(
442 copyable_data_.objectives.next_id().value()));
443 for (const LinearConstraintId id : SortedLinearConstraints()) {
444 RETURN_IF_ERROR(summary.linear_constraints.Insert(
445 id.value(), linear_constraint_name(id)))
446 << "invalid linear constraint id in model";
447 }
448 RETURN_IF_ERROR(summary.linear_constraints.SetNextFreeId(
449 copyable_data_.linear_constraints.next_id().value()));
450 for (const auto id : SortedConstraints<QuadraticConstraintId>()) {
451 RETURN_IF_ERROR(summary.quadratic_constraints.Insert(
452 id.value(), copyable_data_.quadratic_constraints.data(id).name))
453 << "invalid quadratic constraint id in model";
454 }
455 RETURN_IF_ERROR(summary.quadratic_constraints.SetNextFreeId(
456 copyable_data_.quadratic_constraints.next_id().value()));
457 for (const auto id : SortedConstraints<SecondOrderConeConstraintId>()) {
458 RETURN_IF_ERROR(summary.second_order_cone_constraints.Insert(
459 id.value(), copyable_data_.soc_constraints.data(id).name))
460 << "invalid second-order cone constraint id in model";
461 }
462 RETURN_IF_ERROR(summary.second_order_cone_constraints.SetNextFreeId(
463 copyable_data_.soc_constraints.next_id().value()));
464 for (const Sos1ConstraintId id : SortedConstraints<Sos1ConstraintId>()) {
465 RETURN_IF_ERROR(summary.sos1_constraints.Insert(
466 id.value(), constraint_data(id).name()))
467 << "invalid SOS1 constraint id in model";
468 }
469 RETURN_IF_ERROR(summary.sos1_constraints.SetNextFreeId(
470 copyable_data_.sos1_constraints.next_id().value()));
471 for (const Sos2ConstraintId id : SortedConstraints<Sos2ConstraintId>()) {
472 RETURN_IF_ERROR(summary.sos2_constraints.Insert(
473 id.value(), constraint_data(id).name()))
474 << "invalid SOS2 constraint id in model";
475 }
476 RETURN_IF_ERROR(summary.sos2_constraints.SetNextFreeId(
477 copyable_data_.sos2_constraints.next_id().value()));
478
479 for (const IndicatorConstraintId id :
480 SortedConstraints<IndicatorConstraintId>()) {
481 RETURN_IF_ERROR(summary.indicator_constraints.Insert(
482 id.value(), constraint_data(id).name));
483 }
484 RETURN_IF_ERROR(summary.indicator_constraints.SetNextFreeId(
485 copyable_data_.indicator_constraints.next_id().value()));
486
487 RETURN_IF_ERROR(ValidateModelUpdate(update_proto, summary))
488 << "update not valid";
489 }
490
491 // Remove deleted variables and constraints.
492 for (const int64_t v_id : update_proto.deleted_variable_ids()) {
493 DeleteVariable(VariableId(v_id));
494 }
495 for (const int64_t o_id :
496 update_proto.auxiliary_objectives_updates().deleted_objective_ids()) {
497 DeleteAuxiliaryObjective(AuxiliaryObjectiveId(o_id));
498 }
499 for (const int64_t c_id : update_proto.deleted_linear_constraint_ids()) {
500 DeleteLinearConstraint(LinearConstraintId(c_id));
501 }
502 for (const int64_t c_id :
503 update_proto.quadratic_constraint_updates().deleted_constraint_ids()) {
504 DeleteAtomicConstraint(QuadraticConstraintId(c_id));
505 }
506 for (const int64_t c_id : update_proto.second_order_cone_constraint_updates()
507 .deleted_constraint_ids()) {
508 DeleteAtomicConstraint(SecondOrderConeConstraintId(c_id));
509 }
510 for (const int64_t c_id :
511 update_proto.sos1_constraint_updates().deleted_constraint_ids()) {
512 DeleteAtomicConstraint(Sos1ConstraintId(c_id));
513 }
514 for (const int64_t c_id :
515 update_proto.sos2_constraint_updates().deleted_constraint_ids()) {
516 DeleteAtomicConstraint(Sos2ConstraintId(c_id));
517 }
518 for (const int64_t c_id :
519 update_proto.indicator_constraint_updates().deleted_constraint_ids()) {
520 DeleteAtomicConstraint(IndicatorConstraintId(c_id));
521 }
522
523 // Update existing variables' properties.
524 for (const auto [v_id, lb] :
525 MakeView(update_proto.variable_updates().lower_bounds())) {
526 set_variable_lower_bound(VariableId(v_id), lb);
527 }
528 for (const auto [v_id, ub] :
529 MakeView(update_proto.variable_updates().upper_bounds())) {
530 set_variable_upper_bound(VariableId(v_id), ub);
531 }
532 for (const auto [v_id, is_integer] :
533 MakeView(update_proto.variable_updates().integers())) {
534 set_variable_is_integer(VariableId(v_id), is_integer);
535 }
536
537 // Update existing constraints' properties.
538 for (const auto [c_id, lb] :
539 MakeView(update_proto.linear_constraint_updates().lower_bounds())) {
540 set_linear_constraint_lower_bound(LinearConstraintId(c_id), lb);
541 }
542 for (const auto [c_id, ub] :
543 MakeView(update_proto.linear_constraint_updates().upper_bounds())) {
544 set_linear_constraint_upper_bound(LinearConstraintId(c_id), ub);
545 }
546
547 // Add the new variables and constraints.
548 AddVariables(update_proto.new_variables());
549 AddAuxiliaryObjectives(
550 update_proto.auxiliary_objectives_updates().new_objectives());
551 AddLinearConstraints(update_proto.new_linear_constraints());
552 copyable_data_.quadratic_constraints.AddConstraints(
553 update_proto.quadratic_constraint_updates().new_constraints());
554 copyable_data_.soc_constraints.AddConstraints(
555 update_proto.second_order_cone_constraint_updates().new_constraints());
556 copyable_data_.sos1_constraints.AddConstraints(
557 update_proto.sos1_constraint_updates().new_constraints());
558 copyable_data_.sos2_constraints.AddConstraints(
559 update_proto.sos2_constraint_updates().new_constraints());
560 copyable_data_.indicator_constraints.AddConstraints(
561 update_proto.indicator_constraint_updates().new_constraints());
562
563 // Update the primary objective.
564 UpdateObjective(kPrimaryObjectiveId, update_proto.objective_updates());
565
566 // Update the auxiliary objectives.
567 for (const auto& [raw_id, objective_update] :
568 update_proto.auxiliary_objectives_updates().objective_updates()) {
569 UpdateObjective(AuxiliaryObjectiveId(raw_id), objective_update);
570 }
571
572 // Update the linear constraints' coefficients.
573 UpdateLinearConstraintCoefficients(
574 update_proto.linear_constraint_matrix_updates());
575
576 return absl::OkStatus();
577}
578
579} // namespace math_opt
580} // namespace operations_research
#define RETURN_IF_ERROR(expr)
An object oriented wrapper for quadratic constraints in ModelStorage.
Definition gurobi_isv.cc:28
absl::Status ValidateModelUpdate(const ModelUpdateProto &model_update, ModelSummary &model_summary)
constexpr ObjectiveId kPrimaryObjectiveId
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
auto MakeUpdateDataFieldRange(const UpdateTrackers &trackers)
Definition iterators.h:121
void RemoveNames(ModelProto &model)
Removes the model, variables and constraints names of the provided model.
std::optional< AuxiliaryObjectiveId > ObjectiveId
nullopt denotes the primary objective.
std::vector< K > SortedMapKeys(const absl::flat_hash_map< K, V > &in_map)
Definition sorted.h:55
absl::StatusOr< ModelSummary > ValidateModel(const ModelProto &model, const bool check_names)
In SWIG mode, we don't want anything besides these top-level includes.