20#include "absl/status/status.h"
21#include "absl/strings/str_cat.h"
26#include "ortools/math_opt/model_parameters.pb.h"
27#include "ortools/math_opt/solution.pb.h"
28#include "ortools/math_opt/sparse_containers.pb.h"
37absl::Status ValidateSolutionStatus(
const SolutionStatusProto&
status) {
38 if (!SolutionStatusProto_IsValid(
status)) {
39 return absl::InvalidArgumentError(absl::StrCat(
"status = ",
status));
41 if (
status == SOLUTION_STATUS_UNSPECIFIED) {
42 return absl::InvalidArgumentError(
"status = SOLUTION_STATUS_UNSPECIFIED");
44 return absl::OkStatus();
61absl::Status IsFiltered(
const SparseVectorView<T>& vector_view,
62 const SparseVectorFilterProto& filter,
63 const IdNameBiMap& all_items) {
65 SparseVectorFilterPredicate predicate(filter);
68 for (
int i = 0; i < vector_view.ids_size(); ++i) {
69 const int64_t
id = vector_view.ids(i);
70 if (!predicate.AcceptsAndUpdate(
id, vector_view.values(i))) {
71 return absl::InvalidArgumentError(
72 absl::StrCat(
"sparse vector should not contain the pair (id: ",
id,
73 ", value: ", vector_view.values(i),
") (at index: ", i,
74 ") that should have been filtered"));
80 if (filter.skip_zero_values()) {
81 return absl::OkStatus();
84 const int expected_size =
85 filter.filter_by_ids() ? filter.filtered_ids_size() : all_items.Size();
86 if (vector_view.ids_size() != expected_size) {
87 return absl::InvalidArgumentError(absl::StrCat(
88 "sparse vector should contain ", expected_size,
" values but contains ",
89 vector_view.ids_size(),
" instead"));
92 return absl::OkStatus();
103absl::Status IsValidSolutionVector(
const SparseDoubleVectorProto& vector,
104 const SparseVectorFilterProto& filter,
105 const IdNameBiMap& all_items) {
106 const auto vector_view =
MakeView(vector);
109 {.allow_positive_infinity =
false, .allow_negative_infinity =
false}));
111 return absl::OkStatus();
119 if (!solution.has_primal_solution() && !solution.has_dual_solution() &&
120 !solution.has_basis()) {
121 return absl::InvalidArgumentError(
"empty solution");
123 if (solution.has_primal_solution()) {
127 <<
"Invalid primal_solution";
129 if (solution.has_dual_solution()) {
132 <<
"Invalid dual_solution";
134 if (solution.has_basis()) {
140 if (solution.has_basis() && solution.has_dual_solution()) {
141 if (solution.basis().basic_dual_feasibility() == SOLUTION_STATUS_FEASIBLE &&
142 solution.dual_solution().feasibility_status() !=
143 SOLUTION_STATUS_FEASIBLE) {
144 return absl::InvalidArgumentError(
145 "Incompatible basis and dual solution: basis is dual feasible, but "
146 "dual solution is not feasible");
148 if (solution.dual_solution().feasibility_status() ==
149 SOLUTION_STATUS_INFEASIBLE &&
150 solution.basis().basic_dual_feasibility() !=
151 SOLUTION_STATUS_INFEASIBLE) {
152 return absl::InvalidArgumentError(
153 "Incompatible basis and dual solution: dual solution is infeasible, "
154 "but basis is not dual infeasible");
157 return absl::OkStatus();
161 const SparseVectorFilterProto& filter,
164 IsValidSolutionVector(vector, filter, model_summary.
variables));
165 return absl::OkStatus();
169 const SparseVectorFilterProto& filter,
171 RETURN_IF_ERROR(ValidateSolutionStatus(primal_solution.feasibility_status()))
172 <<
"Invalid PrimalSolutionProto.feasibility_status";
174 primal_solution.variable_values(), filter, model_summary))
175 <<
"Invalid PrimalSolutionProto.variable_values";
177 <<
"Invalid PrimalSolutionProto.objective_value";
178 return absl::OkStatus();
182 const SparseVectorFilterProto& filter,
184 RETURN_IF_ERROR(IsValidSolutionVector(primal_ray.variable_values(), filter,
186 <<
"Invalid PrimalRayProto.variable_values";
187 return absl::OkStatus();
193 RETURN_IF_ERROR(ValidateSolutionStatus(dual_solution.feasibility_status()))
194 <<
"Invalid DualSolutionProto.feasibility_status";
198 <<
"Invalid DualSolutionProto.dual_values";
202 <<
"Invalid DualSolutionProto.reduced_costs";
204 <<
"Invalid DualSolutionProto.objective_value";
205 return absl::OkStatus();
214 <<
"Invalid DualRayProto.dual_values";
218 <<
"Invalid DualRayProto.reduced_costs";
219 return absl::OkStatus();
229 for (
auto [
id,
value] : status_vector_view) {
230 if (!BasisStatusProto_IsValid(
value)) {
231 return absl::InvalidArgumentError(
232 absl::StrCat(
"Invalid status: ",
value,
" for id ",
id));
234 if (
value == BASIS_STATUS_UNSPECIFIED) {
235 return absl::InvalidArgumentError(
236 absl::StrCat(
"Found BASIS_STATUS_UNSPECIFIED for id ",
id));
239 return absl::OkStatus();
244 const bool check_dual_feasibility) {
245 if (check_dual_feasibility) {
246 RETURN_IF_ERROR(ValidateSolutionStatus(basis.basic_dual_feasibility()))
247 <<
"Invalid BasisProto.basic_dual_feasibility";
249 const auto constraint_status_view =
MakeView(basis.constraint_status());
250 const auto variable_status_view =
MakeView(basis.variable_status());
252 << absl::StrCat(
"BasisProto.constraint_status invalid");
254 << absl::StrCat(
"BasisProto.variable_status invalid");
258 "BasisProto.constraint_status.ids",
"model_summary.linear_constraints"));
260 basis.variable_status().ids(), model_summary.
variables,
261 "BasisProto.variable_status.ids",
"model_summary.variables"));
263 int non_basic_variables = 0;
264 for (
const auto [
id,
value] : constraint_status_view) {
265 if (
value != BASIS_STATUS_BASIC) {
266 non_basic_variables++;
269 for (
auto [
id,
value] : variable_status_view) {
270 if (
value != BASIS_STATUS_BASIC) {
271 non_basic_variables++;
275 return absl::InvalidArgumentError(absl::StrCat(
276 "Inconsistent number of non-basic variable+constraints: ",
277 non_basic_variables,
", variables: ", model_summary.
variables.
Size()));
279 return absl::OkStatus();
#define RETURN_IF_ERROR(expr)
absl::Status CheckIdsAndValuesSize(const SparseVectorView< T > &vector_view, absl::string_view value_name="values")
absl::Status ValidateBasis(const BasisProto &basis, const ModelSummary &model_summary, const bool check_dual_feasibility)
absl::Status SparseBasisStatusVectorIsValid(const SparseVectorView< int > &status_vector_view)
absl::Status ValidatePrimalSolution(const PrimalSolutionProto &primal_solution, const SparseVectorFilterProto &filter, const ModelSummary &model_summary)
absl::Status ValidatePrimalSolutionVector(const SparseDoubleVectorProto &vector, const SparseVectorFilterProto &filter, const ModelSummary &model_summary)
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 ValidatePrimalRay(const PrimalRayProto &primal_ray, const SparseVectorFilterProto &filter, const ModelSummary &model_summary)
absl::Status CheckIdsSubset(absl::Span< const int64_t > ids, const IdNameBiMap &universe, absl::string_view ids_description, absl::string_view universe_description)
absl::Status ValidateDualRay(const DualRayProto &dual_ray, const ModelSolveParametersProto ¶meters, const ModelSummary &model_summary)
absl::Status CheckScalarNoNanNoInf(const double d)
absl::Status ValidateSolution(const SolutionProto &solution, const ModelSolveParametersProto ¶meters, const ModelSummary &model_summary)
absl::Status ValidateDualSolution(const DualSolutionProto &dual_solution, const ModelSolveParametersProto ¶meters, const ModelSummary &model_summary)
absl::Status CheckIdsIdentical(absl::Span< const int64_t > first_ids, const IdNameBiMap &second_ids, absl::string_view first_description, absl::string_view second_description)
Collection of objects used to extend the Constraint Solver library.
IdNameBiMap linear_constraints