21#include "absl/algorithm/container.h"
22#include "absl/container/flat_hash_map.h"
23#include "absl/container/flat_hash_set.h"
24#include "absl/log/check.h"
25#include "absl/status/status.h"
26#include "absl/strings/string_view.h"
27#include "absl/types/span.h"
45constexpr int32_t kInt32Max = std::numeric_limits<int32_t>::max();
47absl::Status CanExportToProto(int64_t num_entries) {
48 if (num_entries > kInt32Max) {
50 <<
"Cannot export to proto, RepeatedField can hold at most "
51 "std::numeric_limits<int32_t>::max() = 2**31-1 = 2147483647 "
54 << num_entries <<
" entries";
56 return absl::OkStatus();
64template <
int n,
typename Fn>
65absl::Status ForEachIndexUntilError(Fn&& fn) {
66 absl::Status result = absl::OkStatus();
72 result.Update(fn.template
operator()<i>());
85absl::Status ForEachAttrUntilError(Fn&& fn) {
91 result.Update(fn(attr));
102absl::Status ValidateElementsFitInProto(
const Elemental& model) {
103 return ForEachIndexUntilError<kNumElements>(
105 [&model]<
int e>() -> absl::Status {
106 constexpr auto element_type =
static_cast<ElementType>(e);
108 <<
"too many elements of type: " << element_type;
109 return absl::OkStatus();
117absl::Status ValidateAttrsFitInProto(
const Elemental& model) {
118 return ForEachAttrUntilError([&model](
auto attr) -> absl::Status {
121 <<
"too many non-default values for attribute: " << attr;
123 return absl::OkStatus();
128absl::Status ValidateModelFitsInProto(
const Elemental& model) {
131 return absl::OkStatus();
135std::vector<T> Sorted(std::vector<T> vec) {
141std::vector<T> SortSet(
const absl::flat_hash_set<T>& s) {
142 return Sorted(std::vector<T>{s.begin(), s.end()});
145template <ElementType e>
147 absl::c_sort(vec.container());
152std::optional<SparseDoubleVectorProto> ExportSparseDoubleVector(
158 CHECK_LE(keys.size(), kInt32Max);
160 const int32_t num_keys =
static_cast<int32_t
>(keys.size());
162 result.mutable_values()->Reserve(num_keys);
164 result.add_ids(key[0]);
170std::optional<SparseDoubleVectorProto> ExportSparseDoubleVector(
172 return ExportSparseDoubleVector(
173 elemental, double_attr, Sorted(elemental.AttrNonDefaults(double_attr)));
182template <
typename DAttr2>
183std::optional<SparseDoubleMatrixProto> ExportSparseDoubleMatrix(
184 const Elemental& elemental,
const DAttr2 attr,
187 "Attribute must have key size two");
189 std::is_same_v<double, typename AttrTypeDescriptorT<DAttr2>::ValueType>,
190 "Attribute must be double valued");
194 CHECK_LE(keys.size(), kInt32Max);
197 const int nnz =
static_cast<int>(keys.size());
199 result.mutable_column_ids()->Reserve(nnz);
200 result.mutable_coefficients()->Reserve(nnz);
202 result.add_row_ids(key[0]);
203 result.add_column_ids(key[1]);
213template <
int key_index>
214std::optional<SparseDoubleVectorProto> ExportSparseDoubleMatrixSlice(
216 const int64_t slice_element_id) {
217 std::vector<AttrKey<2>> slice =
218 elemental.Slice<key_index>(attr, slice_element_id);
222 CHECK_LE(slice.size(), kInt32Max);
223 const int slice_size =
static_cast<int>(slice.size());
227 vec.mutable_values()->Reserve(slice_size);
229 vec.add_ids(key.RemoveElement<key_index>()[0]);
235template <
typename DAttr2>
236std::optional<SparseDoubleMatrixProto> ExportSparseDoubleMatrix(
237 const Elemental& elemental,
const DAttr2 attr) {
238 return ExportSparseDoubleMatrix(elemental, attr,
239 Sorted(elemental.AttrNonDefaults(attr)));
242std::optional<VariablesProto> ExportVariables(
245 const bool remove_names) {
246 if (var_ids.empty()) {
251 const int num_vars =
static_cast<int>(var_ids.size());
253 vars_proto.mutable_integers()->Reserve(num_vars);
254 vars_proto.mutable_lower_bounds()->Reserve(num_vars);
255 vars_proto.mutable_upper_bounds()->Reserve(num_vars);
257 vars_proto.mutable_names()->Reserve(num_vars);
260 vars_proto.add_ids(var.value());
264 BoolAttr1::kVarInteger,
AttrKey(var)));
266 DoubleAttr1::kVarLb,
AttrKey(var)));
268 DoubleAttr1::kVarUb,
AttrKey(var)));
270 const auto name = elemental.GetElementName(var);
272 vars_proto.add_names(*name);
278std::optional<LinearConstraintsProto> ExportLinearConstraints(
281 const bool remove_names) {
282 if (lin_con_ids.empty()) {
287 const int num_lin_cons =
static_cast<int>(lin_con_ids.size());
289 lin_cons_proto.
mutable_ids()->Reserve(num_lin_cons);
290 lin_cons_proto.mutable_lower_bounds()->Reserve(num_lin_cons);
291 lin_cons_proto.mutable_upper_bounds()->Reserve(num_lin_cons);
293 lin_cons_proto.mutable_names()->Reserve(num_lin_cons);
296 lin_cons_proto.add_ids(lin_con.value());
300 DoubleAttr1::kLinConLb,
AttrKey(lin_con)));
302 DoubleAttr1::kLinConUb,
AttrKey(lin_con)));
304 const auto name = elemental.GetElementName(lin_con);
306 lin_cons_proto.add_names(*name);
309 return lin_cons_proto;
314absl::flat_hash_map<QuadraticConstraintId, QuadraticConstraintProto>
315ExportQuadraticConstraints(
318 const bool remove_names) {
319 absl::flat_hash_map<QuadraticConstraintId, QuadraticConstraintProto> result;
320 CHECK_LE(quad_con_ids.size(), kInt32Max);
324 const auto name = elemental.GetElementName(
id);
326 quad_con.set_name(*name);
329 DoubleAttr1::kQuadConLb,
AttrKey(
id)));
331 DoubleAttr1::kQuadConUb,
AttrKey(
id)));
332 if (std::optional<SparseDoubleVectorProto> lin_coefs =
333 ExportSparseDoubleMatrixSlice<0>(
334 elemental, DoubleAttr2::kQuadConLinCoef,
id.value());
335 lin_coefs.has_value()) {
336 *quad_con.mutable_linear_terms() = *std::move(lin_coefs);
339 elemental.Slice<0>(SymmetricDoubleAttr3::kQuadConQuadCoef,
341 !quad_con_quad_coefs.empty()) {
342 absl::c_sort(quad_con_quad_coefs);
344 *quad_con.mutable_quadratic_terms();
346 quad_coef_proto.add_row_ids(key[1]);
347 quad_coef_proto.add_column_ids(key[2]);
349 SymmetricDoubleAttr3::kQuadConQuadCoef, key));
352 auto [it, inserted] = result.insert({id, std::move(quad_con)});
358absl::flat_hash_map<IndicatorConstraintId, IndicatorConstraintProto>
359ExportIndicatorConstraints(
362 const bool remove_names) {
363 absl::flat_hash_map<IndicatorConstraintId, IndicatorConstraintProto> result;
364 CHECK_LE(ind_con_ids.size(), kInt32Max);
368 const auto name = elemental.GetElementName(
id);
370 ind_con.set_name(*name);
373 DoubleAttr1::kIndConLb,
AttrKey(
id)));
375 DoubleAttr1::kIndConUb,
AttrKey(
id)));
376 if (std::optional<SparseDoubleVectorProto> lin_coefs =
377 ExportSparseDoubleMatrixSlice<0>(
378 elemental, DoubleAttr2::kIndConLinCoef,
id.value());
379 lin_coefs.has_value()) {
380 *ind_con.mutable_expression() = *std::move(lin_coefs);
383 BoolAttr1::kIndConActivateOnZero,
AttrKey(
id)));
385 VariableAttr1::kIndConIndicator,
AttrKey(
id))) {
386 ind_con.set_indicator_id(
388 .GetAttr<Elemental::UBPolicy>(VariableAttr1::kIndConIndicator,
392 CHECK(result.insert({id, std::move(ind_con)}).second);
397std::optional<ObjectiveProto> ExportObjective(
const Elemental& elemental,
398 const bool remove_names) {
399 const bool has_offset =
400 elemental.AttrIsNonDefault(DoubleAttr0::kObjOffset,
AttrKey());
401 const bool has_maximize =
402 elemental.AttrIsNonDefault(BoolAttr0::kMaximize,
AttrKey());
403 const bool has_priority =
404 elemental.AttrIsNonDefault(IntAttr0::kObjPriority,
AttrKey());
406 std::optional<SparseDoubleVectorProto> lin_obj_vec =
407 ExportSparseDoubleVector(elemental, DoubleAttr1::kObjLinCoef);
409 std::optional<SparseDoubleMatrixProto> quad_obj_mat =
410 ExportSparseDoubleMatrix(elemental, SymmetricDoubleAttr2::kObjQuadCoef);
411 const bool has_name =
412 !remove_names && !elemental.primary_objective_name().empty();
413 if (!has_offset && !has_maximize && !has_priority &&
414 !lin_obj_vec.has_value() && !quad_obj_mat.has_value() && !has_name) {
419 result.set_name(elemental.primary_objective_name());
421 result.set_maximize(elemental.GetAttr(BoolAttr0::kMaximize,
AttrKey()));
422 result.set_offset(elemental.GetAttr(DoubleAttr0::kObjOffset,
AttrKey()));
423 result.set_priority(elemental.GetAttr(IntAttr0::kObjPriority,
AttrKey()));
424 if (lin_obj_vec.has_value()) {
425 *result.mutable_linear_coefficients() = *std::move(lin_obj_vec);
427 if (quad_obj_mat.has_value()) {
428 *result.mutable_quadratic_coefficients() = *std::move(quad_obj_mat);
433absl::StatusOr<ObjectiveProto> ExportAuxiliaryObjective(
435 const bool remove_names) {
439 elemental.GetElementName(
id));
440 result.set_name(name);
443 elemental.GetAttr(BoolAttr1::kAuxObjMaximize,
AttrKey(
id)));
444 result.set_offset(elemental.GetAttr(DoubleAttr1::kAuxObjOffset,
AttrKey(
id)));
446 elemental.GetAttr(IntAttr1::kAuxObjPriority,
AttrKey(
id)));
447 if (std::optional<SparseDoubleVectorProto> lin_coefs =
448 ExportSparseDoubleMatrixSlice<0>(
449 elemental, DoubleAttr2::kAuxObjLinCoef,
id.value());
450 lin_coefs.has_value()) {
451 *result.mutable_linear_coefficients() = *std::move(lin_coefs);
456absl::StatusOr<ModelProto> ExportModelProto(
const Elemental& elemental,
457 const bool remove_names) {
461 result.set_name(elemental.model_name());
463 if (
auto vars = ExportVariables(
468 *result.mutable_variables() = *std::move(vars);
472 if (
auto obj = ExportObjective(elemental, remove_names); obj.has_value()) {
473 *result.mutable_objective() = *std::move(obj);
479 ((*result.mutable_auxiliary_objectives())[aux_obj_id.value()]),
480 ExportAuxiliaryObjective(elemental, aux_obj_id, remove_names));
483 if (
auto lin_cons = ExportLinearConstraints(
488 lin_cons.has_value()) {
489 *result.mutable_linear_constraints() = *std::move(lin_cons);
493 if (
auto mat = ExportSparseDoubleMatrix(
494 elemental, DoubleAttr2::kLinConCoef,
495 Sorted(elemental.AttrNonDefaults(DoubleAttr2::kLinConCoef)));
497 *result.mutable_linear_constraint_matrix() = *std::move(mat);
501 for (
auto& [
id, quad_con_coef] : ExportQuadraticConstraints(
506 (*result.mutable_quadratic_constraints())[
id.value()] =
507 std::move(quad_con_coef);
510 for (
auto& [
id, ind_con] : ExportIndicatorConstraints(
515 (*result.mutable_indicator_constraints())[
id.value()] = std::move(ind_con);
524 const bool remove_names)
const {
528 return ExportModelProto(*
this, remove_names);
539absl::Status ValidateElementUpdatesFitInProto(
541 const std::array<std::vector<int64_t>,
kNumElements>& new_elements) {
542 return ForEachIndexUntilError<kNumElements>(
544 [&diff, &new_elements]<
int e>() -> absl::Status {
545 constexpr auto element_type =
static_cast<ElementType>(e);
548 <<
"too many deleted elements of type: " << element_type;
550 <<
"too many new elements of type: " << element_type;
551 return absl::OkStatus();
559absl::Status ValidateAttrUpdatesFitInProto(
const Diff& diff) {
560 return ForEachAttrUntilError([&diff](
auto attr) -> absl::Status {
562 <<
"too many modifications for attribute: " << attr;
563 return absl::OkStatus();
584absl::Status ValidateModelUpdateFitsInProto(
586 const std::array<std::vector<int64_t>,
kNumElements>& new_elements) {
589 return absl::OkStatus();
593template <ElementType e>
594google::protobuf::RepeatedField<int64_t> DeletedIdsSorted(
const Diff& diff) {
595 const std::vector<int64_t> sorted_del_vars =
596 SortSet(diff.deleted_elements(e));
597 return {sorted_del_vars.begin(), sorted_del_vars.end()};
600std::optional<SparseDoubleVectorProto> ExportAttrDiff(
602 std::vector<AttrKey<1>> keys = elemental.ModifiedKeysThatExist(a, diff);
609 const int num_keys =
static_cast<int>(keys.size());
611 result.mutable_values()->Reserve(num_keys);
612 for (
const auto key : keys) {
613 result.add_ids(key[0]);
614 result.add_values(elemental.GetAttr(a, key));
619absl::StatusOr<std::optional<SparseDoubleVectorProto>> ExportLinObjCoefUpdate(
622 std::vector<AttrKey<1>> keys =
623 elemental.ModifiedKeysThatExist(DoubleAttr1::kObjLinCoef, diff);
626 for (
const VariableId id : new_var_ids_sorted) {
628 DoubleAttr1::kObjLinCoef,
AttrKey(
id))) {
633 <<
"cannot export linear objective coefficients in model update";
634 return ExportSparseDoubleVector(elemental, DoubleAttr1::kObjLinCoef, keys);
637absl::StatusOr<std::optional<SparseDoubleMatrixProto>> ExportQuadObjCoefUpdate(
641 std::vector<Key> keys =
642 elemental.ModifiedKeysThatExist(SymmetricDoubleAttr2::kObjQuadCoef, diff);
643 if (!new_var_ids_sorted.empty()) {
644 const int64_t smallest_key = new_var_ids_sorted[0].value();
646 for (
const VariableId id : new_var_ids_sorted) {
648 elemental.Slice<0>(SymmetricDoubleAttr2::kObjQuadCoef,
id.value())) {
649 if (key[0] < smallest_key || key[1] < smallest_key ||
650 key[0] ==
id.value()) {
657 <<
"cannot export linear objective coefficients in model update";
659 return ExportSparseDoubleMatrix(elemental, SymmetricDoubleAttr2::kObjQuadCoef,
663std::optional<SparseBoolVectorProto> ExportAttrDiff(
const Elemental& elemental,
666 std::vector<AttrKey<1>> keys = elemental.ModifiedKeysThatExist(a, diff);
673 const int num_keys =
static_cast<int>(keys.size());
675 result.mutable_values()->Reserve(num_keys);
676 for (
const auto id : keys) {
677 result.add_ids(
id[0]);
678 result.add_values(elemental.GetAttr(a,
id));
683std::vector<int64_t> ElementsSinceCheckpoint(
const ElementType e,
686 std::vector<int64_t> result;
687 for (int64_t
id = diff.checkpoint(e);
id < elemental.NextElementId(e); ++
id) {
688 if (elemental.ElementExistsUntyped(e,
id)) {
689 result.push_back(
id);
695std::array<std::vector<int64_t>,
kNumElements> ElementsSinceCheckpointPerType(
699 result[
static_cast<int>(e)] = ElementsSinceCheckpoint(e, elemental, diff);
704std::optional<VariableUpdatesProto> ExportVariableUpdates(
706 auto ubs = ExportAttrDiff(elemental, DoubleAttr1::kVarUb, diff);
707 auto lbs = ExportAttrDiff(elemental, DoubleAttr1::kVarLb, diff);
708 auto integers = ExportAttrDiff(elemental, BoolAttr1::kVarInteger, diff);
709 if (!ubs.has_value() && !lbs.has_value() && !integers.has_value()) {
713 if (ubs.has_value()) {
714 *var_updates.mutable_upper_bounds() = *std::move(ubs);
716 if (lbs.has_value()) {
717 *var_updates.mutable_lower_bounds() = *std::move(lbs);
719 if (integers.has_value()) {
720 *var_updates.mutable_integers() = *std::move(integers);
725std::optional<LinearConstraintUpdatesProto> ExportLinearConstraintUpdates(
727 auto ubs = ExportAttrDiff(elemental, DoubleAttr1::kLinConUb, diff);
728 auto lbs = ExportAttrDiff(elemental, DoubleAttr1::kLinConLb, diff);
729 if (!ubs.has_value() && !lbs.has_value()) {
733 if (ubs.has_value()) {
734 *lin_con_updates.mutable_upper_bounds() = *std::move(ubs);
736 if (lbs.has_value()) {
737 *lin_con_updates.mutable_lower_bounds() = *std::move(lbs);
739 return lin_con_updates;
742absl::StatusOr<std::optional<ObjectiveUpdatesProto>> ExportObjectiveUpdates(
746 ExportLinObjCoefUpdate(elemental, diff, new_var_ids));
748 ExportQuadObjCoefUpdate(elemental, diff, new_var_ids));
749 const bool maximize_modified =
750 diff.modified_keys(BoolAttr0::kMaximize).contains(
AttrKey());
751 const bool offset_modified =
752 diff.modified_keys(DoubleAttr0::kObjOffset).contains(
AttrKey());
753 const bool priority_modified =
754 diff.modified_keys(IntAttr0::kObjPriority).contains(
AttrKey());
755 if (!lin_coef_updates.has_value() && !quad_coef_updates.has_value() &&
756 !maximize_modified && !offset_modified && !priority_modified) {
760 if (maximize_modified) {
761 objective_updates.set_direction_update(
762 elemental.GetAttr(BoolAttr0::kMaximize,
AttrKey()));
764 if (offset_modified) {
765 objective_updates.set_offset_update(
766 elemental.GetAttr(DoubleAttr0::kObjOffset,
AttrKey()));
768 if (priority_modified) {
769 objective_updates.set_priority_update(
770 elemental.GetAttr(IntAttr0::kObjPriority,
AttrKey()));
772 if (lin_coef_updates.has_value()) {
773 *objective_updates.mutable_linear_coefficients() =
774 *std::move(lin_coef_updates);
776 if (quad_coef_updates.has_value()) {
777 *objective_updates.mutable_quadratic_coefficients() =
778 *std::move(quad_coef_updates);
780 return objective_updates;
783bool ModelUpdateIsEmpty(
785 const std::array<std::vector<int64_t>,
kNumElements> new_elements) {
786 for (
const std::vector<int64_t>& els : new_elements) {
791 bool is_empty =
true;
794 is_empty && diff.deleted_elements(
static_cast<ElementType>(e)).empty();
800 is_empty = is_empty && diff.modified_keys(attr).empty();
805template <
typename AttrType>
806absl::Status EnsureAttrModificationsEmpty(
const Diff& diff, AttrType attr) {
807 if (!diff.modified_keys(attr).empty()) {
809 <<
"Modification for attribute " << attr
810 <<
" is not supported for ModelUpdateProto export.";
812 return absl::OkStatus();
815absl::StatusOr<std::optional<QuadraticConstraintUpdatesProto>>
816ExportQuadraticConstraintsUpdates(
819 const bool remove_names) {
821 RETURN_IF_ERROR(EnsureAttrModificationsEmpty(diff, DoubleAttr1::kQuadConLb));
822 RETURN_IF_ERROR(EnsureAttrModificationsEmpty(diff, DoubleAttr1::kQuadConUb));
824 EnsureAttrModificationsEmpty(diff, DoubleAttr2::kQuadConLinCoef));
826 diff, SymmetricDoubleAttr3::kQuadConQuadCoef));
827 auto deleted = DeletedIdsSorted<ElementType::kQuadraticConstraint>(diff);
828 if (deleted.empty() && new_quad_cons.empty()) {
832 *result.mutable_deleted_constraint_ids() = std::move(deleted);
833 for (
auto& [
id, quad_con] :
834 ExportQuadraticConstraints(elemental, new_quad_cons, remove_names)) {
835 result.mutable_new_constraints()->insert({
id.value(), std::move(quad_con)});
840absl::StatusOr<std::optional<IndicatorConstraintUpdatesProto>>
841ExportIndicatorConstraintsUpdates(
844 const bool remove_names) {
847 EnsureAttrModificationsEmpty(diff, BoolAttr1::kIndConActivateOnZero));
849 EnsureAttrModificationsEmpty(diff, VariableAttr1::kIndConIndicator));
850 RETURN_IF_ERROR(EnsureAttrModificationsEmpty(diff, DoubleAttr1::kIndConLb));
851 RETURN_IF_ERROR(EnsureAttrModificationsEmpty(diff, DoubleAttr1::kIndConUb));
853 EnsureAttrModificationsEmpty(diff, DoubleAttr2::kIndConLinCoef));
854 auto deleted = DeletedIdsSorted<ElementType::kIndicatorConstraint>(diff);
855 if (deleted.empty() && new_ind_cons.empty()) {
860 for (
auto& [
id, ind_con] :
861 ExportIndicatorConstraints(elemental, new_ind_cons, remove_names)) {
862 result.mutable_new_constraints()->insert({
id.value(), std::move(ind_con)});
867absl::StatusOr<std::optional<AuxiliaryObjectivesUpdatesProto>>
868ExportAuxiliaryObjectivesUpdates(
872 const bool remove_names) {
874 auto deleted = DeletedIdsSorted<ElementType::kAuxiliaryObjective>(diff);
878 google::protobuf::Map<int64_t, ObjectiveUpdatesProto>& mods =
879 *result.mutable_objective_updates();
881 diff.modified_keys(BoolAttr1::kAuxObjMaximize)) {
882 mods[aux_obj[0]].set_direction_update(
887 diff.modified_keys(IntAttr1::kAuxObjPriority)) {
888 mods[aux_obj[0]].set_priority_update(
893 diff.modified_keys(DoubleAttr1::kAuxObjOffset)) {
895 DoubleAttr1::kAuxObjOffset, aux_obj));
897 absl::flat_hash_map<int64_t, std::vector<std::pair<int64_t, double>>>
900 elemental.ModifiedKeysThatExist(DoubleAttr2::kAuxObjLinCoef, diff)) {
901 lin_con_updates[aux_lin_obj_var[0]].push_back(
908 elemental.Slice<1>(DoubleAttr2::kAuxObjLinCoef, new_var.value())) {
909 const int64_t aux_obj = aux_lin_obj_var[0];
913 lin_con_updates[aux_obj].push_back(
915 elemental.GetAttr(DoubleAttr2::kAuxObjLinCoef, aux_lin_obj_var)});
918 for (
auto& [aux_obj, lin_terms] : lin_con_updates) {
919 absl::c_sort(lin_terms);
921 *mods[aux_obj].mutable_linear_coefficients();
922 for (
auto [var, coef] : lin_terms) {
923 proto_terms.add_ids(var);
924 proto_terms.add_values(coef);
928 if (deleted.empty() && new_aux_objs.empty() &&
929 result.objective_updates().empty()) {
932 *result.mutable_deleted_objective_ids() = std::move(deleted);
935 ExportAuxiliaryObjective(elemental,
id, remove_names));
940absl::StatusOr<std::optional<ModelUpdateProto>> ExportModelUpdateProto(
941 const Elemental& elemental,
const Diff& diff,
const bool remove_names) {
942 const std::array<std::vector<int64_t>,
kNumElements> new_elements =
943 ElementsSinceCheckpointPerType(elemental, diff);
944 if (ModelUpdateIsEmpty(diff, new_elements)) {
965 *result.mutable_deleted_variable_ids() =
966 DeletedIdsSorted<ElementType::kVariable>(diff);
967 if (
auto var_updates = ExportVariableUpdates(elemental, diff);
968 var_updates.has_value()) {
969 *result.mutable_variable_updates() = *std::move(var_updates);
971 if (
auto vars = ExportVariables(elemental, new_var_ids, remove_names);
973 *result.mutable_new_variables() = *std::move(vars);
979 ExportObjectiveUpdates(elemental, diff, new_var_ids));
980 if (objective_updates.has_value()) {
981 *result.mutable_objective_updates() = *std::move(objective_updates);
987 std::optional<AuxiliaryObjectivesUpdatesProto> aux_objs,
988 ExportAuxiliaryObjectivesUpdates(elemental, diff, new_var_ids,
989 new_aux_objs, remove_names));
990 if (aux_objs.has_value()) {
991 *result.mutable_auxiliary_objectives_updates() = *std::move(aux_objs);
996 *result.mutable_deleted_linear_constraint_ids() =
997 DeletedIdsSorted<ElementType::kLinearConstraint>(diff);
998 if (
auto lin_con_updates = ExportLinearConstraintUpdates(elemental, diff);
999 lin_con_updates.has_value()) {
1000 *result.mutable_linear_constraint_updates() = *std::move(lin_con_updates);
1003 ExportLinearConstraints(elemental, new_lin_cons, remove_names);
1004 lin_cons.has_value()) {
1005 *result.mutable_new_linear_constraints() = *std::move(lin_cons);
1010 std::vector<AttrKey<2>> mat_keys =
1011 elemental.ModifiedKeysThatExist(DoubleAttr2::kLinConCoef, diff);
1012 for (
const VariableId new_var : new_var_ids) {
1014 elemental.Slice<1>(DoubleAttr2::kLinConCoef, new_var.value())) {
1015 mat_keys.push_back(related_key);
1020 elemental.Slice<0>(DoubleAttr2::kLinConCoef, new_con.value())) {
1023 if (related_key[1] < var_checkpoint) {
1024 mat_keys.push_back(related_key);
1029 <<
"too many linear constraint matrix nonzeros in model update";
1030 absl::c_sort(mat_keys);
1031 if (
auto mat = ExportSparseDoubleMatrix(elemental, DoubleAttr2::kLinConCoef,
1034 *result.mutable_linear_constraint_matrix_updates() = *std::move(mat);
1040 std::optional<QuadraticConstraintUpdatesProto> quad_updates,
1041 ExportQuadraticConstraintsUpdates(elemental, diff, new_quad_cons,
1043 if (quad_updates.has_value()) {
1044 *result.mutable_quadratic_constraint_updates() = *std::move(quad_updates);
1049 ASSIGN_OR_RETURN(std::optional<IndicatorConstraintUpdatesProto> ind_updates,
1050 ExportIndicatorConstraintsUpdates(
1051 elemental, diff, new_ind_cons, remove_names));
1052 if (ind_updates.has_value()) {
1053 *result.mutable_indicator_constraint_updates() = *std::move(ind_updates);
1062 const DiffHandle diff,
const bool remove_names)
const {
1063 if (&diff.diffs_ != diffs_.get()) {
1065 <<
"diff with id: " << diff.id() <<
" is from another Elemental";
1067 Diff* diff_value = diffs_->Get(diff.id());
1068 if (diff_value ==
nullptr) {
1070 <<
"Model has no diff with id: " << diff.id();
1075 return ExportModelUpdateProto(*
this, *diff_value, remove_names);
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)
const absl::flat_hash_set< int64_t > & deleted_elements(const ElementType e) const
absl::StatusOr< ModelProto > ExportModel(bool remove_names=false) const
absl::StatusOr< std::optional< ModelUpdateProto > > ExportModelUpdate(DiffHandle diff, bool remove_names=false) const
void set_lower_bound(double value)
::google::protobuf::RepeatedField<::int64_t > *PROTOBUF_NONNULL mutable_deleted_constraint_ids()
::google::protobuf::RepeatedField<::int64_t > *PROTOBUF_NONNULL mutable_ids()
void set_maximize(bool value)
void set_lower_bound(double value)
::google::protobuf::RepeatedField<::int64_t > *PROTOBUF_NONNULL mutable_ids()
::google::protobuf::RepeatedField<::int64_t > *PROTOBUF_NONNULL mutable_row_ids()
::google::protobuf::RepeatedField<::int64_t > *PROTOBUF_NONNULL mutable_ids()
::google::protobuf::RepeatedField<::int64_t > *PROTOBUF_NONNULL mutable_ids()
An object oriented wrapper for quadratic constraints in ModelStorage.
BoolAttr1TypeDescriptor::AttrType BoolAttr1
AttrKey< AttrTypeDescriptorT< AttrType >::kNumKeyElements, typename AttrTypeDescriptorT< AttrType >::Symmetry > AttrKeyFor
The type of the AttrKey for attribute type AttrType.
ElementId< ElementType::kAuxiliaryObjective > AuxiliaryObjectiveId
ElementId< ElementType::kVariable > VariableId
AttrKey(Ints... dims) -> AttrKey< sizeof...(Ints), NoSymmetry >
CTAD for AttrKey(1,2).
constexpr int kNumElements
DoubleAttr1TypeDescriptor::AttrType DoubleAttr1
typename ElementIdsVector< element_type >::View ElementIdsSpan
ElementId< ElementType::kQuadraticConstraint > QuadraticConstraintId
DoubleAttr2TypeDescriptor::AttrType DoubleAttr2
ElementId< ElementType::kLinearConstraint > LinearConstraintId
constexpr int GetAttrKeySize()
constexpr decltype(auto) ForEachIndex(Fn &&fn)
ElementId< ElementType::kIndicatorConstraint > IndicatorConstraintId
StatusBuilder InvalidArgumentErrorBuilder()
static void ForEachAttr(Fn &&fn)