26 #include "absl/memory/memory.h"
27 #include "absl/strings/str_format.h"
41 class GLPKInformation {
43 explicit GLPKInformation(
bool maximize) : num_all_nodes_(0) {
44 ResetBestObjectiveBound(maximize);
46 void Reset(
bool maximize) {
48 ResetBestObjectiveBound(maximize);
50 void ResetBestObjectiveBound(
bool maximize) {
52 best_objective_bound_ = std::numeric_limits<double>::infinity();
54 best_objective_bound_ = -std::numeric_limits<double>::infinity();
58 double best_objective_bound_;
62 void GLPKGatherInformationCallback(glp_tree* tree,
void* info) {
63 CHECK(tree !=
nullptr);
64 CHECK(info !=
nullptr);
65 GLPKInformation* glpk_info =
reinterpret_cast<GLPKInformation*
>(info);
66 switch (glp_ios_reason(tree)) {
73 glp_ios_tree_size(tree,
nullptr,
nullptr, &glpk_info->num_all_nodes_);
75 int node_id = glp_ios_best_node(tree);
77 glpk_info->best_objective_bound_ = glp_ios_node_bound(tree, node_id);
90 int MPSolverIndexToGlpkIndex(
int index) {
return index + 1; }
93 class GLPKInterface :
public MPSolverInterface {
96 GLPKInterface(MPSolver*
const solver,
bool mip);
97 ~GLPKInterface()
override;
100 void SetOptimizationDirection(
bool maximize)
override;
108 void Reset()
override;
111 void SetVariableBounds(
int mpsolver_var_index,
double lb,
double ub)
override;
112 void SetVariableInteger(
int mpsolver_var_index,
bool integer)
override;
113 void SetConstraintBounds(
int mpsolver_constraint_index,
double lb,
117 void AddRowConstraint(MPConstraint*
const ct)
override;
119 void AddVariable(MPVariable*
const var)
override;
121 void SetCoefficient(MPConstraint*
const constraint,
122 const MPVariable*
const variable,
double new_value,
123 double old_value)
override;
125 void ClearConstraint(MPConstraint*
const constraint)
override;
127 void SetObjectiveCoefficient(
const MPVariable*
const variable,
130 void SetObjectiveOffset(
double value)
override;
132 void ClearObjective()
override;
136 int64 iterations()
const override;
138 int64 nodes()
const override;
146 bool CheckSolutionExists()
const override;
150 bool IsContinuous()
const override {
return IsLP(); }
151 bool IsLP()
const override {
return !mip_; }
152 bool IsMIP()
const override {
return mip_; }
154 void ExtractNewVariables()
override;
155 void ExtractNewConstraints()
override;
156 void ExtractObjective()
override;
158 std::string SolverVersion()
const override {
159 return absl::StrFormat(
"GLPK %s", glp_version());
162 void* underlying_solver()
override {
return reinterpret_cast<void*
>(lp_); }
164 double ComputeExactConditionNumber()
const override;
168 void ConfigureGLPKParameters(
const MPSolverParameters& param);
171 void SetParameters(
const MPSolverParameters& param)
override;
173 void SetRelativeMipGap(
double value)
override;
174 void SetPrimalTolerance(
double value)
override;
175 void SetDualTolerance(
double value)
override;
176 void SetPresolveMode(
int value)
override;
177 void SetScalingMode(
int value)
override;
178 void SetLpAlgorithm(
int value)
override;
180 void ExtractOldConstraints();
181 void ExtractOneConstraint(MPConstraint*
const constraint,
int*
const indices,
182 double*
const coefs);
189 double ComputeScaledBasisL1Norm(
int num_rows,
int num_cols,
190 double* row_scaling_factor,
191 double* column_scaling_factor)
const;
196 double ComputeInverseScaledBasisL1Norm(
int num_rows,
int num_cols,
197 double* row_scaling_factor,
198 double* column_scaling_factor)
const;
207 std::unique_ptr<GLPKInformation> mip_callback_info_;
211 GLPKInterface::GLPKInterface(MPSolver*
const solver,
bool mip)
212 : MPSolverInterface(solver), lp_(nullptr), mip_(mip) {
213 lp_ = glp_create_prob();
214 glp_set_prob_name(lp_, solver_->name_.c_str());
215 glp_set_obj_dir(lp_, GLP_MIN);
216 mip_callback_info_ = absl::make_unique<GLPKInformation>(
maximize_);
220 GLPKInterface::~GLPKInterface() {
221 CHECK(lp_ !=
nullptr);
222 glp_delete_prob(lp_);
226 void GLPKInterface::Reset() {
227 CHECK(lp_ !=
nullptr);
228 glp_delete_prob(lp_);
229 lp_ = glp_create_prob();
230 glp_set_prob_name(lp_, solver_->name_.c_str());
231 glp_set_obj_dir(lp_,
maximize_ ? GLP_MAX : GLP_MIN);
232 ResetExtractionInformation();
238 void GLPKInterface::SetOptimizationDirection(
bool maximize) {
239 InvalidateSolutionSynchronization();
240 glp_set_obj_dir(lp_, maximize ? GLP_MAX : GLP_MIN);
243 void GLPKInterface::SetVariableBounds(
int mpsolver_var_index,
double lb,
245 InvalidateSolutionSynchronization();
246 if (!variable_is_extracted(mpsolver_var_index)) {
247 sync_status_ = MUST_RELOAD;
252 const double infinity = solver_->infinity();
253 const int glpk_var_index = MPSolverIndexToGlpkIndex(mpsolver_var_index);
254 if (lb != -infinity) {
255 if (ub != infinity) {
257 glp_set_col_bnds(lp_, glpk_var_index, GLP_FX, lb, ub);
259 glp_set_col_bnds(lp_, glpk_var_index, GLP_DB, lb, ub);
262 glp_set_col_bnds(lp_, glpk_var_index, GLP_LO, lb, 0.0);
264 }
else if (ub != infinity) {
265 glp_set_col_bnds(lp_, glpk_var_index, GLP_UP, 0.0, ub);
267 glp_set_col_bnds(lp_, glpk_var_index, GLP_FR, 0.0, 0.0);
271 void GLPKInterface::SetVariableInteger(
int mpsolver_var_index,
bool integer) {
272 InvalidateSolutionSynchronization();
274 if (variable_is_extracted(mpsolver_var_index)) {
276 glp_set_col_kind(lp_, MPSolverIndexToGlpkIndex(mpsolver_var_index),
277 integer ? GLP_IV : GLP_CV);
279 sync_status_ = MUST_RELOAD;
284 void GLPKInterface::SetConstraintBounds(
int mpsolver_constraint_index,
285 double lb,
double ub) {
286 InvalidateSolutionSynchronization();
287 if (!constraint_is_extracted(mpsolver_constraint_index)) {
288 sync_status_ = MUST_RELOAD;
292 const int glpk_constraint_index =
293 MPSolverIndexToGlpkIndex(mpsolver_constraint_index);
295 const double infinity = solver_->infinity();
296 if (lb != -infinity) {
297 if (ub != infinity) {
299 glp_set_row_bnds(lp_, glpk_constraint_index, GLP_FX, lb, ub);
301 glp_set_row_bnds(lp_, glpk_constraint_index, GLP_DB, lb, ub);
304 glp_set_row_bnds(lp_, glpk_constraint_index, GLP_LO, lb, 0.0);
306 }
else if (ub != infinity) {
307 glp_set_row_bnds(lp_, glpk_constraint_index, GLP_UP, 0.0, ub);
309 glp_set_row_bnds(lp_, glpk_constraint_index, GLP_FR, 0.0, 0.0);
313 void GLPKInterface::SetCoefficient(MPConstraint*
const constraint,
314 const MPVariable*
const variable,
315 double new_value,
double old_value) {
316 InvalidateSolutionSynchronization();
321 if (constraint_is_extracted(constraint->index()) &&
322 (sync_status_ == MODEL_SYNCHRONIZED ||
323 !constraint->ContainsNewVariables())) {
324 const int size = constraint->coefficients_.size();
325 std::unique_ptr<int[]> indices(
new int[size + 1]);
326 std::unique_ptr<double[]> coefs(
new double[size + 1]);
327 ExtractOneConstraint(constraint, indices.get(), coefs.get());
332 void GLPKInterface::ClearConstraint(MPConstraint*
const constraint) {
333 InvalidateSolutionSynchronization();
335 if (constraint_is_extracted(constraint->index())) {
336 glp_set_mat_row(lp_, MPSolverIndexToGlpkIndex(constraint->index()), 0,
342 void GLPKInterface::SetObjectiveCoefficient(
const MPVariable*
const variable,
344 sync_status_ = MUST_RELOAD;
348 void GLPKInterface::SetObjectiveOffset(
double value) {
349 sync_status_ = MUST_RELOAD;
353 void GLPKInterface::ClearObjective() {
354 InvalidateSolutionSynchronization();
355 for (
const auto& entry : solver_->objective_->coefficients_) {
356 const int mpsolver_var_index = entry.first->index();
358 if (!variable_is_extracted(mpsolver_var_index)) {
359 DCHECK_NE(MODEL_SYNCHRONIZED, sync_status_);
361 glp_set_obj_coef(lp_, MPSolverIndexToGlpkIndex(mpsolver_var_index), 0.0);
365 glp_set_obj_coef(lp_, 0, 0.0);
368 void GLPKInterface::AddRowConstraint(MPConstraint*
const ct) {
369 sync_status_ = MUST_RELOAD;
372 void GLPKInterface::AddVariable(MPVariable*
const var) {
373 sync_status_ = MUST_RELOAD;
377 void GLPKInterface::ExtractNewVariables() {
378 int total_num_vars = solver_->variables_.size();
379 if (total_num_vars > last_variable_index_) {
380 glp_add_cols(lp_, total_num_vars - last_variable_index_);
381 for (
int j = last_variable_index_; j < solver_->variables_.size(); ++j) {
382 MPVariable*
const var = solver_->variables_[j];
383 set_variable_as_extracted(j,
true);
384 if (!
var->name().empty()) {
385 glp_set_col_name(lp_, MPSolverIndexToGlpkIndex(j),
var->name().c_str());
387 SetVariableBounds(j,
var->lb(),
var->ub());
388 SetVariableInteger(j,
var->integer());
391 double tmp_obj_coef = 0.0;
392 glp_set_obj_coef(lp_, MPSolverIndexToGlpkIndex(j), tmp_obj_coef);
395 ExtractOldConstraints();
400 void GLPKInterface::ExtractOldConstraints() {
401 const int max_constraint_size =
402 solver_->ComputeMaxConstraintSize(0, last_constraint_index_);
405 std::unique_ptr<int[]> indices(
new int[max_constraint_size + 1]);
406 std::unique_ptr<double[]> coefs(
new double[max_constraint_size + 1]);
408 for (
int i = 0; i < last_constraint_index_; ++i) {
409 MPConstraint*
const ct = solver_->constraints_[i];
410 DCHECK(constraint_is_extracted(i));
411 const int size =
ct->coefficients_.size();
416 if (
ct->ContainsNewVariables()) {
417 ExtractOneConstraint(
ct, indices.get(), coefs.get());
425 void GLPKInterface::ExtractOneConstraint(MPConstraint*
const constraint,
427 double*
const coefs) {
430 for (
const auto& entry : constraint->coefficients_) {
431 DCHECK(variable_is_extracted(entry.first->index()));
432 indices[k] = MPSolverIndexToGlpkIndex(entry.first->index());
433 coefs[k] = entry.second;
436 glp_set_mat_row(lp_, MPSolverIndexToGlpkIndex(constraint->index()), k - 1,
441 void GLPKInterface::ExtractNewConstraints() {
442 int total_num_rows = solver_->constraints_.size();
443 if (last_constraint_index_ < total_num_rows) {
445 glp_add_rows(lp_, total_num_rows - last_constraint_index_);
447 for (
int i = last_constraint_index_; i < total_num_rows; ++i) {
448 MPConstraint*
ct = solver_->constraints_[i];
449 set_constraint_as_extracted(i,
true);
450 if (
ct->name().empty()) {
451 glp_set_row_name(lp_, MPSolverIndexToGlpkIndex(i),
452 absl::StrFormat(
"ct_%i", i).c_str());
454 glp_set_row_name(lp_, MPSolverIndexToGlpkIndex(i),
ct->name().c_str());
457 SetConstraintBounds(i,
ct->lb(),
ct->ub());
458 num_coefs +=
ct->coefficients_.size();
462 if (last_variable_index_ == 0 && last_constraint_index_ == 0) {
469 std::unique_ptr<int[]> variable_indices(
new int[num_coefs + 1]);
470 std::unique_ptr<int[]> constraint_indices(
new int[num_coefs + 1]);
471 std::unique_ptr<double[]> coefs(
new double[num_coefs + 1]);
473 for (
int i = 0; i < solver_->constraints_.size(); ++i) {
474 MPConstraint*
ct = solver_->constraints_[i];
475 for (
const auto& entry :
ct->coefficients_) {
476 DCHECK(variable_is_extracted(entry.first->index()));
477 constraint_indices[k] = MPSolverIndexToGlpkIndex(
ct->index());
478 variable_indices[k] = MPSolverIndexToGlpkIndex(entry.first->index());
479 coefs[k] = entry.second;
484 glp_load_matrix(lp_, num_coefs, constraint_indices.get(),
485 variable_indices.get(), coefs.get());
488 int max_constraint_size = solver_->ComputeMaxConstraintSize(
489 last_constraint_index_, total_num_rows);
492 std::unique_ptr<int[]> indices(
new int[max_constraint_size + 1]);
493 std::unique_ptr<double[]> coefs(
new double[max_constraint_size + 1]);
494 for (
int i = last_constraint_index_; i < total_num_rows; i++) {
495 ExtractOneConstraint(solver_->constraints_[i], indices.get(),
502 void GLPKInterface::ExtractObjective() {
505 for (
const auto& entry : solver_->objective_->coefficients_) {
506 glp_set_obj_coef(lp_, MPSolverIndexToGlpkIndex(entry.first->index()),
510 glp_set_obj_coef(lp_, 0, solver_->Objective().offset());
519 if (param.GetIntegerParam(MPSolverParameters::INCREMENTALITY) ==
520 MPSolverParameters::INCREMENTALITY_OFF) {
526 glp_term_out(GLP_OFF);
528 glp_term_out(GLP_ON);
532 VLOG(1) << absl::StrFormat(
"Model built in %.3f seconds.", timer.
Get());
537 ConfigureGLPKParameters(param);
541 int solver_status = glp_simplex(lp_, &lp_param_);
545 if (solver_status == 0) {
546 solver_status = glp_intopt(lp_, &mip_param_);
552 result_status_ = MPSolver::ABNORMAL;
553 if (solver_status == GLP_ETMLIM) {
554 result_status_ = MPSolver::NOT_SOLVED;
556 sync_status_ = SOLUTION_SYNCHRONIZED;
557 return result_status_;
560 VLOG(1) << absl::StrFormat(
"GLPK Status: %i (time spent: %.3f seconds).",
561 solver_status, timer.
Get());
565 objective_value_ = glp_mip_obj_val(lp_);
566 best_objective_bound_ = mip_callback_info_->best_objective_bound_;
568 objective_value_ = glp_get_obj_val(lp_);
570 VLOG(1) <<
"objective=" << objective_value_
571 <<
", bound=" << best_objective_bound_;
572 for (
int i = 0; i < solver_->variables_.size(); ++i) {
573 MPVariable*
const var = solver_->variables_[i];
576 val = glp_mip_col_val(lp_, MPSolverIndexToGlpkIndex(i));
578 val = glp_get_col_prim(lp_, MPSolverIndexToGlpkIndex(i));
580 var->set_solution_value(val);
581 VLOG(3) <<
var->name() <<
": value =" << val;
584 reduced_cost = glp_get_col_dual(lp_, MPSolverIndexToGlpkIndex(i));
585 var->set_reduced_cost(reduced_cost);
586 VLOG(4) <<
var->name() <<
": reduced cost = " << reduced_cost;
589 for (
int i = 0; i < solver_->constraints_.size(); ++i) {
590 MPConstraint*
const ct = solver_->constraints_[i];
592 const double dual_value =
593 glp_get_row_dual(lp_, MPSolverIndexToGlpkIndex(i));
594 ct->set_dual_value(dual_value);
595 VLOG(4) <<
"row " << MPSolverIndexToGlpkIndex(i)
596 <<
": dual value = " << dual_value;
602 int tmp_status = glp_mip_status(lp_);
603 VLOG(1) <<
"GLPK result status: " << tmp_status;
604 if (tmp_status == GLP_OPT) {
606 }
else if (tmp_status == GLP_FEAS) {
608 }
else if (tmp_status == GLP_NOFEAS) {
613 }
else if (solver_status == GLP_ETMLIM) {
614 result_status_ = MPSolver::NOT_SOLVED;
616 result_status_ = MPSolver::ABNORMAL;
621 int tmp_status = glp_get_status(lp_);
622 VLOG(1) <<
"GLPK result status: " << tmp_status;
623 if (tmp_status == GLP_OPT) {
625 }
else if (tmp_status == GLP_FEAS) {
627 }
else if (tmp_status == GLP_NOFEAS || tmp_status == GLP_INFEAS) {
632 }
else if (tmp_status == GLP_UNBND) {
636 result_status_ = MPSolver::UNBOUNDED;
637 }
else if (solver_status == GLP_ETMLIM) {
638 result_status_ = MPSolver::NOT_SOLVED;
640 result_status_ = MPSolver::ABNORMAL;
644 sync_status_ = SOLUTION_SYNCHRONIZED;
646 return result_status_;
649 MPSolver::BasisStatus GLPKInterface::TransformGLPKBasisStatus(
650 int glpk_basis_status)
const {
651 switch (glpk_basis_status) {
653 return MPSolver::BASIC;
655 return MPSolver::AT_LOWER_BOUND;
657 return MPSolver::AT_UPPER_BOUND;
659 return MPSolver::FREE;
661 return MPSolver::FIXED_VALUE;
663 LOG(
FATAL) <<
"Unknown GLPK basis status";
664 return MPSolver::FREE;
670 int64 GLPKInterface::iterations()
const {
671 #if GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION < 49
672 if (!mip_ && CheckSolutionIsSynchronized()) {
673 return lpx_get_int_parm(lp_, LPX_K_ITCNT);
675 #elif GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION >= 53
676 if (!mip_ && CheckSolutionIsSynchronized()) {
677 return glp_get_it_cnt(lp_);
680 LOG(
WARNING) <<
"Total number of iterations is not available";
681 return kUnknownNumberOfIterations;
684 int64 GLPKInterface::nodes()
const {
686 if (!CheckSolutionIsSynchronized())
return kUnknownNumberOfNodes;
687 return mip_callback_info_->num_all_nodes_;
689 LOG(DFATAL) <<
"Number of nodes only available for discrete problems";
690 return kUnknownNumberOfNodes;
694 MPSolver::BasisStatus GLPKInterface::row_status(
int constraint_index)
const {
696 DCHECK_LT(constraint_index, last_constraint_index_);
697 const int glpk_basis_status =
698 glp_get_row_stat(lp_, MPSolverIndexToGlpkIndex(constraint_index));
699 return TransformGLPKBasisStatus(glpk_basis_status);
702 MPSolver::BasisStatus GLPKInterface::column_status(
int variable_index)
const {
704 DCHECK_LT(variable_index, last_variable_index_);
705 const int glpk_basis_status =
706 glp_get_col_stat(lp_, MPSolverIndexToGlpkIndex(variable_index));
707 return TransformGLPKBasisStatus(glpk_basis_status);
710 bool GLPKInterface::CheckSolutionExists()
const {
711 if (result_status_ == MPSolver::ABNORMAL) {
712 LOG(
WARNING) <<
"Ignoring ABNORMAL status from GLPK: This status may or may"
713 <<
" not indicate that a solution exists.";
717 return MPSolverInterface::CheckSolutionExists();
721 double GLPKInterface::ComputeExactConditionNumber()
const {
722 if (!IsContinuous()) {
724 LOG(DFATAL) <<
"ComputeExactConditionNumber not implemented for"
725 <<
" GLPK_MIXED_INTEGER_PROGRAMMING";
728 if (!CheckSolutionIsSynchronized())
return 0.0;
731 CheckSolutionExists();
732 const int num_rows = glp_get_num_rows(lp_);
733 const int num_cols = glp_get_num_cols(lp_);
735 std::unique_ptr<double[]> row_scaling_factor(
new double[num_rows + 1]);
736 std::unique_ptr<double[]> column_scaling_factor(
new double[num_cols + 1]);
737 for (
int row = 1;
row <= num_rows; ++
row) {
738 row_scaling_factor[
row] = glp_get_rii(lp_,
row);
740 for (
int col = 1;
col <= num_cols; ++
col) {
741 column_scaling_factor[
col] = glp_get_sjj(lp_,
col);
743 return ComputeInverseScaledBasisL1Norm(num_rows, num_cols,
744 row_scaling_factor.get(),
745 column_scaling_factor.get()) *
746 ComputeScaledBasisL1Norm(num_rows, num_cols, row_scaling_factor.get(),
747 column_scaling_factor.get());
750 double GLPKInterface::ComputeScaledBasisL1Norm(
751 int num_rows,
int num_cols,
double* row_scaling_factor,
752 double* column_scaling_factor)
const {
754 std::unique_ptr<double[]> values(
new double[num_rows + 1]);
755 std::unique_ptr<int[]> indices(
new int[num_rows + 1]);
756 for (
int col = 1;
col <= num_cols; ++
col) {
757 const int glpk_basis_status = glp_get_col_stat(lp_,
col);
759 if (glpk_basis_status == GLP_BS) {
761 const int num_nz = glp_get_mat_col(lp_,
col, indices.get(), values.get());
762 double column_norm = 0.0;
763 for (
int k = 1; k <= num_nz; k++) {
764 column_norm += fabs(values[k] * row_scaling_factor[indices[k]]);
766 column_norm *= fabs(column_scaling_factor[
col]);
772 for (
int row = 1;
row <= num_rows; ++
row) {
773 const int glpk_basis_status = glp_get_row_stat(lp_,
row);
775 if (glpk_basis_status == GLP_BS) {
779 const double column_norm = fabs(row_scaling_factor[
row]);
787 double GLPKInterface::ComputeInverseScaledBasisL1Norm(
788 int num_rows,
int num_cols,
double* row_scaling_factor,
789 double* column_scaling_factor)
const {
791 if (!glp_bf_exists(lp_)) {
792 const int factorize_status = glp_factorize(lp_);
793 switch (factorize_status) {
795 LOG(
FATAL) <<
"Not able to factorize: error GLP_EBADB.";
800 <<
"Not able to factorize: "
801 <<
"the basis matrix is singular within the working precision.";
802 return MPSolver::infinity();
806 <<
"Not able to factorize: the basis matrix is ill-conditioned.";
807 return MPSolver::infinity();
813 std::unique_ptr<double[]> right_hand_side(
new double[num_rows + 1]);
827 for (
int k = 1; k <= num_rows; ++k) {
828 for (
int row = 1;
row <= num_rows; ++
row) {
829 right_hand_side[
row] = 0.0;
831 right_hand_side[k] = 1.0;
833 for (
int row = 1;
row <= num_rows; ++
row) {
834 right_hand_side[
row] /= row_scaling_factor[
row];
836 glp_ftran(lp_, right_hand_side.get());
840 for (
int row = 1;
row <= num_rows; ++
row) {
841 const int k = glp_get_bhead(lp_,
row);
844 right_hand_side[
row] *= row_scaling_factor[k];
847 right_hand_side[
row] /= column_scaling_factor[k - num_rows];
851 double column_norm = 0.0;
852 for (
int row = 1;
row <= num_rows; ++
row) {
853 column_norm += fabs(right_hand_side[
row]);
863 void GLPKInterface::ConfigureGLPKParameters(
const MPSolverParameters& param) {
865 glp_init_iocp(&mip_param_);
867 if (solver_->time_limit()) {
868 VLOG(1) <<
"Setting time limit = " << solver_->time_limit() <<
" ms.";
869 mip_param_.tm_lim = solver_->time_limit();
872 mip_param_.cb_func = GLPKGatherInformationCallback;
874 mip_param_.cb_info = mip_callback_info_.get();
880 glp_init_smcp(&lp_param_);
882 if (solver_->time_limit()) {
883 VLOG(1) <<
"Setting time limit = " << solver_->time_limit() <<
" ms.";
884 lp_param_.tm_lim = solver_->time_limit();
888 glp_scale_prob(lp_, GLP_SF_AUTO);
891 glp_adv_basis(lp_, 0);
894 SetParameters(param);
897 void GLPKInterface::SetParameters(
const MPSolverParameters& param) {
898 SetCommonParameters(param);
900 SetMIPParameters(param);
904 void GLPKInterface::SetRelativeMipGap(
double value) {
906 mip_param_.mip_gap =
value;
908 LOG(
WARNING) <<
"The relative MIP gap is only available "
909 <<
"for discrete problems.";
913 void GLPKInterface::SetPrimalTolerance(
double value) {
914 lp_param_.tol_bnd =
value;
917 void GLPKInterface::SetDualTolerance(
double value) { lp_param_.tol_dj =
value; }
919 void GLPKInterface::SetPresolveMode(
int value) {
921 case MPSolverParameters::PRESOLVE_OFF: {
922 mip_param_.presolve = GLP_OFF;
923 lp_param_.presolve = GLP_OFF;
926 case MPSolverParameters::PRESOLVE_ON: {
927 mip_param_.presolve = GLP_ON;
928 lp_param_.presolve = GLP_ON;
932 SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE,
value);
937 void GLPKInterface::SetScalingMode(
int value) {
938 SetUnsupportedIntegerParam(MPSolverParameters::SCALING);
941 void GLPKInterface::SetLpAlgorithm(
int value) {
943 case MPSolverParameters::DUAL: {
945 lp_param_.meth = GLP_DUALP;
948 case MPSolverParameters::PRIMAL: {
949 lp_param_.meth = GLP_PRIMAL;
952 case MPSolverParameters::BARRIER:
954 SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
960 MPSolverInterface* BuildGLPKInterface(
bool mip, MPSolver*
const solver) {
961 return new GLPKInterface(solver, mip);
965 #endif // #if defined(USE_GLPK)