Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
model_summary.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <cstdint>
17#include <initializer_list>
18#include <limits>
19#include <optional>
20#include <string>
21#include <utility>
22
23#include "absl/container/flat_hash_map.h"
24#include "absl/log/check.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"
32#include "ortools/math_opt/model.pb.h"
33#include "ortools/math_opt/model_update.pb.h"
34
35namespace operations_research {
36namespace math_opt {
37
38namespace internal {
39
41 absl::Span<const int64_t> ids) {
42 int64_t previous{-1};
43 for (int i = 0; i < ids.size(); previous = ids[i], ++i) {
44 if (ids[i] < 0 || ids[i] == std::numeric_limits<int64_t>::max()) {
46 << "Expected ids to be nonnegative and not max(int64_t) but at "
47 "index "
48 << i << " found id: " << ids[i];
49 }
50 if (ids[i] <= previous) {
52 << "Expected ids to be strictly increasing, but at index " << i
53 << " found id: " << ids[i] << " and at previous index " << i - 1
54 << " found id: " << ids[i - 1];
55 }
56 }
57 return absl::OkStatus();
58}
59
60} // namespace internal
61
63 std::initializer_list<std::pair<int64_t, absl::string_view>> ids)
64 : IdNameBiMap(/*check_names=*/true) {
65 for (const auto& pair : ids) {
66 CHECK_OK(Insert(pair.first, std::string(pair.second)));
67 }
68}
69
70IdNameBiMap::IdNameBiMap(const IdNameBiMap& other) { *this = other; }
71
73 if (&other == this) {
74 return *this;
75 }
76 next_free_id_ = other.next_free_id_;
77 id_to_name_ = other.id_to_name_;
78 if (!other.nonempty_name_to_id_.has_value()) {
79 nonempty_name_to_id_ = std::nullopt;
80 } else {
81 nonempty_name_to_id_.emplace();
82 for (const auto& [id, name] : id_to_name_) {
83 if (!name.empty()) {
84 const auto [it, success] =
85 nonempty_name_to_id_->insert({absl::string_view(name), id});
86 CHECK(success); // CHECK is OK, other cannot have duplicate names and
87 // non nullopt nonempty_name_to_id_.
88 }
89 }
90 }
91
92 return *this;
93}
94
96 absl::Span<const int64_t> deleted_ids, absl::Span<const int64_t> new_ids,
97 const absl::Span<const std::string* const> names) {
99 << "invalid deleted ids";
101 << "invalid new ids";
102 if (!names.empty() && names.size() != new_ids.size()) {
104 << "names had size " << names.size()
105 << " but should either be empty of have size matching new_ids which "
106 "has size "
107 << new_ids.size();
108 }
109 for (const int64_t id : deleted_ids) {
111 }
112 for (int i = 0; i < new_ids.size(); ++i) {
114 Insert(new_ids[i], names.empty() ? std::string{} : *names[i]));
115 }
116 return absl::OkStatus();
117}
118
119ModelSummary::ModelSummary(const bool check_names)
120 : variables(check_names),
121 auxiliary_objectives(check_names),
122 linear_constraints(check_names),
123 quadratic_constraints(check_names),
124 second_order_cone_constraints(check_names),
125 sos1_constraints(check_names),
126 sos2_constraints(check_names),
127 indicator_constraints(check_names) {}
128
129absl::StatusOr<ModelSummary> ModelSummary::Create(const ModelProto& model,
130 const bool check_names) {
131 ModelSummary summary(check_names);
132 summary.maximize = model.objective().maximize();
133 RETURN_IF_ERROR(summary.variables.BulkUpdate({}, model.variables().ids(),
134 model.variables().names()))
135 << "ModelProto.variables are invalid";
137 {}, model.auxiliary_objectives(), summary.auxiliary_objectives))
138 << "ModelProto.auxiliary_objectives are invalid";
139 {
140 const std::string& objective_name = model.objective().name();
141 if (summary.auxiliary_objectives.HasName(objective_name)) {
143 << "duplicate objective name: " << objective_name;
144 }
145 summary.primary_objective_name = objective_name;
146 }
148 {}, model.linear_constraints().ids(), model.linear_constraints().names()))
149 << "ModelProto.linear_constraints are invalid";
151 {}, model.quadratic_constraints(), summary.quadratic_constraints))
152 << "ModelProto.quadratic_constraints are invalid";
154 {}, model.second_order_cone_constraints(),
156 << "ModelProto.second_order_cone_constraints are invalid";
158 {}, model.sos1_constraints(), summary.sos1_constraints))
159 << "ModelProto.sos1_constraints are invalid";
161 {}, model.sos2_constraints(), summary.sos2_constraints))
162 << "ModelProto.sos2_constraints are invalid";
164 {}, model.indicator_constraints(), summary.indicator_constraints))
165 << "ModelProto.indicator_constraints are invalid";
166 return summary;
167}
168
169absl::Status ModelSummary::Update(const ModelUpdateProto& model_update) {
170 if (model_update.objective_updates().has_direction_update()) {
171 maximize = model_update.objective_updates().direction_update();
172 }
173 RETURN_IF_ERROR(variables.BulkUpdate(model_update.deleted_variable_ids(),
174 model_update.new_variables().ids(),
175 model_update.new_variables().names()))
176 << "invalid variables";
178 model_update.auxiliary_objectives_updates().deleted_objective_ids(),
179 model_update.auxiliary_objectives_updates().new_objectives(),
181 << "invalid auxiliary objectives";
184 << "duplicate objective name: " << primary_objective_name;
185 }
187 model_update.deleted_linear_constraint_ids(),
188 model_update.new_linear_constraints().ids(),
189 model_update.new_linear_constraints().names()))
190 << "invalid linear constraints";
192 model_update.quadratic_constraint_updates().deleted_constraint_ids(),
193 model_update.quadratic_constraint_updates().new_constraints(),
195 << "invalid quadratic constraints";
197 model_update.second_order_cone_constraint_updates()
198 .deleted_constraint_ids(),
199 model_update.second_order_cone_constraint_updates().new_constraints(),
201 << "invalid second-order cone constraints";
203 model_update.sos1_constraint_updates().deleted_constraint_ids(),
204 model_update.sos1_constraint_updates().new_constraints(),
206 << "invalid sos1 constraints";
208 model_update.sos2_constraint_updates().deleted_constraint_ids(),
209 model_update.sos2_constraint_updates().new_constraints(),
211 << "invalid sos2 constraints";
213 model_update.indicator_constraint_updates().deleted_constraint_ids(),
214 model_update.indicator_constraint_updates().new_constraints(),
216 << "invalid indicator constraints";
217 return absl::OkStatus();
218}
219
220} // namespace math_opt
221} // namespace operations_research
#define RETURN_IF_ERROR(expr)
absl::Status Erase(int64_t id)
Removes the given id, or returns an error if id is not present.
bool HasName(absl::string_view name) const
Will always return false if name is empty or if check_names was false.
IdNameBiMap & operator=(const IdNameBiMap &other)
absl::Status BulkUpdate(absl::Span< const int64_t > deleted_ids, absl::Span< const int64_t > new_ids, absl::Span< const std::string *const > names)
absl::Status Insert(int64_t id, std::string name)
const std::string name
A name for logging purposes.
GRBmodel * model
absl::Status UpdateBiMapFromMappedData(const absl::Span< const int64_t > deleted_ids, const google::protobuf::Map< int64_t, DataProto > &proto_map, IdNameBiMap &bimap)
absl::Status CheckIdsRangeAndStrictlyIncreasing2(absl::Span< const int64_t > ids)
In SWIG mode, we don't want anything besides these top-level includes.
StatusBuilder InvalidArgumentErrorBuilder()
absl::Status Update(const ModelUpdateProto &model_update)
static absl::StatusOr< ModelSummary > Create(const ModelProto &model, bool check_names=true)