14#ifndef OR_TOOLS_MATH_OPT_CORE_MODEL_STORAGE_H_
15#define OR_TOOLS_MATH_OPT_CORE_MODEL_STORAGE_H_
25#include "absl/base/thread_annotations.h"
26#include "absl/container/flat_hash_map.h"
27#include "absl/container/flat_hash_set.h"
28#include "absl/meta/type_traits.h"
29#include "absl/status/statusor.h"
30#include "absl/strings/string_view.h"
31#include "absl/synchronization/mutex.h"
34#include "ortools/math_opt/model.pb.h"
35#include "ortools/math_opt/model_update.pb.h"
164 static absl::StatusOr<std::unique_ptr<ModelStorage>>
FromModelProto(
179 std::unique_ptr<ModelStorage>
Clone()
const;
181 inline const std::string&
name()
const {
return name_; }
198 bool is_integer, absl::string_view
name =
"");
203 inline const std::string&
variable_name(VariableId
id)
const;
233 std::vector<VariableId>
variables()
const;
257 absl::string_view
name =
"");
304 VariableId variable)
const;
306 LinearConstraintId constraint, VariableId variable)
const;
317 inline const absl::flat_hash_map<std::pair<LinearConstraintId, VariableId>,
326 LinearConstraintId constraint);
332 inline const absl::flat_hash_set<LinearConstraintId>&
345 VariableId first_variable, VariableId second_variable)
const;
347 VariableId variable)
const;
350 VariableId first_variable, VariableId second_variable)
const;
365 VariableId second_variable,
380 inline const absl::flat_hash_map<std::pair<VariableId, VariableId>,
double>&
471 UpdateTrackerId update_tracker);
481 void Checkpoint(UpdateTrackerId update_tracker);
494 struct VariableData {
495 double lower_bound = -std::numeric_limits<double>::infinity();
496 double upper_bound = std::numeric_limits<double>::infinity();
497 bool is_integer =
false;
498 std::string
name =
"";
501 struct LinearConstraintData {
502 double lower_bound = -std::numeric_limits<double>::infinity();
503 double upper_bound = std::numeric_limits<double>::infinity();
504 std::string
name =
"";
507 struct UpdateTrackerData {
515 std::vector<std::shared_ptr<const ModelUpdateProto>> updates;
518 template <
typename T>
519 void set_variable_property(VariableId
id, T
value, T VariableData::*field,
520 absl::flat_hash_set<VariableId>& dirty_set);
522 inline void set_linear_constraint_property(
523 const LinearConstraintId
id,
double value,
524 double LinearConstraintData::*field,
525 absl::flat_hash_set<LinearConstraintId>& dirty_set);
532 void AddVariableInternal(VariableId
id,
double lower_bound,
534 absl::string_view
name);
538 void AddVariables(
const VariablesProto&
variables);
546 void AddLinearConstraintInternal(LinearConstraintId
id,
double lower_bound,
556 void UpdateLinearObjectiveCoefficients(
561 void UpdateQuadraticObjectiveCoefficients(
566 void UpdateLinearConstraintCoefficients(
572 void EnsureLazyMatrixColumns();
577 void EnsureLazyMatrixRows();
581 void EnsureLazyQuadraticObjective();
584 void AppendVariable(VariableId
id, VariablesProto& variables_proto)
const;
587 void AppendLinearConstraint(
588 LinearConstraintId
id,
589 LinearConstraintsProto& linear_constraints_proto)
const;
596 std::optional<ModelUpdateProto> ExportSharedModelUpdate()
597 ABSL_EXCLUSIVE_LOCKS_REQUIRED(update_trackers_lock_);
601 void SharedCheckpoint() ABSL_EXCLUSIVE_LOCKS_REQUIRED(update_trackers_lock_);
605 void CheckpointLocked(UpdateTrackerId update_tracker)
606 ABSL_EXCLUSIVE_LOCKS_REQUIRED(update_trackers_lock_);
609 VariableId next_variable_id_ = VariableId(0);
610 LinearConstraintId next_linear_constraint_id_ = LinearConstraintId(0);
612 bool is_maximize_ = false;
613 double objective_offset_ = 0.0;
615 absl::flat_hash_map<VariableId, VariableData> variables_;
616 absl::flat_hash_map<LinearConstraintId, LinearConstraintData>
619 absl::flat_hash_map<VariableId,
double> linear_objective_;
622 absl::flat_hash_map<
std::pair<VariableId, VariableId>,
double>
623 quadratic_objective_;
625 absl::flat_hash_map<
std::pair<LinearConstraintId, VariableId>,
double>
626 linear_constraint_matrix_;
627 absl::flat_hash_map<VariableId,
absl::flat_hash_set<LinearConstraintId>>
628 lazy_matrix_columns_;
629 absl::flat_hash_map<LinearConstraintId,
absl::flat_hash_set<VariableId>>
638 absl::flat_hash_map<VariableId,
absl::flat_hash_set<VariableId>>
639 lazy_quadratic_objective_by_variable_;
646 VariableId variables_checkpoint_ = VariableId(0);
647 LinearConstraintId linear_constraints_checkpoint_ = LinearConstraintId(0);
648 bool dirty_objective_direction_ = false;
649 bool dirty_objective_offset_ = false;
651 absl::flat_hash_set<VariableId> dirty_variable_deletes_;
652 absl::flat_hash_set<VariableId> dirty_variable_lower_bounds_;
653 absl::flat_hash_set<VariableId> dirty_variable_upper_bounds_;
654 absl::flat_hash_set<VariableId> dirty_variable_is_integer_;
656 absl::flat_hash_set<VariableId> dirty_linear_objective_coefficients_;
660 absl::flat_hash_set<
std::pair<VariableId, VariableId>>
661 dirty_quadratic_objective_coefficients_;
663 absl::flat_hash_set<LinearConstraintId> dirty_linear_constraint_deletes_;
664 absl::flat_hash_set<LinearConstraintId> dirty_linear_constraint_lower_bounds_;
665 absl::flat_hash_set<LinearConstraintId> dirty_linear_constraint_upper_bounds_;
671 absl::flat_hash_set<
std::pair<LinearConstraintId, VariableId>>
672 dirty_linear_constraint_matrix_keys_;
678 absl::Mutex update_trackers_lock_;
681 UpdateTrackerId next_update_tracker_
682 ABSL_GUARDED_BY(update_trackers_lock_) = {};
685 absl::flat_hash_map<UpdateTrackerId, std::unique_ptr<UpdateTrackerData>>
686 update_trackers_ ABSL_GUARDED_BY(update_trackers_lock_);
700 return AddVariable(-std::numeric_limits<double>::infinity(),
701 std::numeric_limits<double>::infinity(),
false,
name);
705 return variables_.at(
id).lower_bound;
709 return variables_.at(
id).upper_bound;
713 return variables_.at(
id).is_integer;
717 return variables_.at(
id).name;
721void ModelStorage::set_variable_property(
722 const VariableId
id,
const T
value, T VariableData::*
const field,
723 absl::flat_hash_set<VariableId>& dirty_set) {
724 VariableData& var_data = variables_.at(
id);
725 if (var_data.*field !=
value) {
726 var_data.*field =
value;
727 if (
id < variables_checkpoint_) {
728 dirty_set.insert(
id);
736 dirty_variable_lower_bounds_);
742 dirty_variable_upper_bounds_);
746 const bool is_integer) {
747 set_variable_property(
id, is_integer, &VariableData::is_integer,
748 dirty_variable_is_integer_);
764 return variables_.contains(
id);
773 std::numeric_limits<double>::infinity(),
name);
777 const LinearConstraintId
id)
const {
778 return linear_constraints_.at(
id).lower_bound;
782 const LinearConstraintId
id)
const {
783 return linear_constraints_.at(
id).upper_bound;
787 const LinearConstraintId
id)
const {
788 return linear_constraints_.at(
id).name;
791void ModelStorage::set_linear_constraint_property(
792 const LinearConstraintId
id,
const double value,
793 double LinearConstraintData::*
const field,
794 absl::flat_hash_set<LinearConstraintId>& dirty_set) {
795 LinearConstraintData& lin_con_data = linear_constraints_.at(
id);
796 if (lin_con_data.*field !=
value) {
797 lin_con_data.*field =
value;
798 if (
id < linear_constraints_checkpoint_) {
799 dirty_set.insert(
id);
805 const LinearConstraintId
id,
const double lower_bound) {
808 dirty_linear_constraint_lower_bounds_);
812 const LinearConstraintId
id,
const double upper_bound) {
815 dirty_linear_constraint_upper_bounds_);
819 return linear_constraints_.size();
823 return next_linear_constraint_id_;
827 return linear_constraints_.contains(
id);
835 LinearConstraintId constraint, VariableId variable)
const {
837 {constraint, variable});
841 LinearConstraintId constraint, VariableId variable)
const {
842 return linear_constraint_matrix_.contains({constraint, variable});
846 LinearConstraintId constraint, VariableId variable,
double value) {
847 bool was_updated =
false;
849 if (linear_constraint_matrix_.erase({constraint, variable}) > 0) {
851 if (!lazy_matrix_columns_.empty()) {
852 lazy_matrix_columns_.at(variable).erase(constraint);
854 if (!lazy_matrix_rows_.empty()) {
855 lazy_matrix_rows_.at(constraint).erase(variable);
859 const auto [iterator, inserted] =
860 linear_constraint_matrix_.try_emplace({constraint, variable},
value);
863 }
else if (iterator->second !=
value) {
864 iterator->second =
value;
867 if (!lazy_matrix_columns_.empty()) {
868 lazy_matrix_columns_.at(variable).insert(constraint);
870 if (!lazy_matrix_rows_.empty()) {
871 lazy_matrix_rows_.at(constraint).insert(variable);
874 if (was_updated && constraint < linear_constraints_checkpoint_ &&
875 variable < variables_checkpoint_) {
876 dirty_linear_constraint_matrix_keys_.emplace(constraint, variable);
880const absl::flat_hash_map<std::pair<LinearConstraintId, VariableId>,
double>&
882 return linear_constraint_matrix_;
885const absl::flat_hash_set<VariableId>&
887 EnsureLazyMatrixRows();
888 return lazy_matrix_rows_.at(constraint);
891const absl::flat_hash_set<LinearConstraintId>&
893 EnsureLazyMatrixColumns();
894 return lazy_matrix_columns_.at(variable);
904 const VariableId
b) {
905 return a <
b ? std::make_pair(
a,
b) : std::make_pair(
b,
a);
919 const VariableId first_variable,
const VariableId second_variable)
const {
921 quadratic_objective_,
926 VariableId variable)
const {
927 return linear_objective_.contains(variable);
931 const VariableId first_variable,
const VariableId second_variable)
const {
932 return quadratic_objective_.contains(
938 dirty_objective_direction_ =
true;
948 if (
value != objective_offset_) {
949 dirty_objective_offset_ =
true;
950 objective_offset_ =
value;
956 bool was_updated =
false;
958 if (linear_objective_.erase(variable) > 0) {
962 const auto [iterator, inserted] =
963 linear_objective_.try_emplace(variable,
value);
966 }
else if (iterator->second !=
value) {
967 iterator->second =
value;
971 if (was_updated && variable < variables_checkpoint_) {
972 dirty_linear_objective_coefficients_.insert(variable);
977 const VariableId first_variable,
const VariableId second_variable,
979 const std::pair<VariableId, VariableId> key =
981 bool was_updated =
false;
983 if (quadratic_objective_.erase(key) > 0) {
987 const auto [iterator, inserted] =
988 quadratic_objective_.try_emplace(key,
value);
991 }
else if (iterator->second !=
value) {
992 iterator->second =
value;
997 if (!lazy_quadratic_objective_by_variable_.empty()) {
998 lazy_quadratic_objective_by_variable_.at(first_variable)
999 .insert(second_variable);
1000 lazy_quadratic_objective_by_variable_.at(second_variable)
1001 .insert(first_variable);
1003 if (key.second < variables_checkpoint_) {
1004 dirty_quadratic_objective_coefficients_.insert(key);
1011 while (!linear_objective_.empty()) {
1014 while (!quadratic_objective_.empty()) {
1016 quadratic_objective_.begin()->first.first,
1017 quadratic_objective_.begin()->first.second, 0.0);
1023 return linear_objective_;
1026const absl::flat_hash_map<std::pair<VariableId, VariableId>,
double>&
1028 return quadratic_objective_;
LinearConstraintId next_linear_constraint_id() const
void set_quadratic_objective_coefficient(VariableId first_variable, VariableId second_variable, double value)
std::vector< LinearConstraintId > linear_constraints() const
ModelStorage & operator=(const ModelStorage &)=delete
std::vector< VariableId > SortedVariables() const
void DeleteVariable(VariableId id)
const std::string & name() const
void set_variable_as_continuous(VariableId id)
double linear_objective_coefficient(VariableId variable) const
int num_linear_constraints() const
static absl::StatusOr< std::unique_ptr< ModelStorage > > FromModelProto(const ModelProto &model_proto)
std::vector< VariableId > SortedLinearObjectiveNonzeroVariables() const
double linear_constraint_coefficient(LinearConstraintId constraint, VariableId variable) const
void DeleteLinearConstraint(LinearConstraintId id)
void set_linear_objective_coefficient(VariableId variable, double value)
const absl::flat_hash_map< std::pair< LinearConstraintId, VariableId >, double > & linear_constraint_matrix() const
void DeleteUpdateTracker(UpdateTrackerId update_tracker)
std::vector< VariableId > variables() const
const absl::flat_hash_map< std::pair< VariableId, VariableId >, double > & quadratic_objective() const
int num_variables() const
double linear_constraint_lower_bound(LinearConstraintId id) const
bool is_quadratic_objective_coefficient_nonzero(VariableId first_variable, VariableId second_variable) const
double objective_offset() const
ModelStorage(absl::string_view name="")
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)
bool has_linear_constraint(LinearConstraintId id) const
const std::string & variable_name(VariableId id) const
const absl::flat_hash_set< VariableId > & variables_in_linear_constraint(LinearConstraintId constraint)
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)
double quadratic_objective_coefficient(VariableId first_variable, VariableId second_variable) const
void set_linear_constraint_lower_bound(LinearConstraintId id, double lower_bound)
VariableId next_variable_id() const
double linear_constraint_upper_bound(LinearConstraintId id) const
void set_variable_as_integer(VariableId id)
bool has_variable(VariableId id) const
ModelStorage(const ModelStorage &)=delete
double variable_lower_bound(VariableId id) const
const absl::flat_hash_set< LinearConstraintId > & linear_constraints_with_variable(VariableId variable)
bool is_linear_constraint_coefficient_nonzero(LinearConstraintId constraint, VariableId variable) const
bool is_variable_integer(VariableId id) const
const std::string & linear_constraint_name(LinearConstraintId id) const
std::unique_ptr< ModelStorage > Clone() const
LinearConstraintId AddLinearConstraint(absl::string_view name="")
const absl::flat_hash_map< VariableId, double > & linear_objective() const
std::vector< LinearConstraintId > SortedLinearConstraints() const
bool is_linear_objective_coefficient_nonzero(VariableId variable) const
double variable_upper_bound(VariableId id) 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
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)
std::pair< VariableId, VariableId > MakeOrderedPair(const VariableId a, const VariableId b)
DEFINE_STRONG_INT_TYPE(VariableId, int64_t)
Collection of objects used to extend the Constraint Solver library.