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;
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)
const,
81 const absl::string_view object_name) {
82 for (
const auto& [raw_id, bounds_proto] : source) {
83 const typename K::IdType strong_id(raw_id);
84 if (!(
model->*contains_strong_id)(strong_id)) {
86 <<
"no " << object_name <<
" with id: " << raw_id;
91 return absl::OkStatus();
95absl::Status RepeatedIdsProtoToCpp(
96 const google::protobuf::RepeatedField<int64_t>& source,
97 absl::flat_hash_set<K>& target,
const ModelStorage*
const model,
98 bool (ModelStorage::*
const contains_strong_id)(
typename K::IdType
id)
const,
99 const absl::string_view object_name) {
100 for (
const int64_t raw_id : source) {
101 const typename K::IdType strong_id(raw_id);
102 if (!(
model->*contains_strong_id)(strong_id)) {
104 <<
"no " << object_name <<
" with id: " << raw_id;
106 target.insert(K(
model, strong_id));
108 return absl::OkStatus();
112google::protobuf::Map<int64_t, ModelSubsetProto::Bounds> BoundsMapCppToProto(
113 const absl::flat_hash_map<K, ModelSubset::Bounds> source) {
114 google::protobuf::Map<int64_t, ModelSubsetProto::Bounds> result;
115 for (
const auto& [key, bounds] : source) {
116 result.insert({key.id(), bounds.Proto()});
122google::protobuf::RepeatedField<int64_t> RepeatedIdsCppToProto(
123 const absl::flat_hash_set<K>& source) {
124 google::protobuf::RepeatedField<int64_t> result;
125 for (
const auto object : source) {
126 result.Add(
object.
id());
128 absl::c_sort(result);
135 const ModelStorage*
const model,
const ModelSubsetProto&
proto) {
139 &ModelStorage::has_variable,
"variable"))
140 <<
"element of variable_bounds";
143 &ModelStorage::has_variable,
"variable"))
144 <<
"element of variable_integrality";
147 &ModelStorage::has_linear_constraint,
"linear constraint"));
150 &ModelStorage::has_constraint,
"quadratic constraint"));
152 proto.second_order_cone_constraints(),
154 &ModelStorage::has_constraint,
"second-order cone constraint"));
157 &ModelStorage::has_constraint,
"SOS1 constraint"));
160 &ModelStorage::has_constraint,
"SOS2 constraint"));
163 &ModelStorage::has_constraint,
"indicator constraint"));
168 ModelSubsetProto
proto;
170 *
proto.mutable_variable_integrality() =
173 *
proto.mutable_quadratic_constraints() =
175 *
proto.mutable_second_order_cone_constraints() =
179 *
proto.mutable_indicator_constraints() =
185 const ModelStorage*
const expected_storage)
const {
186 const auto validate_map_keys =
187 [expected_storage](
const auto& map,
188 const absl::string_view
name) -> absl::Status {
189 for (
const auto& [key, unused] : map) {
192 <<
"invalid key " << key <<
" in " <<
name;
194 return absl::OkStatus();
196 const auto validate_set_elements =
197 [expected_storage](
const auto& set,
198 const absl::string_view
name) -> absl::Status {
199 for (
const auto entry : set) {
202 <<
"invalid entry " << entry <<
" in " <<
name;
204 return absl::OkStatus();
214 "second_order_cone_constraints"));
219 return absl::OkStatus();
230 std::stringstream str;
231 str <<
"Model Subset:\n";
232 const auto stream_object = [&str](
const auto& object) {
233 str <<
" " <<
object <<
": " <<
object.ToString() <<
"\n";
235 const auto stream_bounded_object =
238 if (bounds.empty()) {
247 const double lb = bounds.lower ? as_expr.lower_bound : -
kInf;
248 const double ub = bounds.upper ? as_expr.upper_bound :
kInf;
249 str <<
" " <<
object <<
": " << (lb <= as_expr.expression <= ub)
253 str <<
" Variable bounds:\n";
255 stream_bounded_object(
256 variable, variable.lower_bound() <= variable <= variable.upper_bound(),
259 str <<
" Variable integrality:\n";
261 str <<
" " << variable <<
"\n";
263 str <<
" Linear constraints:\n";
265 stream_bounded_object(constraint, constraint.AsBoundedLinearExpression(),
269 str <<
" Quadratic constraints:\n";
272 stream_bounded_object(constraint,
273 constraint.AsBoundedQuadraticExpression(),
278 str <<
" Second-order cone constraints:\n";
281 stream_object(constraint);
285 str <<
" SOS1 constraints:\n";
287 stream_object(constraint);
291 str <<
" SOS2 constraints:\n";
293 stream_object(constraint);
297 str <<
" Indicator constraints:\n";
300 stream_object(constraint);
307 const auto stream_bounds_map = [&out](
const auto& map,
308 const absl::string_view
name) {
311 [map](std::string* out,
const auto& key) {
312 absl::StrAppendFormat(
313 out,
"{%s, %s}", absl::FormatStreamed(key),
314 absl::FormatStreamed(map.at(key)));
318 const auto stream_set = [&out](
const auto& set,
319 const absl::string_view
name) {
321 << absl::StrJoin(
SortedElements(set),
", ", absl::StreamFormatter())
333 "quadratic_constraints");
336 "second_order_cone_constraints");
347absl::StatusOr<ComputeInfeasibleSubsystemResult>
349 const ModelStorage*
const model,
350 const ComputeInfeasibleSubsystemResultProto& result_proto) {
352 const std::optional<FeasibilityStatus> feasibility =
354 if (!feasibility.has_value()) {
355 return absl::InvalidArgumentError(
356 "ComputeInfeasibleSubsystemResultProto.feasibility must be specified");
367 "ComputeInfeasibleSubsystemResultProto.infeasible_subsystem");
368 result.
is_minimal = result_proto.is_minimal();
374 ComputeInfeasibleSubsystemResultProto
proto;
376 if (!infeasible_subsystem.empty()) {
377 *
proto.mutable_infeasible_subsystem() = infeasible_subsystem.Proto();
379 proto.set_is_minimal(is_minimal);
384 const ModelStorage*
const expected_storage)
const {
392 <<
", is_minimal: " << (result.
is_minimal ?
"true" :
"false") <<
"}";
#define RETURN_IF_ERROR(expr)
CpModelProto proto
The output proto.
const std::string name
A name for logging purposes.
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)