24#include "absl/base/nullability.h"
25#include "absl/log/check.h"
26#include "absl/memory/memory.h"
27#include "absl/status/status.h"
28#include "absl/status/statusor.h"
29#include "absl/strings/string_view.h"
30#include "absl/types/span.h"
49absl::StatusOr<absl::Nonnull<std::unique_ptr<ModelStorage>>>
50ModelStorage::FromModelProto(
const ModelProto& model_proto) {
57 auto storage = std::make_unique<ModelStorage>(model_proto.name(),
58 model_proto.objective().name());
61 storage->AddVariables(model_proto.variables());
65 model_proto.objective().maximize());
67 model_proto.objective().offset());
68 storage->UpdateLinearObjectiveCoefficients(
70 storage->UpdateQuadraticObjectiveCoefficients(
74 storage->AddAuxiliaryObjectives(model_proto.auxiliary_objectives());
77 storage->AddLinearConstraints(model_proto.linear_constraints());
80 storage->UpdateLinearConstraintCoefficients(
81 model_proto.linear_constraint_matrix());
84 storage->copyable_data_.quadratic_constraints.AddConstraints(
85 model_proto.quadratic_constraints());
88 storage->copyable_data_.soc_constraints.AddConstraints(
89 model_proto.second_order_cone_constraints());
92 storage->copyable_data_.sos1_constraints.AddConstraints(
93 model_proto.sos1_constraints());
94 storage->copyable_data_.sos2_constraints.AddConstraints(
95 model_proto.sos2_constraints());
98 storage->copyable_data_.indicator_constraints.AddConstraints(
99 model_proto.indicator_constraints());
104void ModelStorage::UpdateObjective(
const ObjectiveId id,
106 if (update.has_direction_update()) {
107 set_is_maximize(
id, update.direction_update());
109 if (update.has_priority_update()) {
110 set_objective_priority(
id, update.priority_update());
112 if (update.has_offset_update()) {
113 set_objective_offset(
id, update.offset_update());
115 UpdateLinearObjectiveCoefficients(
id, update.linear_coefficients());
116 UpdateQuadraticObjectiveCoefficients(
id, update.quadratic_coefficients());
119void ModelStorage::UpdateLinearObjectiveCoefficients(
121 for (
const auto [var_id, value] :
MakeView(coefficients)) {
122 set_linear_objective_coefficient(
id,
VariableId(var_id), value);
126void ModelStorage::UpdateQuadraticObjectiveCoefficients(
128 for (
int i = 0;
i < coefficients.row_ids_size(); ++
i) {
131 set_quadratic_objective_coefficient(
id,
VariableId(coefficients.row_ids(i)),
133 coefficients.coefficients(i));
137void ModelStorage::UpdateLinearConstraintCoefficients(
139 for (
int i = 0;
i < coefficients.row_ids_size(); ++
i) {
141 set_linear_constraint_coefficient(
143 VariableId(coefficients.column_ids(i)), coefficients.coefficients(i));
147absl::Nonnull<std::unique_ptr<ModelStorage>> ModelStorage::Clone(
148 const std::optional<absl::string_view> new_name)
const {
151 std::unique_ptr<ModelStorage> clone =
152 absl::WrapUnique(
new ModelStorage(*
this));
153 if (new_name.has_value()) {
154 clone->copyable_data_.name = *new_name;
159VariableId ModelStorage::AddVariable(
const double lower_bound,
160 const double upper_bound,
161 const bool is_integer,
162 const absl::string_view name) {
163 return copyable_data_.variables.Add(lower_bound, upper_bound, is_integer,
168 const bool has_names = !variables.names().empty();
169 for (
int v = 0; v < variables.ids_size(); ++v) {
173 ensure_next_variable_id_at_least(
VariableId(variables.ids(v)));
174 AddVariable(variables.lower_bounds(v),
175 variables.upper_bounds(v),
176 variables.integers(v),
177 has_names ? variables.names(v) : absl::string_view());
181void ModelStorage::DeleteVariable(
const VariableId id) {
182 CHECK(copyable_data_.variables.contains(
id));
183 const auto& trackers = update_trackers_.GetUpdatedTrackers();
186 copyable_data_.objectives.DeleteVariable(
189 copyable_data_.linear_constraints.DeleteVariable(
193 copyable_data_.quadratic_constraints.DeleteVariable(
id);
194 copyable_data_.soc_constraints.DeleteVariable(
id);
195 copyable_data_.sos1_constraints.DeleteVariable(
id);
196 copyable_data_.sos2_constraints.DeleteVariable(
id);
197 copyable_data_.indicator_constraints.DeleteVariable(
id);
198 copyable_data_.variables.Delete(
203std::vector<VariableId> ModelStorage::variables()
const {
204 return copyable_data_.variables.Variables();
207std::vector<VariableId> ModelStorage::SortedVariables()
const {
208 return copyable_data_.variables.SortedVariables();
212 const double lower_bound,
const double upper_bound,
213 const absl::string_view name) {
214 return copyable_data_.linear_constraints.Add(lower_bound, upper_bound, name);
217void ModelStorage::AddLinearConstraints(
219 const bool has_names = !linear_constraints.names().empty();
220 for (
int c = 0;
c < linear_constraints.ids_size(); ++
c) {
224 ensure_next_linear_constraint_id_at_least(
228 linear_constraints.lower_bounds(
c),
229 linear_constraints.upper_bounds(
c),
230 has_names ? linear_constraints.names(
c) : absl::string_view());
235 CHECK(copyable_data_.linear_constraints.contains(
id));
236 copyable_data_.linear_constraints.Delete(
id,
237 UpdateAndGetLinearConstraintDiffs());
240std::vector<LinearConstraintId> ModelStorage::LinearConstraints()
const {
241 return copyable_data_.linear_constraints.LinearConstraints();
244std::vector<LinearConstraintId> ModelStorage::SortedLinearConstraints()
const {
245 return copyable_data_.linear_constraints.SortedLinearConstraints();
248void ModelStorage::AddAuxiliaryObjectives(
249 const google::protobuf::Map<int64_t, ObjectiveProto>& objectives) {
252 ensure_next_auxiliary_objective_id_at_least(
id);
254 AddAuxiliaryObjective(proto.priority(), proto.name());
255 set_is_maximize(
id, proto.maximize());
256 set_objective_offset(
id, proto.offset());
257 for (
const auto [raw_var_id, coeff] :
258 MakeView(proto.linear_coefficients())) {
259 set_linear_objective_coefficient(
id,
VariableId(raw_var_id), coeff);
266ModelProto ModelStorage::ExportModel(
const bool remove_names)
const {
268 result.
set_name(copyable_data_.name);
269 *result.mutable_variables() = copyable_data_.variables.Proto();
271 auto [primary, auxiliary] = copyable_data_.objectives.Proto();
272 *result.mutable_objective() = std::move(primary);
273 *result.mutable_auxiliary_objectives() = std::move(auxiliary);
276 auto [constraints, matrix] = copyable_data_.linear_constraints.Proto();
277 *result.mutable_linear_constraints() = std::move(constraints);
278 *result.mutable_linear_constraint_matrix() = std::move(matrix);
280 *result.mutable_quadratic_constraints() =
281 copyable_data_.quadratic_constraints.Proto();
282 *result.mutable_second_order_cone_constraints() =
283 copyable_data_.soc_constraints.Proto();
284 *result.mutable_sos1_constraints() = copyable_data_.sos1_constraints.Proto();
285 *result.mutable_sos2_constraints() = copyable_data_.sos2_constraints.Proto();
286 *result.mutable_indicator_constraints() =
287 copyable_data_.indicator_constraints.Proto();
297std::optional<ModelUpdateProto>
298ModelStorage::UpdateTrackerData::ExportModelUpdate(
299 const ModelStorage& storage,
const bool remove_names)
const {
303 if (storage.copyable_data_.variables.diff_is_empty(dirty_variables) &&
304 storage.copyable_data_.objectives.diff_is_empty(dirty_objective) &&
305 storage.copyable_data_.linear_constraints.diff_is_empty(
306 dirty_linear_constraints) &&
307 storage.copyable_data_.quadratic_constraints.diff_is_empty(
308 dirty_quadratic_constraints) &&
309 storage.copyable_data_.soc_constraints.diff_is_empty(
310 dirty_soc_constraints) &&
311 storage.copyable_data_.sos1_constraints.diff_is_empty(
312 dirty_sos1_constraints) &&
313 storage.copyable_data_.sos2_constraints.diff_is_empty(
314 dirty_sos2_constraints) &&
315 storage.copyable_data_.indicator_constraints.diff_is_empty(
316 dirty_indicator_constraints)) {
325 storage.copyable_data_.variables.Update(dirty_variables);
326 *result.mutable_deleted_variable_ids() = std::move(variable_update.deleted);
327 *result.mutable_variable_updates() = std::move(variable_update.updates);
328 *result.mutable_new_variables() = std::move(variable_update.creates);
330 const std::vector<VariableId> new_variables =
331 storage.copyable_data_.variables.VariablesFrom(
332 dirty_variables.checkpoint);
337 storage.copyable_data_.linear_constraints.Update(
338 dirty_linear_constraints, dirty_variables.deleted, new_variables);
339 *result.mutable_deleted_linear_constraint_ids() =
340 std::move(lin_con_update.deleted);
341 *result.mutable_linear_constraint_updates() =
342 std::move(lin_con_update.updates);
343 *result.mutable_new_linear_constraints() =
344 std::move(lin_con_update.creates);
345 *result.mutable_linear_constraint_matrix_updates() =
346 std::move(lin_con_update.matrix_updates);
351 storage.copyable_data_.quadratic_constraints.Update(
352 dirty_quadratic_constraints);
355 *result.mutable_second_order_cone_constraint_updates() =
356 storage.copyable_data_.soc_constraints.Update(dirty_soc_constraints);
359 *result.mutable_sos1_constraint_updates() =
360 storage.copyable_data_.sos1_constraints.Update(dirty_sos1_constraints);
361 *result.mutable_sos2_constraint_updates() =
362 storage.copyable_data_.sos2_constraints.Update(dirty_sos2_constraints);
365 *result.mutable_indicator_constraint_updates() =
366 storage.copyable_data_.indicator_constraints.Update(
367 dirty_indicator_constraints);
371 auto [primary, auxiliary] = storage.copyable_data_.objectives.Update(
372 dirty_objective, dirty_variables.deleted, new_variables);
373 *result.mutable_objective_updates() = std::move(primary);
374 *result.mutable_auxiliary_objectives_updates() = std::move(auxiliary);
380 return {std::move(result)};
383void ModelStorage::UpdateTrackerData::AdvanceCheckpoint(
384 const ModelStorage& storage) {
385 storage.copyable_data_.variables.AdvanceCheckpointInDiff(dirty_variables);
386 storage.copyable_data_.objectives.AdvanceCheckpointInDiff(
387 dirty_variables.checkpoint, dirty_objective);
388 storage.copyable_data_.linear_constraints.AdvanceCheckpointInDiff(
389 dirty_variables.checkpoint, dirty_linear_constraints);
390 storage.copyable_data_.quadratic_constraints.AdvanceCheckpointInDiff(
391 dirty_quadratic_constraints);
392 storage.copyable_data_.soc_constraints.AdvanceCheckpointInDiff(
393 dirty_soc_constraints);
394 storage.copyable_data_.sos1_constraints.AdvanceCheckpointInDiff(
395 dirty_sos1_constraints);
396 storage.copyable_data_.sos2_constraints.AdvanceCheckpointInDiff(
397 dirty_sos2_constraints);
398 storage.copyable_data_.indicator_constraints.AdvanceCheckpointInDiff(
399 dirty_indicator_constraints);
402UpdateTrackerId ModelStorage::NewUpdateTracker() {
403 return update_trackers_.NewUpdateTracker(
404 copyable_data_.variables, copyable_data_.objectives,
405 copyable_data_.linear_constraints, copyable_data_.quadratic_constraints,
406 copyable_data_.soc_constraints, copyable_data_.sos1_constraints,
407 copyable_data_.sos2_constraints, copyable_data_.indicator_constraints);
410void ModelStorage::DeleteUpdateTracker(
const UpdateTrackerId update_tracker) {
411 update_trackers_.DeleteUpdateTracker(update_tracker);
414std::optional<ModelUpdateProto> ModelStorage::ExportModelUpdate(
415 const UpdateTrackerId update_tracker,
const bool remove_names)
const {
416 return update_trackers_.GetData(update_tracker)
417 .ExportModelUpdate(*
this, remove_names);
420void ModelStorage::AdvanceCheckpoint(UpdateTrackerId update_tracker) {
421 update_trackers_.GetData(update_tracker).AdvanceCheckpoint(*
this);
424absl::Status ModelStorage::ApplyUpdateProto(
431 for (
const VariableId id : SortedVariables()) {
432 RETURN_IF_ERROR(summary.variables.Insert(
id.value(), variable_name(
id)))
433 <<
"invalid variable id in model";
436 copyable_data_.variables.next_id().value()));
439 summary.auxiliary_objectives.Insert(
id.value(), objective_name(
id)))
440 <<
"invalid auxiliary objective id in model";
443 copyable_data_.objectives.next_id().value()));
446 id.value(), linear_constraint_name(
id)))
447 <<
"invalid linear constraint id in model";
450 copyable_data_.linear_constraints.next_id().value()));
451 for (
const auto id : SortedConstraints<QuadraticConstraintId>()) {
453 id.value(), copyable_data_.quadratic_constraints.data(
id).name))
454 <<
"invalid quadratic constraint id in model";
457 copyable_data_.quadratic_constraints.next_id().value()));
458 for (
const auto id : SortedConstraints<SecondOrderConeConstraintId>()) {
460 id.value(), copyable_data_.soc_constraints.data(
id).name))
461 <<
"invalid second-order cone constraint id in model";
464 copyable_data_.soc_constraints.next_id().value()));
465 for (
const Sos1ConstraintId
id : SortedConstraints<Sos1ConstraintId>()) {
467 id.value(), constraint_data(
id).name()))
468 <<
"invalid SOS1 constraint id in model";
471 copyable_data_.sos1_constraints.next_id().value()));
472 for (
const Sos2ConstraintId
id : SortedConstraints<Sos2ConstraintId>()) {
474 id.value(), constraint_data(
id).name()))
475 <<
"invalid SOS2 constraint id in model";
478 copyable_data_.sos2_constraints.next_id().value()));
481 SortedConstraints<IndicatorConstraintId>()) {
483 id.value(), constraint_data(
id).name));
486 copyable_data_.indicator_constraints.next_id().value()));
489 <<
"update not valid";
493 for (
const int64_t v_id : update_proto.deleted_variable_ids()) {
496 for (
const int64_t o_id :
497 update_proto.auxiliary_objectives_updates().deleted_objective_ids()) {
500 for (
const int64_t c_id : update_proto.deleted_linear_constraint_ids()) {
503 for (
const int64_t c_id :
504 update_proto.quadratic_constraint_updates().deleted_constraint_ids()) {
507 for (
const int64_t c_id : update_proto.second_order_cone_constraint_updates()
508 .deleted_constraint_ids()) {
509 DeleteAtomicConstraint(SecondOrderConeConstraintId(c_id));
511 for (
const int64_t c_id :
512 update_proto.sos1_constraint_updates().deleted_constraint_ids()) {
513 DeleteAtomicConstraint(Sos1ConstraintId(c_id));
515 for (
const int64_t c_id :
516 update_proto.sos2_constraint_updates().deleted_constraint_ids()) {
517 DeleteAtomicConstraint(Sos2ConstraintId(c_id));
519 for (
const int64_t c_id :
520 update_proto.indicator_constraint_updates().deleted_constraint_ids()) {
525 for (
const auto [v_id, lb] :
526 MakeView(update_proto.variable_updates().lower_bounds())) {
527 set_variable_lower_bound(
VariableId(v_id), lb);
529 for (
const auto [v_id, ub] :
530 MakeView(update_proto.variable_updates().upper_bounds())) {
531 set_variable_upper_bound(
VariableId(v_id), ub);
533 for (
const auto [v_id, is_integer] :
534 MakeView(update_proto.variable_updates().integers())) {
535 set_variable_is_integer(
VariableId(v_id), is_integer);
539 for (
const auto [c_id, lb] :
540 MakeView(update_proto.linear_constraint_updates().lower_bounds())) {
543 for (
const auto [c_id, ub] :
544 MakeView(update_proto.linear_constraint_updates().upper_bounds())) {
549 AddVariables(update_proto.new_variables());
550 AddAuxiliaryObjectives(
551 update_proto.auxiliary_objectives_updates().new_objectives());
552 AddLinearConstraints(update_proto.new_linear_constraints());
553 copyable_data_.quadratic_constraints.AddConstraints(
554 update_proto.quadratic_constraint_updates().new_constraints());
555 copyable_data_.soc_constraints.AddConstraints(
556 update_proto.second_order_cone_constraint_updates().new_constraints());
557 copyable_data_.sos1_constraints.AddConstraints(
558 update_proto.sos1_constraint_updates().new_constraints());
559 copyable_data_.sos2_constraints.AddConstraints(
560 update_proto.sos2_constraint_updates().new_constraints());
561 copyable_data_.indicator_constraints.AddConstraints(
562 update_proto.indicator_constraint_updates().new_constraints());
568 for (
const auto& [raw_id, objective_update] :
569 update_proto.auxiliary_objectives_updates().objective_updates()) {
574 UpdateLinearConstraintCoefficients(
575 update_proto.linear_constraint_matrix_updates());
577 return absl::OkStatus();
#define RETURN_IF_ERROR(expr)
void set_name(Arg_ &&arg, Args_... args)
::operations_research::math_opt::QuadraticConstraintUpdatesProto *PROTOBUF_NONNULL mutable_quadratic_constraint_updates()
An object oriented wrapper for quadratic constraints in ModelStorage.
absl::Status ValidateModelUpdate(const ModelUpdateProto &model_update, ModelSummary &model_summary)
ElementId< ElementType::kAuxiliaryObjective > AuxiliaryObjectiveId
ElementId< ElementType::kVariable > VariableId
constexpr ObjectiveId kPrimaryObjectiveId
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
ElementId< ElementType::kQuadraticConstraint > QuadraticConstraintId
ElementId< ElementType::kLinearConstraint > LinearConstraintId
auto MakeUpdateDataFieldRange(const UpdateTrackers &trackers)
void RemoveNames(ModelProto &model)
Removes the model, variables and constraints names of the provided model.
std::optional< AuxiliaryObjectiveId > ObjectiveId
nullopt denotes the primary objective.
ElementId< ElementType::kIndicatorConstraint > IndicatorConstraintId
std::vector< K > SortedMapKeys(const absl::flat_hash_map< K, V > &in_map)
absl::StatusOr< ModelSummary > ValidateModel(const ModelProto &model, const bool check_names)
In SWIG mode, we don't want anything besides these top-level includes.