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