23 #include "absl/container/flat_hash_map.h"
24 #include "absl/container/flat_hash_set.h"
25 #include "absl/status/status.h"
26 #include "absl/status/statusor.h"
27 #include "absl/strings/string_view.h"
28 #include "absl/types/span.h"
29 #include "absl/log/check.h"
35 #include "ortools/math_opt/model.pb.h"
36 #include "ortools/math_opt/model_update.pb.h"
37 #include "ortools/math_opt/sparse_containers.pb.h"
57 auto storage = std::make_unique<ModelStorage>(
model_proto.name());
63 storage->set_is_maximize(
model_proto.objective().maximize());
64 storage->set_objective_offset(
model_proto.objective().offset());
65 storage->UpdateLinearObjectiveCoefficients(
67 storage->UpdateQuadraticObjectiveCoefficients(
71 storage->AddLinearConstraints(
model_proto.linear_constraints());
74 storage->UpdateLinearConstraintCoefficients(
78 storage->quadratic_constraints_.AddConstraints(
82 storage->sos1_constraints_.AddConstraints(
model_proto.sos1_constraints());
83 storage->sos2_constraints_.AddConstraints(
model_proto.sos2_constraints());
86 storage->indicator_constraints_.AddConstraints(
92 void ModelStorage::UpdateLinearObjectiveCoefficients(
99 void ModelStorage::UpdateQuadraticObjectiveCoefficients(
110 void ModelStorage::UpdateLinearConstraintCoefficients(
121 const std::optional<absl::string_view> new_name)
const {
123 if (new_name.has_value()) {
126 absl::StatusOr<std::unique_ptr<ModelStorage>> clone =
130 CHECK_OK(clone.status());
135 clone.value()->ensure_next_linear_constraint_id_at_least(
137 clone.value()->ensure_next_constraint_id_at_least(
138 next_constraint_id<QuadraticConstraintId>());
139 clone.value()->ensure_next_constraint_id_at_least(
140 next_constraint_id<Sos1ConstraintId>());
141 clone.value()->ensure_next_constraint_id_at_least(
142 next_constraint_id<Sos2ConstraintId>());
143 clone.value()->ensure_next_constraint_id_at_least(
144 next_constraint_id<IndicatorConstraintId>());
146 return std::move(clone).value();
151 const bool is_integer,
152 const absl::string_view
name) {
156 void ModelStorage::AddVariables(
const VariablesProto& variables) {
157 const bool has_names = !
variables.names().empty();
158 for (
int v = 0; v <
variables.ids_size(); ++v) {
166 has_names ?
variables.names(v) : absl::string_view());
177 MakeUpdateDataFieldRange<&UpdateTrackerData::dirty_objective>(trackers));
180 MakeUpdateDataFieldRange<&UpdateTrackerData::dirty_linear_constraints>(
182 quadratic_constraints_.DeleteVariable(
id);
183 sos1_constraints_.DeleteVariable(
id);
184 sos2_constraints_.DeleteVariable(
id);
185 indicator_constraints_.DeleteVariable(
id);
188 MakeUpdateDataFieldRange<&UpdateTrackerData::dirty_variables>(trackers));
201 const absl::string_view
name) {
205 void ModelStorage::AddLinearConstraints(
206 const LinearConstraintsProto& linear_constraints) {
207 const bool has_names = !linear_constraints.names().empty();
208 for (
int c = 0; c < linear_constraints.ids_size(); ++c) {
213 LinearConstraintId(linear_constraints.ids(c)));
216 linear_constraints.lower_bounds(c),
217 linear_constraints.upper_bounds(c),
218 has_names ? linear_constraints.names(c) : absl::string_view());
223 CHECK(linear_constraints_.
contains(
id));
224 linear_constraints_.
Delete(
id, UpdateAndGetLinearConstraintDiffs());
237 result.set_name(name_);
238 *result.mutable_variables() = variables_.
Proto();
239 *result.mutable_objective() = objective_.
Proto();
241 auto [constraints, matrix] = linear_constraints_.
Proto();
242 *result.mutable_linear_constraints() = std::move(constraints);
243 *result.mutable_linear_constraint_matrix() = std::move(matrix);
245 *result.mutable_quadratic_constraints() = quadratic_constraints_.Proto();
246 *result.mutable_sos1_constraints() = sos1_constraints_.Proto();
247 *result.mutable_sos2_constraints() = sos2_constraints_.Proto();
248 *result.mutable_indicator_constraints() = indicator_constraints_.Proto();
252 std::optional<ModelUpdateProto>
253 ModelStorage::UpdateTrackerData::ExportModelUpdate(
260 storage.linear_constraints_.
diff_is_empty(dirty_linear_constraints) &&
261 storage.quadratic_constraints_.diff_is_empty(
262 dirty_quadratic_constraints) &&
263 storage.sos1_constraints_.diff_is_empty(dirty_sos1_constraints) &&
264 storage.sos2_constraints_.diff_is_empty(dirty_sos2_constraints) &&
265 storage.indicator_constraints_.diff_is_empty(
266 dirty_indicator_constraints)) {
270 ModelUpdateProto result;
274 VariableStorage::UpdateResult variable_update =
275 storage.variables_.
Update(dirty_variables);
276 *result.mutable_deleted_variable_ids() = std::move(variable_update.deleted);
277 *result.mutable_variable_updates() = std::move(variable_update.updates);
278 *result.mutable_new_variables() = std::move(variable_update.creates);
280 const std::vector<VariableId> new_variables =
281 storage.variables_.
VariablesFrom(dirty_variables.checkpoint);
285 LinearConstraintStorage::UpdateResult lin_con_update =
286 storage.linear_constraints_.
Update(
287 dirty_linear_constraints, dirty_variables.deleted, new_variables);
288 *result.mutable_deleted_linear_constraint_ids() =
289 std::move(lin_con_update.deleted);
290 *result.mutable_linear_constraint_updates() =
291 std::move(lin_con_update.updates);
292 *result.mutable_new_linear_constraints() =
293 std::move(lin_con_update.creates);
294 *result.mutable_linear_constraint_matrix_updates() =
295 std::move(lin_con_update.matrix_updates);
299 *result.mutable_quadratic_constraint_updates() =
300 storage.quadratic_constraints_.Update(dirty_quadratic_constraints);
303 *result.mutable_sos1_constraint_updates() =
304 storage.sos1_constraints_.Update(dirty_sos1_constraints);
305 *result.mutable_sos2_constraint_updates() =
306 storage.sos2_constraints_.Update(dirty_sos2_constraints);
309 *result.mutable_indicator_constraint_updates() =
310 storage.indicator_constraints_.Update(dirty_indicator_constraints);
313 *result.mutable_objective_updates() = storage.objective_.
Update(
314 dirty_objective, dirty_variables.deleted, new_variables);
316 return {std::move(result)};
319 void ModelStorage::UpdateTrackerData::AdvanceCheckpoint(
320 const ModelStorage& storage) {
321 storage.variables_.AdvanceCheckpointInDiff(dirty_variables);
322 storage.objective_.AdvanceCheckpointInDiff(dirty_variables.checkpoint,
324 storage.linear_constraints_.AdvanceCheckpointInDiff(
325 dirty_variables.checkpoint, dirty_linear_constraints);
326 storage.quadratic_constraints_.AdvanceCheckpointInDiff(
327 dirty_quadratic_constraints);
328 storage.sos1_constraints_.AdvanceCheckpointInDiff(dirty_sos1_constraints);
329 storage.sos2_constraints_.AdvanceCheckpointInDiff(dirty_sos2_constraints);
330 storage.indicator_constraints_.AdvanceCheckpointInDiff(
331 dirty_indicator_constraints);
336 variables_, linear_constraints_, quadratic_constraints_,
337 sos1_constraints_, sos2_constraints_, indicator_constraints_);
345 const UpdateTrackerId update_tracker)
const {
346 return update_trackers_.
GetData(update_tracker).ExportModelUpdate(*
this);
350 update_trackers_.
GetData(update_tracker).AdvanceCheckpoint(*
this);
354 const ModelUpdateProto& update_proto) {
362 <<
"invalid variable id in model";
369 <<
"invalid linear constraint id in model";
372 linear_constraints_.
next_id().value()));
373 for (
const auto id : SortedConstraints<QuadraticConstraintId>()) {
375 id.value(), quadratic_constraints_.data(
id).name))
376 <<
"invalid quadratic constraint id in model";
379 quadratic_constraints_.next_id().value()));
380 for (
const Sos1ConstraintId
id : SortedConstraints<Sos1ConstraintId>()) {
383 <<
"invalid SOS1 constraint id in model";
386 sos1_constraints_.next_id().value()));
387 for (
const Sos2ConstraintId
id : SortedConstraints<Sos2ConstraintId>()) {
390 <<
"invalid SOS2 constraint id in model";
393 sos2_constraints_.next_id().value()));
395 for (
const IndicatorConstraintId
id :
396 SortedConstraints<IndicatorConstraintId>()) {
401 indicator_constraints_.next_id().value()));
404 <<
"update not valid";
408 for (
const int64_t v_id : update_proto.deleted_variable_ids()) {
411 for (
const int64_t c_id : update_proto.deleted_linear_constraint_ids()) {
414 for (
const int64_t c_id :
415 update_proto.quadratic_constraint_updates().deleted_constraint_ids()) {
418 for (
const int64_t c_id :
419 update_proto.sos1_constraint_updates().deleted_constraint_ids()) {
422 for (
const int64_t c_id :
423 update_proto.sos2_constraint_updates().deleted_constraint_ids()) {
426 for (
const int64_t c_id :
427 update_proto.indicator_constraint_updates().deleted_constraint_ids()) {
432 for (
const auto [v_id, lb] :
433 MakeView(update_proto.variable_updates().lower_bounds())) {
436 for (
const auto [v_id, ub] :
437 MakeView(update_proto.variable_updates().upper_bounds())) {
440 for (
const auto [v_id, is_integer] :
441 MakeView(update_proto.variable_updates().integers())) {
446 for (
const auto [c_id, lb] :
447 MakeView(update_proto.linear_constraint_updates().lower_bounds())) {
450 for (
const auto [c_id, ub] :
451 MakeView(update_proto.linear_constraint_updates().upper_bounds())) {
456 AddVariables(update_proto.new_variables());
457 AddLinearConstraints(update_proto.new_linear_constraints());
458 quadratic_constraints_.AddConstraints(
459 update_proto.quadratic_constraint_updates().new_constraints());
460 sos1_constraints_.AddConstraints(
461 update_proto.sos1_constraint_updates().new_constraints());
462 sos2_constraints_.AddConstraints(
463 update_proto.sos2_constraint_updates().new_constraints());
464 indicator_constraints_.AddConstraints(
465 update_proto.indicator_constraint_updates().new_constraints());
468 if (update_proto.objective_updates().has_direction_update()) {
471 if (update_proto.objective_updates().has_offset_update()) {
474 UpdateLinearObjectiveCoefficients(
475 update_proto.objective_updates().linear_coefficients());
476 UpdateQuadraticObjectiveCoefficients(
477 update_proto.objective_updates().quadratic_coefficients());
480 UpdateLinearConstraintCoefficients(
481 update_proto.linear_constraint_matrix_updates());
483 return absl::OkStatus();
#define RETURN_IF_ERROR(expr)
absl::Status Insert(int64_t id, std::string name)
absl::Status SetNextFreeId(int64_t new_next_free_id)
bool diff_is_empty(const Diff &diff) const
void DeleteVariable(VariableId variable, const iterator_range< DiffIter > &diffs)
void Delete(LinearConstraintId id, const iterator_range< DiffIter > &diffs)
UpdateResult Update(const Diff &diff, const absl::flat_hash_set< VariableId > &deleted_variables, const std::vector< VariableId > &new_variables) const
LinearConstraintId next_id() const
bool contains(LinearConstraintId id) const
LinearConstraintId Add(double lower_bound, double upper_bound, absl::string_view name)
std::vector< LinearConstraintId > LinearConstraints() const
std::pair< LinearConstraintsProto, SparseDoubleMatrixProto > Proto() const
std::vector< LinearConstraintId > SortedLinearConstraints() const
LinearConstraintId next_linear_constraint_id() const
void set_quadratic_objective_coefficient(VariableId first_variable, VariableId second_variable, double value)
std::vector< VariableId > SortedVariables() const
void DeleteVariable(VariableId id)
static absl::StatusOr< std::unique_ptr< ModelStorage > > FromModelProto(const ModelProto &model_proto)
std::optional< ModelUpdateProto > ExportModelUpdate(UpdateTrackerId update_tracker) const
void DeleteLinearConstraint(LinearConstraintId id)
void set_linear_objective_coefficient(VariableId variable, double value)
const AtomicConstraintTraits< IdType >::ConstraintData & constraint_data(IdType id) const
void DeleteUpdateTracker(UpdateTrackerId update_tracker)
std::vector< VariableId > variables() const
absl::Status ApplyUpdateProto(const ModelUpdateProto &update_proto)
void set_linear_constraint_coefficient(LinearConstraintId constraint, VariableId variable, double value)
VariableId AddVariable(absl::string_view name="")
void AdvanceCheckpoint(UpdateTrackerId update_tracker)
void set_variable_upper_bound(VariableId id, double upper_bound)
void set_variable_is_integer(VariableId id, bool is_integer)
void ensure_next_variable_id_at_least(VariableId id)
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 set_linear_constraint_lower_bound(LinearConstraintId id, double lower_bound)
VariableId next_variable_id() const
std::vector< LinearConstraintId > LinearConstraints() const
std::unique_ptr< ModelStorage > Clone(std::optional< absl::string_view > new_name=std::nullopt) const
const std::string & name() const
void ensure_next_linear_constraint_id_at_least(LinearConstraintId id)
void DeleteAtomicConstraint(IdType id)
const std::string & linear_constraint_name(LinearConstraintId id) 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)
bool diff_is_empty(const Diff &diff) const
void DeleteVariable(VariableId variable, const iterator_range< DiffIter > &diffs)
ObjectiveUpdatesProto Update(const Diff &diff, const absl::flat_hash_set< VariableId > &deleted_variables, const std::vector< VariableId > &new_variables) const
ObjectiveProto Proto() const
Data & GetData(UpdateTrackerId update_tracker)
void DeleteUpdateTracker(UpdateTrackerId update_tracker)
const std::vector< IdDataPair > & GetUpdatedTrackers()
UpdateTrackerId NewUpdateTracker(T &&... args)
bool diff_is_empty(const Diff &diff) const
void Delete(VariableId id, const iterator_range< DiffIter > &diffs)
std::vector< VariableId > SortedVariables() const
std::vector< VariableId > VariablesFrom(VariableId start) const
VariableId Add(double lower_bound, double upper_bound, bool is_integer, absl::string_view name)
std::vector< VariableId > Variables() const
VariablesProto Proto() const
VariableId next_id() const
UpdateResult Update(const Diff &diff) const
bool contains(VariableId id) const
CpModelProto const * model_proto
absl::Span< const double > coefficients
absl::Status ValidateModelUpdate(const ModelUpdateProto &model_update, ModelSummary &model_summary)
absl::StatusOr< ModelSummary > ValidateModel(const ModelProto &model, const bool check_names)
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
Collection of objects used to extend the Constraint Solver library.
IdNameBiMap indicator_constraints
IdNameBiMap sos1_constraints
IdNameBiMap sos2_constraints
IdNameBiMap linear_constraints
IdNameBiMap quadratic_constraints