24#include "absl/algorithm/container.h"
25#include "absl/container/flat_hash_map.h"
26#include "absl/container/flat_hash_set.h"
27#include "absl/status/status.h"
28#include "absl/status/statusor.h"
29#include "absl/strings/str_format.h"
30#include "absl/strings/str_join.h"
31#include "absl/strings/string_view.h"
44#include "ortools/math_opt/infeasible_subsystem.pb.h"
45#include "ortools/math_opt/result.pb.h"
52constexpr double kInf = std::numeric_limits<double>::infinity();
55 const ModelSubsetProto::Bounds& bounds_proto) {
56 return {.lower = bounds_proto.lower(), .upper = bounds_proto.upper()};
60 ModelSubsetProto::Bounds proto;
61 proto.set_lower(
lower);
62 proto.set_upper(
upper);
67 const auto bool_to_str = [](
const bool b) {
return b ?
"true" :
"false"; };
68 out <<
"{lower: " << bool_to_str(bounds.
lower)
69 <<
", upper: " << bool_to_str(bounds.
upper) <<
"}";
76absl::Status BoundsMapProtoToCpp(
77 const google::protobuf::Map<int64_t, ModelSubsetProto::Bounds>& source,
78 absl::flat_hash_map<K, ModelSubset::Bounds>& target,
79 const ModelStorage*
const model,
80 bool (ModelStorage::*
const contains_strong_id)(
typename K::IdType
id)
82 const absl::string_view object_name) {
83 for (
const auto& [raw_id, bounds_proto] : source) {
84 const typename K::IdType strong_id(raw_id);
85 if (!(model->*contains_strong_id)(strong_id)) {
87 <<
"no " << object_name <<
" with id: " << raw_id;
92 return absl::OkStatus();
96absl::Status RepeatedIdsProtoToCpp(
97 const google::protobuf::RepeatedField<int64_t>& source,
98 absl::flat_hash_set<K>& target,
const ModelStorage*
const model,
99 bool (ModelStorage::*
const contains_strong_id)(
typename K::IdType
id)
101 const absl::string_view object_name) {
102 for (
const int64_t raw_id : source) {
103 const typename K::IdType strong_id(raw_id);
104 if (!(model->*contains_strong_id)(strong_id)) {
106 <<
"no " << object_name <<
" with id: " << raw_id;
108 target.insert(K(model, strong_id));
110 return absl::OkStatus();
114google::protobuf::Map<int64_t, ModelSubsetProto::Bounds> BoundsMapCppToProto(
115 const absl::flat_hash_map<K, ModelSubset::Bounds> source) {
116 google::protobuf::Map<int64_t, ModelSubsetProto::Bounds> result;
117 for (
const auto& [key, bounds] : source) {
118 result.insert({key.id(), bounds.Proto()});
124google::protobuf::RepeatedField<int64_t> RepeatedIdsCppToProto(
125 const absl::flat_hash_set<K>& source) {
126 google::protobuf::RepeatedField<int64_t> result;
127 for (
const auto object : source) {
128 result.Add(
object.
id());
130 absl::c_sort(result);
137 const ModelStorage*
const model,
const ModelSubsetProto& proto) {
141 &ModelStorage::has_variable,
"variable"))
142 <<
"element of variable_bounds";
145 &ModelStorage::has_variable,
"variable"))
146 <<
"element of variable_integrality";
149 &ModelStorage::has_linear_constraint,
"linear constraint"));
152 &ModelStorage::has_constraint,
"quadratic constraint"));
154 proto.second_order_cone_constraints(),
156 &ModelStorage::has_constraint,
"second-order cone constraint"));
159 &ModelStorage::has_constraint,
"SOS1 constraint"));
162 &ModelStorage::has_constraint,
"SOS2 constraint"));
165 &ModelStorage::has_constraint,
"indicator constraint"));
170 ModelSubsetProto proto;
171 *proto.mutable_variable_bounds() = BoundsMapCppToProto(
variable_bounds);
172 *proto.mutable_variable_integrality() =
175 *proto.mutable_quadratic_constraints() =
177 *proto.mutable_second_order_cone_constraints() =
179 *proto.mutable_sos1_constraints() = RepeatedIdsCppToProto(
sos1_constraints);
180 *proto.mutable_sos2_constraints() = RepeatedIdsCppToProto(
sos2_constraints);
181 *proto.mutable_indicator_constraints() =
187 const ModelStorage*
const expected_storage)
const {
188 const auto validate_map_keys =
189 [expected_storage](
const auto& map,
190 const absl::string_view name) -> absl::Status {
191 for (
const auto& [key, unused] : map) {
194 <<
"invalid key " << key <<
" in " << name;
196 return absl::OkStatus();
198 const auto validate_set_elements =
199 [expected_storage](
const auto& set,
200 const absl::string_view name) -> absl::Status {
201 for (
const auto entry : set) {
204 <<
"invalid entry " << entry <<
" in " << name;
206 return absl::OkStatus();
216 "second_order_cone_constraints"));
221 return absl::OkStatus();
232 std::stringstream str;
233 str <<
"Model Subset:\n";
234 const auto stream_object = [&str](
const auto& object) {
235 str <<
" " <<
object <<
": " <<
object.ToString() <<
"\n";
237 const auto stream_bounded_object =
240 if (bounds.empty()) {
249 const double lb = bounds.lower ? as_expr.lower_bound : -
kInf;
250 const double ub = bounds.upper ? as_expr.upper_bound :
kInf;
251 str <<
" " <<
object <<
": " << (lb <= as_expr.expression <= ub)
255 str <<
" Variable bounds:\n";
257 stream_bounded_object(
258 variable, variable.lower_bound() <= variable <= variable.upper_bound(),
261 str <<
" Variable integrality:\n";
263 str <<
" " << variable <<
"\n";
265 str <<
" Linear constraints:\n";
267 stream_bounded_object(constraint, constraint.AsBoundedLinearExpression(),
271 str <<
" Quadratic constraints:\n";
274 stream_bounded_object(constraint,
275 constraint.AsBoundedQuadraticExpression(),
280 str <<
" Second-order cone constraints:\n";
283 stream_object(constraint);
287 str <<
" SOS1 constraints:\n";
289 stream_object(constraint);
293 str <<
" SOS2 constraints:\n";
295 stream_object(constraint);
299 str <<
" Indicator constraints:\n";
302 stream_object(constraint);
309 const auto stream_bounds_map = [&out](
const auto& map,
310 const absl::string_view name) {
313 [map](std::string* out,
const auto& key) {
314 absl::StrAppendFormat(
315 out,
"{%s, %s}", absl::FormatStreamed(key),
316 absl::FormatStreamed(map.at(key)));
320 const auto stream_set = [&out](
const auto& set,
321 const absl::string_view name) {
323 << absl::StrJoin(
SortedElements(set),
", ", absl::StreamFormatter())
335 "quadratic_constraints");
338 "second_order_cone_constraints");
349absl::StatusOr<ComputeInfeasibleSubsystemResult>
351 const ModelStorage*
const model,
352 const ComputeInfeasibleSubsystemResultProto& result_proto) {
354 const std::optional<FeasibilityStatus>
feasibility =
357 return absl::InvalidArgumentError(
358 "ComputeInfeasibleSubsystemResultProto.feasibility must be specified");
369 "ComputeInfeasibleSubsystemResultProto.infeasible_subsystem");
370 result.
is_minimal = result_proto.is_minimal();
376 ComputeInfeasibleSubsystemResultProto proto;
386 const ModelStorage*
const expected_storage)
const {
394 <<
", is_minimal: " << (result.
is_minimal ?
"true" :
"false") <<
"}";
#define RETURN_IF_ERROR(expr)
absl::Status CheckModelStorage(const ModelStorage *const storage, const ModelStorage *const expected_storage)
An object oriented wrapper for quadratic constraints in ModelStorage.
std::vector< typename Set::key_type > SortedElements(const Set &set)
std::optional< typename EnumProto< P >::Cpp > EnumFromProto(P proto_value)
std::ostream & operator<<(std::ostream &ostr, const IndicatorConstraint &constraint)
Enum< E >::Proto EnumToProto(std::optional< E > value)
absl::Status ValidateComputeInfeasibleSubsystemResultNoModel(const ComputeInfeasibleSubsystemResultProto &result)
Validates the internal consistency of the fields.
std::vector< typename Map::key_type > SortedKeys(const Map &map)
StatusBuilder InvalidArgumentErrorBuilder()
A QuadraticExpression with upper and lower bounds.
absl::Status CheckModelStorage(const ModelStorage *expected_storage) const
static absl::StatusOr< ComputeInfeasibleSubsystemResult > FromProto(const ModelStorage *model, const ComputeInfeasibleSubsystemResultProto &result_proto)
ModelSubset infeasible_subsystem
FeasibilityStatus feasibility
The primal feasibility status of the model, as determined by the solver.
ComputeInfeasibleSubsystemResultProto Proto() const
ModelSubsetProto::Bounds Proto() const
static Bounds FromProto(const ModelSubsetProto::Bounds &bounds_proto)
absl::flat_hash_map< Variable, Bounds > variable_bounds
absl::flat_hash_set< SecondOrderConeConstraint > second_order_cone_constraints
absl::flat_hash_set< Variable > variable_integrality
bool empty() const
True if this object corresponds to the empty subset.
absl::flat_hash_set< Sos1Constraint > sos1_constraints
ModelSubsetProto Proto() const
absl::Status CheckModelStorage(const ModelStorage *expected_storage) const
absl::flat_hash_map< LinearConstraint, Bounds > linear_constraints
std::string ToString() const
absl::flat_hash_set< IndicatorConstraint > indicator_constraints
static absl::StatusOr< ModelSubset > FromProto(const ModelStorage *model, const ModelSubsetProto &proto)
absl::flat_hash_map< QuadraticConstraint, Bounds > quadratic_constraints
absl::flat_hash_set< Sos2Constraint > sos2_constraints
#define OR_ASSIGN_OR_RETURN3(lhs, rexpr, error_expression)