24#include "absl/container/flat_hash_map.h"
25#include "absl/container/flat_hash_set.h"
26#include "absl/memory/memory.h"
27#include "absl/meta/type_traits.h"
28#include "absl/status/statusor.h"
29#include "absl/strings/string_view.h"
30#include "absl/synchronization/mutex.h"
31#include "absl/types/span.h"
38#include "ortools/math_opt/model.pb.h"
39#include "ortools/math_opt/model_update.pb.h"
40#include "ortools/math_opt/solution.pb.h"
41#include "ortools/math_opt/sparse_containers.pb.h"
49template <
typename K,
typename V>
50std::vector<K> MapKeys(
const absl::flat_hash_map<K, V>& in_map) {
52 keys.reserve(in_map.size());
53 for (
const auto& key_pair : in_map) {
54 keys.push_back(key_pair.first);
59template <
typename K,
typename V>
60std::vector<K> SortedMapKeys(
const absl::flat_hash_map<K, V>& in_map) {
61 std::vector<K> keys = MapKeys(in_map);
62 std::sort(keys.begin(), keys.end());
67std::vector<T> SortedSetKeys(
const absl::flat_hash_set<T>& in_set) {
69 keys.reserve(in_set.size());
70 for (
const auto& key : in_set) {
73 std::sort(keys.begin(), keys.end());
78template <
typename IdType>
79void AppendFromMapOrDefault(
const absl::Span<const IdType> ids,
80 const absl::flat_hash_map<IdType, double>& values,
81 SparseDoubleVectorProto& sparse_vector) {
82 for (
const IdType
id : ids) {
83 sparse_vector.add_ids(
id.
value());
89template <
typename IdType,
typename IdIterable>
90void AppendFromMapIfPresent(
const IdIterable& ids,
91 const absl::flat_hash_map<IdType, double>& values,
92 SparseDoubleVectorProto& sparse_vector) {
93 for (
const IdType
id : ids) {
95 if (double_value !=
nullptr) {
96 sparse_vector.add_ids(
id.
value());
97 sparse_vector.add_values(*double_value);
102template <
typename IdType,
typename DataType>
103void AppendFromMap(
const absl::flat_hash_set<IdType>& dirty_keys,
104 const absl::flat_hash_map<IdType, DataType>& values,
105 double DataType::*field,
106 SparseDoubleVectorProto& sparse_vector) {
107 for (
const IdType
id : SortedSetKeys(dirty_keys)) {
108 sparse_vector.add_ids(
id.
value());
109 sparse_vector.add_values(values.at(
id).*field);
114absl::flat_hash_map<T, BasisStatusProto> SparseBasisVectorToMap(
115 const SparseBasisStatusVector& sparse_vector) {
116 absl::flat_hash_map<T, BasisStatusProto> result;
117 CHECK_EQ(sparse_vector.ids_size(), sparse_vector.values_size());
118 result.reserve(sparse_vector.ids_size());
129template <
typename RK,
typename CK>
130SparseDoubleMatrixProto ExportMatrix(
131 const absl::flat_hash_map<std::pair<RK, CK>,
double>&
coefficients,
132 const std::vector<std::pair<RK, CK>>& keys) {
133 SparseDoubleMatrixProto matrix;
134 matrix.mutable_row_ids()->Reserve(keys.size());
135 matrix.mutable_column_ids()->Reserve(keys.size());
136 matrix.mutable_coefficients()->Reserve(keys.size());
137 for (
const auto [row_id, column_id] : keys) {
138 matrix.add_row_ids(row_id.value());
139 matrix.add_column_ids(column_id.value());
140 matrix.add_coefficients(
156 auto storage = std::make_unique<ModelStorage>(
model_proto.name());
162 storage->set_is_maximize(
model_proto.objective().maximize());
163 storage->set_objective_offset(
model_proto.objective().offset());
164 storage->UpdateLinearObjectiveCoefficients(
166 storage->UpdateQuadraticObjectiveCoefficients(
170 storage->AddLinearConstraints(
model_proto.linear_constraints());
173 storage->UpdateLinearConstraintCoefficients(
179void ModelStorage::UpdateLinearObjectiveCoefficients(
186void ModelStorage::UpdateQuadraticObjectiveCoefficients(
197void ModelStorage::UpdateLinearConstraintCoefficients(
208 absl::StatusOr<std::unique_ptr<ModelStorage>> clone =
216 CHECK_LE(clone.value()->next_variable_id_, next_variable_id_);
217 clone.value()->next_variable_id_ = next_variable_id_;
218 CHECK_LE(clone.value()->next_linear_constraint_id_,
219 next_linear_constraint_id_);
220 clone.value()->next_linear_constraint_id_ = next_linear_constraint_id_;
222 return std::move(clone).value();
227 const bool is_integer,
228 const absl::string_view
name) {
229 const VariableId
id = next_variable_id_;
230 AddVariableInternal(
id,
238void ModelStorage::AddVariableInternal(
const VariableId
id,
241 const bool is_integer,
242 const absl::string_view
name) {
244 next_variable_id_ =
id + VariableId(1);
246 VariableData& var_data = variables_[id];
249 var_data.is_integer = is_integer;
250 var_data.name = std::string(
name);
251 if (!lazy_matrix_columns_.empty()) {
254 if (!lazy_quadratic_objective_by_variable_.empty()) {
259void ModelStorage::AddVariables(
const VariablesProto& variables) {
260 const bool has_names = !
variables.names().empty();
261 for (
int v = 0; v <
variables.ids_size(); ++v) {
263 AddVariableInternal(VariableId(
variables.ids(v)),
267 has_names ?
variables.names(v) : absl::string_view());
272 CHECK(variables_.contains(
id));
273 EnsureLazyMatrixColumns();
274 EnsureLazyMatrixRows();
275 linear_objective_.erase(
id);
276 if (
id < variables_checkpoint_) {
277 dirty_variable_deletes_.insert(
id);
278 dirty_variable_lower_bounds_.erase(
id);
279 dirty_variable_upper_bounds_.erase(
id);
280 dirty_variable_is_integer_.erase(
id);
281 dirty_linear_objective_coefficients_.erase(
id);
290 if (!quadratic_objective_.empty() ||
291 !dirty_quadratic_objective_coefficients_.empty()) {
292 EnsureLazyQuadraticObjective();
293 const auto related_variables =
294 lazy_quadratic_objective_by_variable_.extract(
id);
295 for (
const VariableId other_id : related_variables.mapped()) {
297 if (
id != other_id) {
298 CHECK_GT(lazy_quadratic_objective_by_variable_.at(other_id).erase(
id),
302 quadratic_objective_.erase(ordered_pair);
304 if (
id < variables_checkpoint_ && other_id < variables_checkpoint_) {
305 dirty_quadratic_objective_coefficients_.erase(ordered_pair);
309 for (
const LinearConstraintId related_constraint :
310 lazy_matrix_columns_.at(
id)) {
311 CHECK_GT(lazy_matrix_rows_.at(related_constraint).erase(
id), 0);
312 CHECK_GT(linear_constraint_matrix_.erase({related_constraint, id}), 0);
313 if (
id < variables_checkpoint_ &&
314 related_constraint < linear_constraints_checkpoint_) {
315 dirty_linear_constraint_matrix_keys_.erase({related_constraint,
id});
318 CHECK_GT(lazy_matrix_columns_.erase(
id), 0);
319 variables_.erase(
id);
323 return MapKeys(variables_);
327 return SortedMapKeys(variables_);
332 const absl::string_view
name) {
333 const LinearConstraintId
id = next_linear_constraint_id_;
340void ModelStorage::AddLinearConstraintInternal(
const LinearConstraintId
id,
343 const absl::string_view
name) {
344 CHECK_GE(
id, next_linear_constraint_id_);
345 next_linear_constraint_id_ =
id + LinearConstraintId(1);
347 LinearConstraintData& lin_con_data = linear_constraints_[id];
350 lin_con_data.name = std::string(
name);
351 if (!lazy_matrix_rows_.empty()) {
356void ModelStorage::AddLinearConstraints(
357 const LinearConstraintsProto& linear_constraints) {
361 AddLinearConstraintInternal(
370 CHECK(linear_constraints_.contains(
id));
371 EnsureLazyMatrixColumns();
372 EnsureLazyMatrixRows();
373 linear_constraints_.erase(
id);
374 if (
id < linear_constraints_checkpoint_) {
375 dirty_linear_constraint_deletes_.insert(
id);
376 dirty_linear_constraint_lower_bounds_.erase(
id);
377 dirty_linear_constraint_upper_bounds_.erase(
id);
379 for (
const VariableId related_variable : lazy_matrix_rows_.at(
id)) {
380 CHECK_GT(lazy_matrix_columns_.at(related_variable).erase(
id), 0);
381 CHECK_GT(linear_constraint_matrix_.erase({id, related_variable}), 0);
382 if (
id < linear_constraints_checkpoint_ &&
383 related_variable < variables_checkpoint_) {
384 dirty_linear_constraint_matrix_keys_.erase({id, related_variable});
387 CHECK_GT(lazy_matrix_rows_.erase(
id), 0);
391 return MapKeys(linear_constraints_);
395 return SortedMapKeys(linear_constraints_);
400 return SortedMapKeys(linear_objective_);
403void ModelStorage::AppendVariable(
const VariableId
id,
404 VariablesProto& variables_proto)
const {
405 const VariableData& var_data = variables_.at(
id);
406 variables_proto.add_ids(
id.
value());
407 variables_proto.add_lower_bounds(var_data.lower_bound);
408 variables_proto.add_upper_bounds(var_data.upper_bound);
409 variables_proto.add_integers(var_data.is_integer);
410 variables_proto.add_names(var_data.name);
413void ModelStorage::AppendLinearConstraint(
414 const LinearConstraintId
id,
415 LinearConstraintsProto& linear_constraints_proto)
const {
416 const LinearConstraintData& con_impl = linear_constraints_.at(
id);
417 linear_constraints_proto.add_ids(
id.
value());
418 linear_constraints_proto.add_lower_bounds(con_impl.lower_bound);
419 linear_constraints_proto.add_upper_bounds(con_impl.upper_bound);
420 linear_constraints_proto.add_names(con_impl.name);
425 result.set_name(name_);
427 for (
const VariableId variable : SortedMapKeys(variables_)) {
428 AppendVariable(variable, *result.mutable_variables());
432 result.mutable_objective()->set_maximize(is_maximize_);
433 result.mutable_objective()->set_offset(objective_offset_);
434 AppendFromMapOrDefault<VariableId>(
435 SortedMapKeys(linear_objective_), linear_objective_,
436 *result.mutable_objective()->mutable_linear_coefficients());
437 *result.mutable_objective()->mutable_quadratic_coefficients() =
438 ExportMatrix(quadratic_objective_, SortedMapKeys(quadratic_objective_));
441 for (
const LinearConstraintId con : SortedMapKeys(linear_constraints_)) {
442 AppendLinearConstraint(con, *result.mutable_linear_constraints());
446 *result.mutable_linear_constraint_matrix() =
447 ExportMatrix<LinearConstraintId, VariableId>(
448 linear_constraint_matrix_, SortedMapKeys(linear_constraint_matrix_));
452std::optional<ModelUpdateProto> ModelStorage::ExportSharedModelUpdate() {
455 if (variables_checkpoint_ == next_variable_id_ &&
456 linear_constraints_checkpoint_ == next_linear_constraint_id_ &&
457 !dirty_objective_direction_ && !dirty_objective_offset_ &&
458 dirty_variable_deletes_.empty() && dirty_variable_lower_bounds_.empty() &&
459 dirty_variable_upper_bounds_.empty() &&
460 dirty_variable_is_integer_.empty() &&
461 dirty_linear_objective_coefficients_.empty() &&
462 dirty_quadratic_objective_coefficients_.empty() &&
463 dirty_linear_constraint_deletes_.empty() &&
464 dirty_linear_constraint_lower_bounds_.empty() &&
465 dirty_linear_constraint_upper_bounds_.empty() &&
466 dirty_linear_constraint_matrix_keys_.empty()) {
473 EnsureLazyMatrixRows();
474 EnsureLazyMatrixColumns();
476 ModelUpdateProto result;
479 for (
const VariableId del_var : SortedSetKeys(dirty_variable_deletes_)) {
480 result.add_deleted_variable_ids(del_var.value());
482 for (
const LinearConstraintId del_lin_con :
483 SortedSetKeys(dirty_linear_constraint_deletes_)) {
484 result.add_deleted_linear_constraint_ids(del_lin_con.value());
488 auto var_updates = result.mutable_variable_updates();
489 AppendFromMap(dirty_variable_lower_bounds_, variables_,
491 *var_updates->mutable_lower_bounds());
492 AppendFromMap(dirty_variable_upper_bounds_, variables_,
494 *var_updates->mutable_upper_bounds());
496 for (
const VariableId integer_var :
497 SortedSetKeys(dirty_variable_is_integer_)) {
498 var_updates->mutable_integers()->add_ids(integer_var.value());
499 var_updates->mutable_integers()->add_values(
500 variables_.at(integer_var).is_integer);
502 for (VariableId new_id = variables_checkpoint_; new_id < next_variable_id_;
504 if (variables_.contains(new_id)) {
505 AppendVariable(new_id, *result.mutable_new_variables());
510 auto obj_updates = result.mutable_objective_updates();
511 if (dirty_objective_direction_) {
512 obj_updates->set_direction_update(is_maximize_);
514 if (dirty_objective_offset_) {
515 obj_updates->set_offset_update(objective_offset_);
517 AppendFromMapOrDefault<VariableId>(
518 SortedSetKeys(dirty_linear_objective_coefficients_), linear_objective_,
519 *obj_updates->mutable_linear_coefficients());
524 for (VariableId var_id = variables_checkpoint_; var_id < next_variable_id_;
526 const double*
const double_value =
528 if (double_value !=
nullptr) {
529 obj_updates->mutable_linear_coefficients()->add_ids(var_id.value());
530 obj_updates->mutable_linear_coefficients()->add_values(*double_value);
538 if (!quadratic_objective_.empty() ||
539 !dirty_quadratic_objective_coefficients_.empty()) {
540 EnsureLazyQuadraticObjective();
543 std::vector<std::pair<VariableId, VariableId>> quadratic_objective_updates(
544 dirty_quadratic_objective_coefficients_.begin(),
545 dirty_quadratic_objective_coefficients_.end());
552 for (VariableId new_var = variables_checkpoint_;
553 new_var < next_variable_id_; ++new_var) {
554 if (variables_.contains(new_var)) {
555 for (
const VariableId other_var :
556 lazy_quadratic_objective_by_variable_.at(new_var)) {
557 if (other_var <= new_var) {
558 quadratic_objective_updates.push_back(
564 std::sort(quadratic_objective_updates.begin(),
565 quadratic_objective_updates.end());
566 *result.mutable_objective_updates()->mutable_quadratic_coefficients() =
567 ExportMatrix(quadratic_objective_, quadratic_objective_updates);
571 auto lin_con_updates = result.mutable_linear_constraint_updates();
572 AppendFromMap(dirty_linear_constraint_lower_bounds_, linear_constraints_,
574 *lin_con_updates->mutable_lower_bounds());
575 AppendFromMap(dirty_linear_constraint_upper_bounds_, linear_constraints_,
577 *lin_con_updates->mutable_upper_bounds());
579 for (LinearConstraintId new_id = linear_constraints_checkpoint_;
580 new_id < next_linear_constraint_id_; ++new_id) {
581 if (linear_constraints_.contains(new_id)) {
582 AppendLinearConstraint(new_id, *result.mutable_new_linear_constraints());
587 std::vector<std::pair<LinearConstraintId, VariableId>>
588 constraint_matrix_updates(dirty_linear_constraint_matrix_keys_.begin(),
589 dirty_linear_constraint_matrix_keys_.end());
590 for (VariableId new_var = variables_checkpoint_; new_var < next_variable_id_;
592 if (variables_.contains(new_var)) {
593 for (
const LinearConstraintId lin_con :
594 lazy_matrix_columns_.at(new_var)) {
595 constraint_matrix_updates.emplace_back(lin_con, new_var);
599 for (LinearConstraintId new_lin_con = linear_constraints_checkpoint_;
600 new_lin_con < next_linear_constraint_id_; ++new_lin_con) {
601 if (linear_constraints_.contains(new_lin_con)) {
602 for (
const VariableId
var : lazy_matrix_rows_.at(new_lin_con)) {
604 if (
var < variables_checkpoint_) {
605 constraint_matrix_updates.emplace_back(new_lin_con,
var);
610 std::sort(constraint_matrix_updates.begin(), constraint_matrix_updates.end());
611 *result.mutable_linear_constraint_matrix_updates() =
612 ExportMatrix(linear_constraint_matrix_, constraint_matrix_updates);
617 return {std::move(result)};
620void ModelStorage::EnsureLazyMatrixColumns() {
621 if (lazy_matrix_columns_.empty()) {
622 for (
const auto& var_pair : variables_) {
623 lazy_matrix_columns_.insert({var_pair.first, {}});
625 for (
const auto& mat_entry : linear_constraint_matrix_) {
626 lazy_matrix_columns_.at(mat_entry.first.second)
627 .insert(mat_entry.first.first);
632void ModelStorage::EnsureLazyMatrixRows() {
633 if (lazy_matrix_rows_.empty()) {
634 for (
const auto& lin_con_pair : linear_constraints_) {
635 lazy_matrix_rows_.insert({lin_con_pair.first, {}});
637 for (
const auto& mat_entry : linear_constraint_matrix_) {
638 lazy_matrix_rows_.at(mat_entry.first.first)
639 .insert(mat_entry.first.second);
644void ModelStorage::EnsureLazyQuadraticObjective() {
645 if (lazy_quadratic_objective_by_variable_.empty()) {
646 for (
const auto& [
var, data] : variables_) {
647 lazy_quadratic_objective_by_variable_.insert({
var, {}});
649 for (
const auto& [vars,
coeff] : quadratic_objective_) {
650 lazy_quadratic_objective_by_variable_.at(vars.first).insert(vars.second);
651 lazy_quadratic_objective_by_variable_.at(vars.second).insert(vars.first);
653 for (
const auto& vars : dirty_quadratic_objective_coefficients_) {
654 lazy_quadratic_objective_by_variable_.at(vars.first).insert(vars.second);
655 lazy_quadratic_objective_by_variable_.at(vars.second).insert(vars.first);
660void ModelStorage::SharedCheckpoint() {
661 variables_checkpoint_ = next_variable_id_;
662 linear_constraints_checkpoint_ = next_linear_constraint_id_;
663 dirty_objective_direction_ =
false;
664 dirty_objective_offset_ =
false;
666 dirty_variable_deletes_.clear();
667 dirty_variable_lower_bounds_.clear();
668 dirty_variable_upper_bounds_.clear();
669 dirty_variable_is_integer_.clear();
671 dirty_linear_objective_coefficients_.clear();
672 dirty_quadratic_objective_coefficients_.clear();
674 dirty_linear_constraint_deletes_.clear();
675 dirty_linear_constraint_lower_bounds_.clear();
676 dirty_linear_constraint_upper_bounds_.clear();
677 dirty_linear_constraint_matrix_keys_.clear();
681 const absl::MutexLock lock(&update_trackers_lock_);
683 const UpdateTrackerId update_tracker = next_update_tracker_;
684 ++next_update_tracker_;
686 CHECK(update_trackers_
687 .try_emplace(update_tracker, std::make_unique<UpdateTrackerData>())
690 CheckpointLocked(update_tracker);
692 return update_tracker;
696 const absl::MutexLock lock(&update_trackers_lock_);
697 const auto found = update_trackers_.find(update_tracker);
698 CHECK(found != update_trackers_.end())
699 <<
"Update tracker " << update_tracker <<
" does not exist";
700 update_trackers_.erase(found);
704 const UpdateTrackerId update_tracker) {
705 const absl::MutexLock lock(&update_trackers_lock_);
707 const auto found_data = update_trackers_.find(update_tracker);
708 CHECK(found_data != update_trackers_.end())
709 <<
"Update tracker " << update_tracker <<
" does not exist";
710 const std::unique_ptr<UpdateTrackerData>& data = found_data->second;
715 if (data->updates.empty()) {
716 return ExportSharedModelUpdate();
721 std::vector<UpdateTrackerData*> all_trackers_at_checkpoint;
722 for (
const auto& [other_id, other_data] : update_trackers_) {
723 if (!other_data->updates.empty() &&
724 other_data->updates.front() == data->updates.front()) {
725 all_trackers_at_checkpoint.push_back(other_data.get());
729 CHECK_EQ(data->updates.size(), other_data->updates.size());
731 for (
int i = 0; i < data->updates.size(); ++i) {
732 CHECK_EQ(data->updates[i], other_data->updates[i])
733 <<
"Two trackers have the same checkpoint but different updates.";
749 const auto merge = std::make_shared<ModelUpdateProto>();
750 for (
const auto& update : data->updates) {
756 for (UpdateTrackerData*
const other_data : all_trackers_at_checkpoint) {
757 other_data->updates.clear();
758 other_data->updates.push_back(merge);
761 ModelUpdateProto update = *merge;
762 const std::optional<ModelUpdateProto> pending_update =
763 ExportSharedModelUpdate();
764 if (pending_update) {
771 return {std::move(update)};
775 const absl::MutexLock lock(&update_trackers_lock_);
777 CheckpointLocked(update_tracker);
780void ModelStorage::CheckpointLocked(
const UpdateTrackerId update_tracker) {
781 const auto found_data = update_trackers_.find(update_tracker);
782 CHECK(found_data != update_trackers_.end())
783 <<
"Update tracker " << update_tracker <<
" does not exist";
784 const std::unique_ptr<UpdateTrackerData>& data = found_data->second;
789 if (update_trackers_.size() > 1) {
790 std::optional<ModelUpdateProto> update = ExportSharedModelUpdate();
792 const auto shared_update =
793 std::make_shared<ModelUpdateProto>(*std::move(update));
795 for (
const auto& [other_id, other_data] : update_trackers_) {
796 other_data->updates.push_back(shared_update);
801 data->updates.clear();
805 const ModelUpdateProto& update_proto) {
819 next_linear_constraint_id_.value());
826 for (
const int64_t v_id : update_proto.deleted_variable_ids()) {
829 for (
const int64_t c_id : update_proto.deleted_linear_constraint_ids()) {
834 for (
const auto [v_id, lb] :
835 MakeView(update_proto.variable_updates().lower_bounds())) {
838 for (
const auto [v_id, ub] :
839 MakeView(update_proto.variable_updates().upper_bounds())) {
842 for (
const auto [v_id, is_integer] :
843 MakeView(update_proto.variable_updates().integers())) {
848 for (
const auto [c_id, lb] :
849 MakeView(update_proto.linear_constraint_updates().lower_bounds())) {
852 for (
const auto [c_id, ub] :
853 MakeView(update_proto.linear_constraint_updates().upper_bounds())) {
858 AddVariables(update_proto.new_variables());
859 AddLinearConstraints(update_proto.new_linear_constraints());
862 if (update_proto.objective_updates().has_direction_update()) {
865 if (update_proto.objective_updates().has_offset_update()) {
868 UpdateLinearObjectiveCoefficients(
869 update_proto.objective_updates().linear_coefficients());
870 UpdateQuadraticObjectiveCoefficients(
871 update_proto.objective_updates().quadratic_coefficients());
874 UpdateLinearConstraintCoefficients(
875 update_proto.linear_constraint_matrix_updates());
877 return absl::OkStatus();
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define CHECK_GT(val1, val2)
#define CHECK_LE(val1, val2)
#define RETURN_IF_ERROR(expr)
void SetNextFreeId(int64_t new_next_free_id)
void Insert(int64_t id, std::string name)
void set_quadratic_objective_coefficient(VariableId first_variable, VariableId second_variable, double value)
std::vector< LinearConstraintId > linear_constraints() const
std::vector< VariableId > SortedVariables() const
void DeleteVariable(VariableId id)
const std::string & name() const
static absl::StatusOr< std::unique_ptr< ModelStorage > > FromModelProto(const ModelProto &model_proto)
std::vector< VariableId > SortedLinearObjectiveNonzeroVariables() const
void DeleteLinearConstraint(LinearConstraintId id)
void set_linear_objective_coefficient(VariableId variable, double value)
void DeleteUpdateTracker(UpdateTrackerId update_tracker)
std::vector< VariableId > variables() const
absl::Status ApplyUpdateProto(const ModelUpdateProto &update_proto)
std::optional< ModelUpdateProto > ExportModelUpdate(UpdateTrackerId update_tracker)
void set_linear_constraint_coefficient(LinearConstraintId constraint, VariableId variable, double value)
VariableId AddVariable(absl::string_view name="")
void set_variable_upper_bound(VariableId id, double upper_bound)
void set_variable_is_integer(VariableId id, bool is_integer)
const std::string & variable_name(VariableId id) const
void set_linear_constraint_upper_bound(LinearConstraintId id, double upper_bound)
ModelProto ExportModel() const
UpdateTrackerId NewUpdateTracker()
void set_is_maximize(bool is_maximize)
void Checkpoint(UpdateTrackerId update_tracker)
void set_linear_constraint_lower_bound(LinearConstraintId id, double lower_bound)
const std::string & linear_constraint_name(LinearConstraintId id) const
std::unique_ptr< ModelStorage > Clone() const
LinearConstraintId AddLinearConstraint(absl::string_view name="")
std::vector< LinearConstraintId > SortedLinearConstraints() const
void set_variable_lower_bound(VariableId id, double lower_bound)
void set_objective_offset(double value)
CpModelProto const * model_proto
absl::Span< const double > coefficients
void InsertOrDie(Collection *const collection, const typename Collection::value_type &value)
const Collection::value_type::second_type & FindWithDefault(const Collection &collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
const Collection::value_type::second_type * FindOrNull(const Collection &collection, const typename Collection::value_type::first_type &key)
std::pair< VariableId, VariableId > MakeOrderedPair(const VariableId a, const VariableId b)
absl::Status ValidateModelUpdateAndSummary(const ModelUpdateProto &model_update, const ModelSummary &model_summary, const bool check_names)
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
void MergeIntoUpdate(const ModelUpdateProto &from_new, ModelUpdateProto &into_old)
absl::Status ValidateModel(const ModelProto &model, const bool check_names)
Collection of objects used to extend the Constraint Solver library.
IdNameBiMap linear_constraints