16#include <initializer_list>
25#include "absl/log/check.h"
26#include "absl/status/status.h"
27#include "absl/status/statusor.h"
28#include "absl/strings/escaping.h"
29#include "absl/strings/str_cat.h"
30#include "absl/strings/str_join.h"
31#include "absl/strings/string_view.h"
32#include "absl/time/time.h"
33#include "absl/types/span.h"
48constexpr double kInf = std::numeric_limits<double>::infinity();
68 ostr <<
"{primal_bound: "
70 ostr <<
", dual_bound: "
77 std::ostringstream stream;
112 .dual_bound = objective_value};
119 return "undetermined";
134 return absl::MakeConstSpan(kFeasibilityStatus);
147 return "infeasible_or_unbounded";
153 return "no_solution_found";
155 return "numerical_error";
157 return "other_error";
174 return absl::MakeConstSpan(kTerminationReasonValues);
180 return "undetermined";
198 return "interrupted";
200 return "slow_progress";
208 static constexpr Limit kLimitValues[] = {
213 return absl::MakeConstSpan(kLimitValues);
223 const double dual_objective_value,
224 const std::string
detail) {
235 const std::string
detail) {
241 const std::string
detail) {
254 const std::string
detail) {
266 const std::string
detail) {
276 const std::optional<double> optional_dual_objective,
277 const std::string
detail) {
282 if (optional_dual_objective.has_value()) {
292 const double finite_primal_objective,
293 const std::optional<double> optional_dual_objective,
294 const std::string
detail) {
299 if (optional_dual_objective.has_value()) {
308 const std::string
detail) {
329 if (this->reason ==
reason)
return absl::OkStatus();
331 <<
"expected termination reason '" <<
reason <<
"' but got " << *
this;
335 std::initializer_list<TerminationReason> reasons)
const {
340 <<
"expected termination reason in {"
341 << absl::StrJoin(reasons,
", ",
343 absl::StrAppend(out,
"'");
344 absl::StreamFormatter()(out,
reason);
345 absl::StrAppend(out,
"'");
347 <<
"} but got " << *
this;
370 const std::optional<TerminationReason>
reason =
372 if (!
reason.has_value()) {
373 return absl::InvalidArgumentError(
"reason must be specified");
376 termination_proto.
detail());
381 _ <<
"invalid problem_status");
388 ostr <<
"{reason: " << termination.
reason;
389 if (termination.
limit.has_value()) {
390 ostr <<
", limit: " << *termination.
limit;
392 if (!termination.
detail.empty()) {
393 ostr <<
", detail: " <<
'"' << absl::CEscape(termination.
detail) <<
'"';
402 std::ostringstream stream;
420 return absl::InvalidArgumentError(
"primal_status must be specified");
422 const std::optional<FeasibilityStatus>
dual_status =
425 return absl::InvalidArgumentError(
"dual_status must be specified");
429 .primal_or_dual_infeasible =
436 ostr <<
", dual_status: " << problem_status.
dual_status;
437 ostr <<
", primal_or_dual_infeasible: "
444 std::ostringstream stream;
453 <<
"invalid solve_time (value must be finite)";
467 _ <<
"invalid solve_time");
476 ostr <<
"{solve_time: " << solve_stats.
solve_time;
480 ostr <<
", node_count: " << solve_stats.
node_count;
486 std::ostringstream stream;
494 return absl::OkStatus();
497 <<
"cannot set solver specific output twice, was already "
505 _ <<
"invalid solve_stats");
547 UpgradedTerminationProtoForStatsMigration(solve_result_proto)),
548 _ <<
"invalid termination");
552 _ <<
"invalid solve_stats");
558 _ <<
"invalid solution at index " << i);
559 result.solutions.push_back(std::move(
solution));
565 _ <<
"invalid primal ray at index " << i);
566 result.
primal_rays.push_back(std::move(primal_ray));
572 _ <<
"invalid dual ray at index " << i);
573 result.
dual_rays.push_back(std::move(dual_ray));
586 <<
"unexpected value of solver_specific_output_case "
591 return !solutions.empty() && solutions[0].primal_solution.has_value() &&
592 (solutions[0].primal_solution->feasibility_status ==
598 return *solutions.front().primal_solution;
615 return solutions[0].primal_solution->objective_value;
620 return solutions[0].primal_solution->get_objective_value(objective);
631 return solutions[0].primal_solution->variable_values;
640 return !solutions.empty() && solutions[0].dual_solution.has_value() &&
641 (solutions[0].dual_solution->feasibility_status ==
647 return solutions[0].dual_solution->dual_values;
652 return solutions[0].dual_solution->reduced_costs;
665 return !solutions.empty() && solutions[0].basis.has_value();
670 return solutions[0].basis->constraint_status;
675 return solutions[0].basis->variable_status;
681void PrintVectorSize(std::ostream& out,
const std::vector<T>& v) {
684 out << v.size() <<
" available";
692 <<
", solve_stats: " << result.
solve_stats <<
", solutions: ";
693 PrintVectorSize(out, result.solutions);
694 out <<
", primal_rays: ";
696 out <<
", dual_rays: ";
699 const std::string gscip_specific_output =
701 if (!gscip_specific_output.empty()) {
702 out <<
", gscip_solver_specific_output: " << gscip_specific_output;
#define RETURN_IF_ERROR(expr)
void set_dual_bound(double value)
double dual_bound() const
void set_primal_bound(double value)
double primal_bound() const
void set_primal_status(::operations_research::math_opt::FeasibilityStatusProto value)
::operations_research::math_opt::FeasibilityStatusProto dual_status() const
void set_primal_or_dual_infeasible(bool value)
bool primal_or_dual_infeasible() const
void set_dual_status(::operations_research::math_opt::FeasibilityStatusProto value)
::operations_research::math_opt::FeasibilityStatusProto primal_status() const
::operations_research::math_opt::SolutionProto *PROTOBUF_NONNULL add_solutions()
::operations_research::math_opt::SolveResultProto_PdlpOutput *PROTOBUF_NONNULL mutable_pdlp_output()
const ::operations_research::math_opt::PrimalRayProto & primal_rays(int index) const
::operations_research::math_opt::PrimalRayProto *PROTOBUF_NONNULL add_primal_rays()
const ::operations_research::math_opt::SolutionProto & solutions(int index) const
::operations_research::math_opt::DualRayProto *PROTOBUF_NONNULL add_dual_rays()
const ::operations_research::math_opt::SolveResultProto_PdlpOutput & pdlp_output() const
::operations_research::math_opt::TerminationProto *PROTOBUF_NONNULL mutable_termination()
const ::operations_research::math_opt::DualRayProto & dual_rays(int index) const
::operations_research::GScipOutput *PROTOBUF_NONNULL mutable_gscip_output()
SolverSpecificOutputCase solver_specific_output_case() const
int dual_rays_size() const
const ::operations_research::math_opt::SolveStatsProto & solve_stats() const
::operations_research::math_opt::SolveStatsProto *PROTOBUF_NONNULL mutable_solve_stats()
const ::operations_research::GScipOutput & gscip_output() const
int primal_rays_size() const
const ::operations_research::math_opt::TerminationProto & termination() const
int solutions_size() const
@ SOLVER_SPECIFIC_OUTPUT_NOT_SET
::int64_t node_count() const
void set_simplex_iterations(::int64_t value)
::google::protobuf::Duration *PROTOBUF_NONNULL mutable_solve_time()
void set_node_count(::int64_t value)
void set_first_order_iterations(::int64_t value)
void set_barrier_iterations(::int64_t value)
::int64_t barrier_iterations() const
::int64_t first_order_iterations() const
const ::google::protobuf::Duration & solve_time() const
::int64_t simplex_iterations() const
const ::operations_research::math_opt::ObjectiveBoundsProto & objective_bounds() const
void set_limit(::operations_research::math_opt::LimitProto value)
void set_detail(Arg_ &&arg, Args_... args)
::operations_research::math_opt::ObjectiveBoundsProto *PROTOBUF_NONNULL mutable_objective_bounds()
::operations_research::math_opt::ProblemStatusProto *PROTOBUF_NONNULL mutable_problem_status()
const ::operations_research::math_opt::ProblemStatusProto & problem_status() const
::operations_research::math_opt::TerminationReasonProto reason() const
const ::std::string & detail() const
void set_reason(::operations_research::math_opt::TerminationReasonProto value)
::operations_research::math_opt::LimitProto limit() const
absl::Status CheckSolverSpecificOutputEmpty(const SolveResultProto &result)
const ModelStorage *absl_nonnull ModelStorageCPtr
absl::flat_hash_map< Variable, V > VariableMap
absl::flat_hash_map< LinearConstraint, V > LinearConstraintMap
std::optional< typename EnumProto< P >::Cpp > EnumFromProto(P proto_value)
ProblemStatusProto GetProblemStatus(const SolveResultProto &solve_result)
ObjectiveBoundsProto GetObjectiveBounds(const SolveResultProto &solve_result)
std::ostream & operator<<(std::ostream &ostr, const SecondOrderConeConstraint &constraint)
Enum< E >::Proto EnumToProto(std::optional< E > value)
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
std::string ProtobufShortDebugString(const P &message)
inline ::absl::StatusOr< absl::Duration > DecodeGoogleApiProto(const google::protobuf::Duration &proto)
inline ::absl::StatusOr< google::protobuf::Duration > EncodeGoogleApiProto(absl::Duration d)
StatusBuilder InternalErrorBuilder()
StatusBuilder InvalidArgumentErrorBuilder()
static absl::StatusOr< DualRay > FromProto(ModelStorageCPtr model, const DualRayProto &dual_ray_proto)
static absl::Span< const E > AllValues()
static std::optional< absl::string_view > ToOptString(E value)
static ObjectiveBounds MakeTrivial(bool is_maximize)
ObjectiveBoundsProto Proto() const
static ObjectiveBounds MinimizeMakeTrivial()
static ObjectiveBounds MakeUnbounded(bool is_maximize)
static ObjectiveBounds MinimizeMakeUnbounded()
static ObjectiveBounds MakeOptimal(double objective_value)
static ObjectiveBounds FromProto(const ObjectiveBoundsProto &objective_bounds_proto)
static ObjectiveBounds MaximizeMakeTrivial()
static ObjectiveBounds MaximizeMakeUnbounded()
std::string ToString() const
static absl::StatusOr< PrimalRay > FromProto(ModelStorageCPtr model, const PrimalRayProto &primal_ray_proto)
ProblemStatusProto Proto() const
std::string ToString() const
FeasibilityStatus primal_status
bool primal_or_dual_infeasible
static absl::StatusOr< ProblemStatus > FromProto(const ProblemStatusProto &problem_status_proto)
FeasibilityStatus dual_status
static absl::StatusOr< Solution > FromProto(ModelStorageCPtr model, const SolutionProto &solution_proto)
const VariableMap< double > & ray_reduced_costs() const
const LinearConstraintMap< double > & ray_dual_values() const
bool has_dual_ray() const
double objective_value() const
const VariableMap< double > & variable_values() const
static absl::StatusOr< SolveResult > FromProto(ModelStorageCPtr model, const SolveResultProto &solve_result_proto)
double best_objective_bound() const
SolveResultProto::PdlpOutput pdlp_solver_specific_output
double primal_bound() const
bool has_dual_feasible_solution() const
GScipOutput gscip_solver_specific_output
const LinearConstraintMap< BasisStatus > & constraint_status() const
const LinearConstraintMap< double > & dual_values() const
std::vector< DualRay > dual_rays
const VariableMap< double > & ray_variable_values() const
SolveResult(Termination termination)
bool has_primal_feasible_solution() const
const VariableMap< BasisStatus > & variable_status() const
absl::StatusOr< SolveResultProto > Proto() const
const VariableMap< double > & reduced_costs() const
*All convex optimization solvers(LP, convex QP) return only one *Only MI(Q) P solvers return more than one solution. MIP solvers do not std std::vector< PrimalRay > primal_rays
const PrimalSolution & best_primal_solution() const
double dual_bound() const
int first_order_iterations
absl::StatusOr< SolveStatsProto > Proto() const
std::string ToString() const
absl::Duration solve_time
static absl::StatusOr< SolveStats > FromProto(const SolveStatsProto &solve_stats_proto)
static Termination Unbounded(bool is_maximize, std::string detail={})
TerminationProto Proto() const
Termination(bool is_maximize, TerminationReason reason, std::string detail={})
absl::Status EnsureIsOptimalOrFeasible() const
std::string ToString() const
static Termination InfeasibleOrUnbounded(bool is_maximize, FeasibilityStatus dual_feasibility_status=FeasibilityStatus::kUndetermined, std::string detail={})
absl::Status EnsureReasonIsAnyOf(std::initializer_list< TerminationReason > reasons) const
static Termination Cutoff(bool is_maximize, std::string detail={})
bool limit_reached() const
absl::Status EnsureIsOptimal() const
static absl::StatusOr< Termination > FromProto(const TerminationProto &termination_proto)
static Termination Infeasible(bool is_maximize, FeasibilityStatus dual_feasibility_status=FeasibilityStatus::kUndetermined, std::string detail={})
absl::Status EnsureReasonIs(TerminationReason reason) const
bool IsOptimalOrFeasible() const
ProblemStatus problem_status
static Termination NoSolutionFound(bool is_maximize, Limit limit, std::optional< double > optional_dual_objective=std::nullopt, std::string detail={})
std::optional< Limit > limit
ObjectiveBounds objective_bounds
static Termination Feasible(bool is_maximize, Limit limit, double finite_primal_objective, std::optional< double > optional_dual_objective=std::nullopt, std::string detail={})
static Termination Optimal(double objective_value, std::string detail={})
#define OR_ASSIGN_OR_RETURN3(lhs, rexpr, error_expression)