21#include "absl/log/check.h"
22#include "absl/status/status.h"
23#include "absl/status/statusor.h"
24#include "absl/strings/str_cat.h"
33absl::StatusOr<GlpkRay> ComputePrimalRay(glp_prob*
const problem,
34 const int non_basic_variable) {
35 const int num_cstrs = glp_get_num_rows(problem);
38 const int non_basic_variable_status =
42 CHECK_NE(non_basic_variable_status, GLP_BS);
100 problem, num_cstrs, non_basic_variable);
101 const double t = (glp_get_obj_dir(problem) == GLP_MAX ? 1.0 : -1.0) *
102 (reduced_cost >= 0 ? 1.0 : -1.0);
106 switch (non_basic_variable_status) {
109 return absl::InternalError(
110 "a non-basic variable at its lower-bound is reported as cause of "
111 "unboundness but the reduced cost's sign indicates that the solver "
112 "considered making it smaller");
117 return absl::InternalError(
118 "a non-basic variable at its upper-bound is reported as cause of "
119 "unboundness but the reduced cost's sign indicates that the solver "
120 "considered making it bigger");
126 return absl::InternalError(absl::StrCat(
128 " reported as cause of unboundness"));
137 ray_non_zeros.emplace_back(non_basic_variable, t);
145 std::vector<int> inds(num_cstrs + 1);
146 std::vector<double> vals(num_cstrs + 1);
147 const int non_zeros =
148 glp_eval_tab_col(problem, non_basic_variable, inds.data(), vals.data());
149 for (
int i = 1;
i <= non_zeros; ++
i) {
150 ray_non_zeros.emplace_back(inds[i], t * vals[i]);
156absl::StatusOr<GlpkRay> ComputeDualRay(glp_prob*
const problem,
157 const int basic_variable) {
158 const int num_cstrs = glp_get_num_rows(problem);
301 problem, num_cstrs, basic_variable);
304 problem, num_cstrs, basic_variable);
306 problem, num_cstrs, basic_variable);
308 return absl::InternalError(
309 "dual ray computation failed: GLPK identified a basic variable as the "
310 "source of unboundness but its primal value is within its bounds");
317 const double t = (glp_get_obj_dir(problem) == GLP_MAX ? 1.0 : -1.0) *
326 ray_non_zeros.emplace_back(basic_variable, t);
335 const int num_structural_vars = glp_get_num_cols(problem);
336 std::vector<int> inds(num_structural_vars + 1);
337 std::vector<double> vals(num_structural_vars + 1);
338 const int non_zeros =
339 glp_eval_tab_row(problem, basic_variable, inds.data(), vals.data());
340 for (
int i = 1;
i <= non_zeros; ++
i) {
341 ray_non_zeros.emplace_back(inds[i], -t * vals[i]);
350 : type(type), non_zero_components(
std::move(non_zero_components)) {}
353 glp_prob*
const problem) {
354 const int unbound_ray = glp_get_unbnd_ray(problem);
355 if (unbound_ray <= 0) {
357 DCHECK_EQ(unbound_ray, 0);
364 if (!glp_bf_exists(problem)) {
365 const int factorization_rc = glp_factorize(problem);
366 if (factorization_rc != 0) {
375 const bool is_dual_ray =
377 glp_get_num_rows(problem),
378 unbound_ray) == GLP_BS;
380 (is_dual_ray ? ComputeDualRay(problem, unbound_ray)
381 : ComputePrimalRay(problem, unbound_ray)));
#define ASSIGN_OR_RETURN(lhs, rexpr)
An object oriented wrapper for quadratic constraints in ModelStorage.
absl::StatusOr< std::optional< GlpkRay > > GlpkComputeUnboundRay(glp_prob *const problem)
GlpkRayType
The type of the GlpkRay.
double ComputeFormVarPrimalValue(glp_prob *const problem, const int num_cstrs, const int k)
int ComputeFormVarStatus(glp_prob *const problem, const int num_cstrs, const int k)
std::string BasisStatusString(const int stat)
Formats a linear constraint or variable basis status (GLP_BS,...).
double ComputeFormVarReducedCost(glp_prob *const problem, const int num_cstrs, const int k)
double ComputeFormVarLowerBound(glp_prob *const problem, const int num_cstrs, const int k)
double ComputeFormVarUpperBound(glp_prob *const problem, const int num_cstrs, const int k)
std::string ReturnCodeString(const int rc)
StatusBuilder InternalErrorBuilder()
GlpkRay(GlpkRayType type, SparseVector non_zero_components)
std::vector< std::pair< int, double > > SparseVector