19#include "absl/status/status.h"
20#include "absl/strings/str_cat.h"
23#include "ortools/math_opt/model_parameters.pb.h"
24#include "ortools/math_opt/result.pb.h"
25#include "ortools/math_opt/solution.pb.h"
34absl::Status ValidateTermination(
const TerminationProto& termination) {
35 if (termination.reason() == TERMINATION_REASON_UNSPECIFIED) {
36 return absl::InvalidArgumentError(
"termination reason must be specified");
38 if (termination.reason() == TERMINATION_REASON_FEASIBLE ||
39 termination.reason() == TERMINATION_REASON_NO_SOLUTION_FOUND) {
40 if (termination.limit() == LIMIT_UNSPECIFIED) {
41 return absl::InvalidArgumentError(
43 ", limit must be specified"));
45 if (termination.limit() == LIMIT_CUTOFF &&
46 termination.reason() == TERMINATION_REASON_FEASIBLE) {
47 return absl::InvalidArgumentError(
48 "For LIMIT_CUTOFF expected no solutions");
51 if (termination.limit() != LIMIT_UNSPECIFIED) {
52 return absl::InvalidArgumentError(
54 ", limit should be unspecified, but was set to: ",
58 return absl::OkStatus();
61bool HasPrimalFeasibleSolution(
const SolutionProto& solution) {
62 return solution.has_primal_solution() &&
63 solution.primal_solution().feasibility_status() ==
64 SOLUTION_STATUS_FEASIBLE;
67bool HasPrimalFeasibleSolution(
const SolveResultProto& result) {
69 return !result.solutions().empty() &&
70 HasPrimalFeasibleSolution(result.solutions(0));
73bool HasDualFeasibleSolution(
const SolutionProto& solution) {
74 return solution.has_dual_solution() &&
75 solution.dual_solution().feasibility_status() ==
76 SOLUTION_STATUS_FEASIBLE;
79bool HasDualFeasibleSolution(
const SolveResultProto& result) {
80 for (
const auto& solution : result.solutions()) {
81 if (HasDualFeasibleSolution(solution)) {
88absl::Status ValidateSolutions(
89 const google::protobuf::RepeatedPtrField<SolutionProto>& solutions,
91 const ModelSummary& model_summary) {
93 for (
int i = 0; i < solutions.size(); ++i) {
95 <<
"invalid solutions[" << i <<
"]";
98 if (solutions.empty())
return absl::OkStatus();
102 bool previous_primal_feasible = HasPrimalFeasibleSolution(solutions[0]);
103 bool previous_dual_feasible = HasDualFeasibleSolution(solutions[0]);
104 for (
int i = 1; i < solutions.size(); ++i) {
105 const bool current_primal_feasible =
106 HasPrimalFeasibleSolution(solutions[i]);
107 const bool current_dual_feasible = HasDualFeasibleSolution(solutions[i]);
109 if (current_primal_feasible && !previous_primal_feasible) {
110 return absl::InvalidArgumentError(
111 "primal solution ordering not satisfied");
118 if (current_dual_feasible && !previous_dual_feasible) {
119 if (!(previous_primal_feasible && !current_primal_feasible)) {
120 return absl::InvalidArgumentError(
121 "dual solution ordering not satisfied");
124 previous_primal_feasible = current_primal_feasible;
125 previous_dual_feasible = current_dual_feasible;
127 return absl::OkStatus();
130absl::Status RequireNoPrimalFeasibleSolution(
const SolveResultProto& result) {
131 if (HasPrimalFeasibleSolution(result)) {
132 return absl::InvalidArgumentError(
133 "expected no primal feasible solution, but one was returned");
136 return absl::OkStatus();
139absl::Status RequireNoDualFeasibleSolution(
const SolveResultProto& result) {
140 if (HasDualFeasibleSolution(result)) {
141 return absl::InvalidArgumentError(
142 "expected no dual feasible solution, but one was returned");
145 return absl::OkStatus();
150 if (!HasPrimalFeasibleSolution(result)) {
151 return absl::InvalidArgumentError(
152 "primal feasible solution expected, but not found");
155 return absl::OkStatus();
159 const SolveResultProto& result) {
160 if (result.solve_stats().problem_status().primal_status() !=
161 FEASIBILITY_STATUS_FEASIBLE &&
162 HasPrimalFeasibleSolution(result)) {
163 return absl::InvalidArgumentError(
164 "primal feasibility status is not FEASIBILITY_STATUS_FEASIBLE, but "
165 "primal feasible solution is returned.");
167 return absl::OkStatus();
171 const SolveResultProto& result) {
172 if (result.solve_stats().problem_status().dual_status() !=
173 FEASIBILITY_STATUS_FEASIBLE &&
174 HasDualFeasibleSolution(result)) {
175 return absl::InvalidArgumentError(
176 "dual feasibility status is not FEASIBILITY_STATUS_FEASIBLE, but "
177 "dual feasible solution is returned.");
179 return absl::OkStatus();
186 const ProblemStatusProto
status = result.solve_stats().problem_status();
187 switch (result.termination().reason()) {
188 case TERMINATION_REASON_OPTIMAL:
194 return absl::OkStatus();
195 case TERMINATION_REASON_INFEASIBLE:
202 return absl::OkStatus();
203 case TERMINATION_REASON_UNBOUNDED:
209 return absl::OkStatus();
210 case TERMINATION_REASON_INFEASIBLE_OR_UNBOUNDED:
225 return absl::OkStatus();
226 case TERMINATION_REASON_IMPRECISE:
228 return absl::OkStatus();
229 case TERMINATION_REASON_FEASIBLE:
240 return absl::OkStatus();
241 case TERMINATION_REASON_NO_SOLUTION_FOUND:
250 return absl::OkStatus();
251 case TERMINATION_REASON_NUMERICAL_ERROR:
252 case TERMINATION_REASON_OTHER_ERROR: {
257 if (!result.solutions().empty()) {
258 return absl::InvalidArgumentError(
259 absl::StrCat(
"termination reason is ",
261 ", but solutions are available"));
263 if (result.solve_stats().problem_status().primal_or_dual_infeasible()) {
264 return absl::InvalidArgumentError(absl::StrCat(
265 "termination reason is ",
267 ", but solve_stats.problem_status.primal_or_dual_infeasible = "
272 return absl::OkStatus();
275 <<
" not implemented";
278 return absl::OkStatus();
287 ValidateSolutions(result.solutions(),
parameters, model_summary));
289 for (
int i = 0; i < result.primal_rays_size(); ++i) {
293 <<
"Invalid primal_rays[" << i <<
"]";
295 for (
int i = 0; i < result.dual_rays_size(); ++i) {
298 <<
"Invalid dual_rays[" << i <<
"]";
302 <<
"inconsistent termination reason "
305 return absl::OkStatus();
#define RETURN_IF_ERROR(expr)
absl::Status ValidateResult(const SolveResultProto &result, const ModelSolveParametersProto ¶meters, const ModelSummary &model_summary)
absl::Status CheckDualSolutionAndStatusConsistency(const SolveResultProto &result)
absl::Status ValidateTerminationConsistency(const SolveResultProto &result)
absl::Status CheckPrimalStatusIs(const ProblemStatusProto &status, const FeasibilityStatusProto required_status)
absl::Status CheckDualStatusIs(const ProblemStatusProto &status, const FeasibilityStatusProto required_status, const bool primal_or_dual_infeasible_also_ok)
absl::Status CheckPrimalSolutionAndStatusConsistency(const SolveResultProto &result)
absl::Status ValidatePrimalRay(const PrimalRayProto &primal_ray, const SparseVectorFilterProto &filter, const ModelSummary &model_summary)
absl::Status CheckDualStatusIsNot(const ProblemStatusProto &status, const FeasibilityStatusProto forbidden_status)
absl::Status CheckHasPrimalSolution(const SolveResultProto &result)
absl::Status CheckPrimalStatusIsNot(const ProblemStatusProto &status, const FeasibilityStatusProto forbidden_status)
absl::Status ValidateSolveStats(const SolveStatsProto &solve_stats)
absl::Status ValidateDualRay(const DualRayProto &dual_ray, const ModelSolveParametersProto ¶meters, const ModelSummary &model_summary)
absl::Status ValidateSolution(const SolutionProto &solution, const ModelSolveParametersProto ¶meters, const ModelSummary &model_summary)
Collection of objects used to extend the Constraint Solver library.
std::string ProtoEnumToString(ProtoEnumType enum_value)