Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
termination_validator.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 "absl/status/status.h"
17#include "absl/strings/str_cat.h"
21#include "ortools/math_opt/result.pb.h"
24
25namespace operations_research {
26namespace math_opt {
27
28namespace {
29absl::Status CheckNotPrimalDualInfeasible(const ProblemStatusProto& status) {
30 if (status.primal_or_dual_infeasible()) {
32 << "expected primal_or_dual_infeasible = false";
33 }
34 return absl::OkStatus();
35}
36
37// Assumes ValidateObjectiveBounds(objective_bounds, is_maximize) and
38// ValidateProblemStatus(status) are ok.
39absl::Status ValidateTerminationReasonConsistency(
40 const TerminationProto& termination) {
41 switch (termination.reason()) {
42 case TERMINATION_REASON_OPTIMAL: {
44 FEASIBILITY_STATUS_FEASIBLE));
46 FEASIBILITY_STATUS_FEASIBLE));
48 // TODO(b/290359402): Add CheckFiniteDualBounds() to enforce finite dual
49 // bounds when possible.
50 return absl::OkStatus();
51 }
52 case TERMINATION_REASON_INFEASIBLE: {
54 FEASIBILITY_STATUS_INFEASIBLE));
55 return absl::OkStatus();
56 }
57 case TERMINATION_REASON_UNBOUNDED: {
59 FEASIBILITY_STATUS_FEASIBLE));
61 FEASIBILITY_STATUS_INFEASIBLE));
62 return absl::OkStatus();
63 }
64 case TERMINATION_REASON_INFEASIBLE_OR_UNBOUNDED:
66 FEASIBILITY_STATUS_UNDETERMINED));
68 termination.problem_status(), FEASIBILITY_STATUS_INFEASIBLE,
69 /*primal_or_dual_infeasible_also_ok=*/true));
70 // Note that if primal status was not FEASIBILITY_STATUS_UNDETERMINED,
71 // then primal_or_dual_infeasible must be false and dual status would be
72 // FEASIBILITY_STATUS_INFEASIBLE. Then if primal status was
73 // FEASIBILITY_STATUS_INFEASIBLE we would have
74 // TERMINATION_REASON_INFEASIBLE and if it was
75 // FEASIBILITY_STATUS_FEASIBLE we would have
76 // TERMINATION_REASON_UNBOUNDED.
77 return absl::OkStatus();
78 case TERMINATION_REASON_IMPRECISE:
80 FEASIBILITY_STATUS_UNDETERMINED));
82 FEASIBILITY_STATUS_UNDETERMINED));
84 CheckNotPrimalDualInfeasible(termination.problem_status()));
85 // TODO(b/211679884): update when imprecise solutions are added.
86 return absl::OkStatus();
87 case TERMINATION_REASON_FEASIBLE: {
89 FEASIBILITY_STATUS_FEASIBLE));
91 FEASIBILITY_STATUS_INFEASIBLE));
92 // Note that if dual status was FEASIBILITY_STATUS_INFEASIBLE, then we
93 // would have TERMINATION_REASON_UNBOUNDED (For MIP this follows the
94 // assumption that every floating point ray can be scaled to be
95 // integer).
97 return absl::OkStatus();
98 }
99 case TERMINATION_REASON_NO_SOLUTION_FOUND: {
100 // Primal status may be feasible as long as no solutions are returned.
102 FEASIBILITY_STATUS_INFEASIBLE));
103 // Note if primal status was FEASIBILITY_STATUS_INFEASIBLE, then we
104 // would have TERMINATION_REASON_INFEASIBLE.
105 return absl::OkStatus();
106 }
107 case TERMINATION_REASON_NUMERICAL_ERROR:
108 case TERMINATION_REASON_OTHER_ERROR: {
110 FEASIBILITY_STATUS_UNDETERMINED));
112 FEASIBILITY_STATUS_UNDETERMINED));
114 CheckNotPrimalDualInfeasible(termination.problem_status()));
115 }
116 return absl::OkStatus();
117 default:
118 LOG(FATAL) << ProtoEnumToString(termination.reason())
119 << " not implemented";
120 }
121
122 return absl::OkStatus();
123}
124
125} // namespace
126
127absl::Status ValidateTermination(const TerminationProto& termination,
128 const bool is_maximize) {
129 if (termination.reason() == TERMINATION_REASON_UNSPECIFIED) {
130 return absl::InvalidArgumentError("termination reason must be specified");
131 }
132 if (termination.reason() == TERMINATION_REASON_FEASIBLE ||
133 termination.reason() == TERMINATION_REASON_NO_SOLUTION_FOUND) {
134 if (termination.limit() == LIMIT_UNSPECIFIED) {
135 return absl::InvalidArgumentError(
136 absl::StrCat("for reason ", ProtoEnumToString(termination.reason()),
137 ", limit must be specified"));
138 }
139 if (termination.limit() == LIMIT_CUTOFF &&
140 termination.reason() == TERMINATION_REASON_FEASIBLE) {
141 return absl::InvalidArgumentError(
142 "For LIMIT_CUTOFF expected no solutions");
143 }
144 } else {
145 if (termination.limit() != LIMIT_UNSPECIFIED) {
146 return absl::InvalidArgumentError(
147 absl::StrCat("for reason:", ProtoEnumToString(termination.reason()),
148 ", limit should be unspecified, but was set to: ",
150 }
151 }
155 termination.problem_status(),
156 is_maximize));
157 RETURN_IF_ERROR(ValidateTerminationReasonConsistency(termination))
158 << "for termination reason " << ProtoEnumToString(termination.reason());
159 return absl::OkStatus();
160}
161
162} // namespace math_opt
163} // namespace operations_research
#define RETURN_IF_ERROR(expr)
absl::Status status
Definition g_gurobi.cc:44
TerminationReason termination
absl::Status CheckDualStatusIsNot(const ProblemStatusProto &status, const FeasibilityStatusProto forbidden_status)
Assumes ValidateProblemStatus(status) is ok.
absl::Status CheckPrimalStatusIs(const ProblemStatusProto &status, const FeasibilityStatusProto required_status)
Assumes ValidateProblemStatus(status) is ok.
absl::Status ValidateProblemStatus(const ProblemStatusProto &status)
absl::Status CheckDualStatusIs(const ProblemStatusProto &status, const FeasibilityStatusProto required_status, const bool primal_or_dual_infeasible_also_ok)
Assumes ValidateProblemStatus(status) is ok.
absl::Status CheckFinitePrimalBound(const ObjectiveBoundsProto &bounds)
absl::Status ValidateObjectiveBounds(const ObjectiveBoundsProto &bounds)
absl::Status ValidateTermination(const TerminationProto &termination, const bool is_maximize)
Checks all messages are valid and compatible.
absl::Status ValidateBoundStatusConsistency(const ObjectiveBoundsProto &objective_bounds, const ProblemStatusProto &status, bool is_maximize)
absl::Status CheckPrimalStatusIsNot(const ProblemStatusProto &status, const FeasibilityStatusProto forbidden_status)
Assumes ValidateProblemStatus(status) is ok.
In SWIG mode, we don't want anything besides these top-level includes.
std::string ProtoEnumToString(ProtoEnumType enum_value)
Definition proto_utils.h:50
StatusBuilder InvalidArgumentErrorBuilder()