20#include "absl/status/status.h"
21#include "absl/status/statusor.h"
30#include "ortools/math_opt/model.pb.h"
31#include "ortools/math_opt/model_update.pb.h"
32#include "ortools/math_opt/sparse_containers.pb.h"
46absl::Status VariablesValid(
const VariablesProto& variables) {
48 <<
"Bad variable ids";
51 {.allow_positive_infinity = false},
"lower_bounds"));
54 {.allow_negative_infinity = false},
"upper_bounds"));
57 return absl::OkStatus();
60absl::Status VariableUpdatesValid(
const VariableUpdatesProto& variable_updates,
62 const int64_t old_var_id_ub) {
64 {.allow_positive_infinity = false}))
65 <<
"Bad lower bounds";
67 {.allow_negative_infinity = false}))
68 <<
"Bad upper bounds";
73 <<
"lower bound update on invalid variable id";
76 <<
"upper bound update on invalid variable id";
79 <<
"integer update on invalid variable id";
80 return absl::OkStatus();
83absl::Status ObjectiveValid(
const ObjectiveProto& objective,
87 <<
"Objective offset invalid";
89 const auto linear_coefficients =
MakeView(objective.linear_coefficients());
92 {.allow_positive_infinity =
false, .allow_negative_infinity =
false}))
93 <<
"Linear objective coefficients bad";
95 <<
"Objective.linear_coefficients.ids not found in Variables.ids";
99 <<
"Objective.quadratic_coefficients invalid";
102 <<
"Objective.quadratic_coefficients invalid";
103 if (
const int64_t priority = objective.priority(); priority < 0) {
105 <<
"expected Objective.priority to be nonnegative but found "
109 return absl::OkStatus();
113absl::Status ObjectiveUpdatesValid(
114 const ObjectiveUpdatesProto& objective_updates,
118 <<
"Offset update invalid";
121 MakeView(objective_updates.linear_coefficients()),
122 {.allow_positive_infinity = false, .allow_negative_infinity = false}))
123 <<
"Linear objective coefficients invalid";
127 <<
"Objective.quadratic_coefficients invalid";
130 <<
"Linear coefficients ids not found in variable ids";
133 <<
"quadratic_coefficients invalid";
134 if (objective_updates.has_priority_update()) {
135 const int64_t priority = objective_updates.priority_update();
138 <<
"expected Objective.priority to be nonnegative but found "
143 return absl::OkStatus();
146absl::Status AuxiliaryObjectivesUpdatesValid(
147 const AuxiliaryObjectivesUpdatesProto& objectives,
148 const IdNameBiMap&
variable_ids,
const IdNameBiMap& objective_ids) {
149 for (
const auto& [
id, new_objective] : objectives.new_objectives()) {
151 <<
"bad new auxiliary objective with id: " << id;
153 for (
const auto& [
id, objective_update] : objectives.objective_updates()) {
154 if (!objective_ids.HasId(
id)) {
156 <<
"objective update on auxiliary objective not present in model "
162 return absl::OkStatus();
165absl::Status LinearConstraintsValid(
166 const LinearConstraintsProto& linear_constraints) {
168 <<
"Bad linear constraint ids";
170 MakeView(linear_constraints.ids(), linear_constraints.lower_bounds()),
171 {.allow_positive_infinity = false},
"lower_bounds"));
173 MakeView(linear_constraints.ids(), linear_constraints.upper_bounds()),
174 {.allow_negative_infinity = false},
"upper_bounds"));
175 return absl::OkStatus();
178absl::Status LinearConstraintUpdatesValid(
179 const LinearConstraintUpdatesProto& linear_constraint_updates,
180 const IdNameBiMap& linear_constraint_ids,
const int64_t old_lin_con_id_ub) {
183 {.allow_positive_infinity = false}))
184 <<
"Bad lower bounds";
187 {.allow_negative_infinity = false}))
188 <<
"Bad upper bounds";
190 linear_constraint_ids, old_lin_con_id_ub))
191 <<
"lower bound update on invalid linear constraint id";
193 linear_constraint_ids, old_lin_con_id_ub))
194 <<
"upper bound update on invalid linear constraint id";
195 return absl::OkStatus();
198absl::Status LinearConstraintMatrixIdsValidForUpdate(
199 const SparseDoubleMatrixProto& matrix,
200 const IdNameBiMap& linear_constraint_ids,
const IdNameBiMap&
variable_ids) {
202 <<
"Unknown linear_constraint_id";
204 <<
"Unknown variable_id";
205 return absl::OkStatus();
211template <
typename Constra
intType>
212absl::Status ValidateConstraintMap(
213 const google::protobuf::Map<int64_t, ConstraintType>& constraints,
214 const IdNameBiMap& variable_universe) {
215 for (
const auto& [
id, constraint] : constraints) {
217 <<
"invalid constraint with id: " << id;
219 return absl::OkStatus();
229 const bool check_names) {
233 <<
"ModelProto.variables are invalid.";
235 <<
"ModelProto.objective is invalid";
236 for (
const auto& [
id, objective] :
model.auxiliary_objectives()) {
238 <<
"ModelProto.auxiliary_objectives is invalid with objective id: "
242 <<
"ModelProto.linear_constraints are invalid";
244 <<
"ModelProto.linear_constraint_matrix invalid";
246 model_summary.linear_constraints,
247 model_summary.variables))
248 <<
"ModelProto.linear_constraint_matrix ids are inconsistent";
251 model_summary.variables))
252 <<
"ModelProto.quadratic_constraints invalid";
254 model_summary.variables))
255 <<
"ModelProto.second_order_cone_constraints invalid";
257 ValidateConstraintMap(
model.sos1_constraints(), model_summary.variables))
258 <<
"ModelProto.sos1_constraints invalid";
260 ValidateConstraintMap(
model.sos2_constraints(), model_summary.variables))
261 <<
"ModelProto.sos2_constraints invalid";
263 model_summary.variables))
264 <<
"ModelProto.indicator_constraints invalid";
266 return model_summary;
274 ModelSummary& model_summary) {
276 const int64_t old_var_id_ub = model_update.new_variables().ids_size() > 0
277 ? model_update.new_variables().ids(0)
278 : model_summary.variables.next_free_id();
279 const int64_t old_lin_con_id_ub =
280 model_update.new_linear_constraints().ids_size() > 0
281 ? model_update.new_linear_constraints().ids(0)
282 : model_summary.linear_constraints.next_free_id();
284 model_summary.variables, old_var_id_ub))
285 <<
"ModelUpdateProto.variable_updates invalid";
286 RETURN_IF_ERROR(ObjectiveUpdatesValid(model_update.objective_updates(),
287 model_summary.variables))
288 <<
"ModelUpdateProto.objective_update invalid";
290 model_update.auxiliary_objectives_updates(), model_summary.variables,
291 model_summary.auxiliary_objectives))
292 <<
"ModelUpdateProto.auxiliary_objectives_updates invalid";
294 model_update.linear_constraint_updates(),
295 model_summary.linear_constraints, old_lin_con_id_ub))
296 <<
"ModelUpdateProto.linear_constraint_updates invalid";
298 <<
"ModelUpdateProto.new_variables invalid";
299 RETURN_IF_ERROR(LinearConstraintsValid(model_update.new_linear_constraints()))
300 <<
"ModelUpdateProto.new_linear_constraints invalid";
303 <<
"ModelUpdateProto.linear_constraint_matrix_updates invalid";
306 model_update.linear_constraint_matrix_updates(),
307 model_summary.linear_constraints, model_summary.variables))
308 <<
"invalid linear constraint matrix update";
311 model_update.quadratic_constraint_updates().new_constraints(),
312 model_summary.variables))
313 <<
"ModelUpdateProto.quadratic_constraint_updates.new_constraints "
316 model_update.second_order_cone_constraint_updates().new_constraints(),
317 model_summary.variables))
318 <<
"ModelUpdateProto.second_order_cone_constraint_updates.new_"
319 "constraints invalid";
321 model_update.sos1_constraint_updates().new_constraints(),
322 model_summary.variables))
323 <<
"ModelUpdateProto.sos1_constraint_updates.new_constraints invalid";
325 model_update.sos2_constraint_updates().new_constraints(),
326 model_summary.variables))
327 <<
"ModelUpdateProto.sos2_constraint_updates.new_constraints invalid";
329 model_update.indicator_constraint_updates().new_constraints(),
330 model_summary.variables))
331 <<
"ModelUpdateProto.indicator_constraint_updates.new_constraints "
334 return absl::OkStatus();
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)
absl::Span< const int64_t > variable_ids
absl::Status ValidateModelUpdate(const ModelUpdateProto &model_update, ModelSummary &model_summary)
absl::Status CheckValues(const SparseVectorView< T > &vector_view, absl::string_view value_name="values")
absl::Status SparseMatrixIdsAreKnown(const SparseDoubleMatrixProto &matrix, const IdNameBiMap &row_ids, const IdNameBiMap &column_ids)
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
absl::Status CheckIdsAndValues(const SparseVectorView< T > &vector_view, absl::string_view value_name="values")
absl::Status ValidateConstraint(const IndicatorConstraintProto &constraint, const IdNameBiMap &variable_universe)
absl::Status CheckIdsSubset(absl::Span< const int64_t > ids, const IdNameBiMap &universe, std::optional< int64_t > upper_bound)
absl::Status CheckScalarNoNanNoInf(const double d)
absl::Status SparseMatrixValid(const SparseDoubleMatrixProto &matrix, const bool enforce_upper_triangular)
absl::Status CheckIdsRangeAndStrictlyIncreasing(absl::Span< const int64_t > ids)
absl::StatusOr< ModelSummary > ValidateModel(const ModelProto &model, const bool check_names)
In SWIG mode, we don't want anything besides these top-level includes.
StatusBuilder InvalidArgumentErrorBuilder()
static absl::StatusOr< ModelSummary > Create(const ModelProto &model, bool check_names=true)