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;
140 double best_objective_bound()
const override;
148 bool CheckSolutionExists()
const override;
150 bool CheckBestObjectiveBoundExists()
const override;
154 bool IsContinuous()
const override {
return IsLP(); }
155 bool IsLP()
const override {
return !mip_; }
156 bool IsMIP()
const override {
return mip_; }
158 void ExtractNewVariables()
override;
159 void ExtractNewConstraints()
override;
160 void ExtractObjective()
override;
162 std::string SolverVersion()
const override {
163 return absl::StrFormat(
"GLPK %s", glp_version());
166 void* underlying_solver()
override {
return reinterpret_cast<void*
>(lp_); }
168 double ComputeExactConditionNumber()
const override;
172 void ConfigureGLPKParameters(
const MPSolverParameters& param);
175 void SetParameters(
const MPSolverParameters& param)
override;
177 void SetRelativeMipGap(
double value)
override;
178 void SetPrimalTolerance(
double value)
override;
179 void SetDualTolerance(
double value)
override;
180 void SetPresolveMode(
int value)
override;
181 void SetScalingMode(
int value)
override;
182 void SetLpAlgorithm(
int value)
override;
184 void ExtractOldConstraints();
185 void ExtractOneConstraint(MPConstraint*
const constraint,
int*
const indices,
186 double*
const coefs);
193 double ComputeScaledBasisL1Norm(
int num_rows,
int num_cols,
194 double* row_scaling_factor,
195 double* column_scaling_factor)
const;
200 double ComputeInverseScaledBasisL1Norm(
int num_rows,
int num_cols,
201 double* row_scaling_factor,
202 double* column_scaling_factor)
const;
211 std::unique_ptr<GLPKInformation> mip_callback_info_;
215 GLPKInterface::GLPKInterface(MPSolver*
const solver,
bool mip)
216 : MPSolverInterface(solver), lp_(nullptr), mip_(mip) {
217 lp_ = glp_create_prob();
218 glp_set_prob_name(lp_, solver_->name_.c_str());
219 glp_set_obj_dir(lp_, GLP_MIN);
220 mip_callback_info_ = absl::make_unique<GLPKInformation>(
maximize_);
224 GLPKInterface::~GLPKInterface() {
225 CHECK(lp_ !=
nullptr);
226 glp_delete_prob(lp_);
230 void GLPKInterface::Reset() {
231 CHECK(lp_ !=
nullptr);
232 glp_delete_prob(lp_);
233 lp_ = glp_create_prob();
234 glp_set_prob_name(lp_, solver_->name_.c_str());
235 glp_set_obj_dir(lp_,
maximize_ ? GLP_MAX : GLP_MIN);
236 ResetExtractionInformation();
242 void GLPKInterface::SetOptimizationDirection(
bool maximize) {
243 InvalidateSolutionSynchronization();
244 glp_set_obj_dir(lp_, maximize ? GLP_MAX : GLP_MIN);
247 void GLPKInterface::SetVariableBounds(
int mpsolver_var_index,
double lb,
249 InvalidateSolutionSynchronization();
250 if (!variable_is_extracted(mpsolver_var_index)) {
251 sync_status_ = MUST_RELOAD;
255 DCHECK(lp_ !=
nullptr);
256 const double infinity = solver_->infinity();
257 const int glpk_var_index = MPSolverIndexToGlpkIndex(mpsolver_var_index);
258 if (lb != -infinity) {
259 if (ub != infinity) {
261 glp_set_col_bnds(lp_, glpk_var_index, GLP_FX, lb, ub);
263 glp_set_col_bnds(lp_, glpk_var_index, GLP_DB, lb, ub);
266 glp_set_col_bnds(lp_, glpk_var_index, GLP_LO, lb, 0.0);
268 }
else if (ub != infinity) {
269 glp_set_col_bnds(lp_, glpk_var_index, GLP_UP, 0.0, ub);
271 glp_set_col_bnds(lp_, glpk_var_index, GLP_FR, 0.0, 0.0);
275 void GLPKInterface::SetVariableInteger(
int mpsolver_var_index,
bool integer) {
276 InvalidateSolutionSynchronization();
278 if (variable_is_extracted(mpsolver_var_index)) {
280 glp_set_col_kind(lp_, MPSolverIndexToGlpkIndex(mpsolver_var_index),
281 integer ? GLP_IV : GLP_CV);
283 sync_status_ = MUST_RELOAD;
288 void GLPKInterface::SetConstraintBounds(
int mpsolver_constraint_index,
289 double lb,
double ub) {
290 InvalidateSolutionSynchronization();
291 if (!constraint_is_extracted(mpsolver_constraint_index)) {
292 sync_status_ = MUST_RELOAD;
296 const int glpk_constraint_index =
297 MPSolverIndexToGlpkIndex(mpsolver_constraint_index);
298 DCHECK(lp_ !=
nullptr);
299 const double infinity = solver_->infinity();
300 if (lb != -infinity) {
301 if (ub != infinity) {
303 glp_set_row_bnds(lp_, glpk_constraint_index, GLP_FX, lb, ub);
305 glp_set_row_bnds(lp_, glpk_constraint_index, GLP_DB, lb, ub);
308 glp_set_row_bnds(lp_, glpk_constraint_index, GLP_LO, lb, 0.0);
310 }
else if (ub != infinity) {
311 glp_set_row_bnds(lp_, glpk_constraint_index, GLP_UP, 0.0, ub);
313 glp_set_row_bnds(lp_, glpk_constraint_index, GLP_FR, 0.0, 0.0);
317 void GLPKInterface::SetCoefficient(MPConstraint*
const constraint,
318 const MPVariable*
const variable,
319 double new_value,
double old_value) {
320 InvalidateSolutionSynchronization();
325 if (constraint_is_extracted(constraint->index()) &&
326 (sync_status_ == MODEL_SYNCHRONIZED ||
327 !constraint->ContainsNewVariables())) {
328 const int size = constraint->coefficients_.size();
329 std::unique_ptr<int[]> indices(
new int[size + 1]);
330 std::unique_ptr<double[]> coefs(
new double[size + 1]);
331 ExtractOneConstraint(constraint, indices.get(), coefs.get());
336 void GLPKInterface::ClearConstraint(MPConstraint*
const constraint) {
337 InvalidateSolutionSynchronization();
339 if (constraint_is_extracted(constraint->index())) {
340 glp_set_mat_row(lp_, MPSolverIndexToGlpkIndex(constraint->index()), 0,
346 void GLPKInterface::SetObjectiveCoefficient(
const MPVariable*
const variable,
348 sync_status_ = MUST_RELOAD;
352 void GLPKInterface::SetObjectiveOffset(
double value) {
353 sync_status_ = MUST_RELOAD;
357 void GLPKInterface::ClearObjective() {
358 InvalidateSolutionSynchronization();
359 for (
const auto& entry : solver_->objective_->coefficients_) {
360 const int mpsolver_var_index = entry.first->index();
362 if (!variable_is_extracted(mpsolver_var_index)) {
363 DCHECK_NE(MODEL_SYNCHRONIZED, sync_status_);
365 glp_set_obj_coef(lp_, MPSolverIndexToGlpkIndex(mpsolver_var_index), 0.0);
369 glp_set_obj_coef(lp_, 0, 0.0);
372 void GLPKInterface::AddRowConstraint(MPConstraint*
const ct) {
373 sync_status_ = MUST_RELOAD;
376 void GLPKInterface::AddVariable(MPVariable*
const var) {
377 sync_status_ = MUST_RELOAD;
381 void GLPKInterface::ExtractNewVariables() {
382 int total_num_vars = solver_->variables_.size();
383 if (total_num_vars > last_variable_index_) {
384 glp_add_cols(lp_, total_num_vars - last_variable_index_);
385 for (
int j = last_variable_index_; j < solver_->variables_.size(); ++j) {
386 MPVariable*
const var = solver_->variables_[j];
387 set_variable_as_extracted(j,
true);
388 if (!
var->name().empty()) {
389 glp_set_col_name(lp_, MPSolverIndexToGlpkIndex(j),
var->name().c_str());
391 SetVariableBounds(j,
var->lb(),
var->ub());
392 SetVariableInteger(j,
var->integer());
395 double tmp_obj_coef = 0.0;
396 glp_set_obj_coef(lp_, MPSolverIndexToGlpkIndex(j), tmp_obj_coef);
399 ExtractOldConstraints();
404 void GLPKInterface::ExtractOldConstraints() {
405 const int max_constraint_size =
406 solver_->ComputeMaxConstraintSize(0, last_constraint_index_);
409 std::unique_ptr<int[]> indices(
new int[max_constraint_size + 1]);
410 std::unique_ptr<double[]> coefs(
new double[max_constraint_size + 1]);
412 for (
int i = 0; i < last_constraint_index_; ++i) {
413 MPConstraint*
const ct = solver_->constraints_[i];
414 DCHECK(constraint_is_extracted(i));
415 const int size =
ct->coefficients_.size();
420 if (
ct->ContainsNewVariables()) {
421 ExtractOneConstraint(
ct, indices.get(), coefs.get());
429 void GLPKInterface::ExtractOneConstraint(MPConstraint*
const constraint,
431 double*
const coefs) {
434 for (
const auto& entry : constraint->coefficients_) {
435 DCHECK(variable_is_extracted(entry.first->index()));
436 indices[k] = MPSolverIndexToGlpkIndex(entry.first->index());
437 coefs[k] = entry.second;
440 glp_set_mat_row(lp_, MPSolverIndexToGlpkIndex(constraint->index()), k - 1,
445 void GLPKInterface::ExtractNewConstraints() {
446 int total_num_rows = solver_->constraints_.size();
447 if (last_constraint_index_ < total_num_rows) {
449 glp_add_rows(lp_, total_num_rows - last_constraint_index_);
451 for (
int i = last_constraint_index_; i < total_num_rows; ++i) {
452 MPConstraint*
ct = solver_->constraints_[i];
453 set_constraint_as_extracted(i,
true);
454 if (
ct->name().empty()) {
455 glp_set_row_name(lp_, MPSolverIndexToGlpkIndex(i),
456 absl::StrFormat(
"ct_%i", i).c_str());
458 glp_set_row_name(lp_, MPSolverIndexToGlpkIndex(i),
ct->name().c_str());
461 SetConstraintBounds(i,
ct->lb(),
ct->ub());
462 num_coefs +=
ct->coefficients_.size();
466 if (last_variable_index_ == 0 && last_constraint_index_ == 0) {
473 std::unique_ptr<int[]> variable_indices(
new int[num_coefs + 1]);
474 std::unique_ptr<int[]> constraint_indices(
new int[num_coefs + 1]);
475 std::unique_ptr<double[]> coefs(
new double[num_coefs + 1]);
477 for (
int i = 0; i < solver_->constraints_.size(); ++i) {
478 MPConstraint*
ct = solver_->constraints_[i];
479 for (
const auto& entry :
ct->coefficients_) {
480 DCHECK(variable_is_extracted(entry.first->index()));
481 constraint_indices[k] = MPSolverIndexToGlpkIndex(
ct->index());
482 variable_indices[k] = MPSolverIndexToGlpkIndex(entry.first->index());
483 coefs[k] = entry.second;
487 CHECK_EQ(num_coefs + 1, k);
488 glp_load_matrix(lp_, num_coefs, constraint_indices.get(),
489 variable_indices.get(), coefs.get());
492 int max_constraint_size = solver_->ComputeMaxConstraintSize(
493 last_constraint_index_, total_num_rows);
496 std::unique_ptr<int[]> indices(
new int[max_constraint_size + 1]);
497 std::unique_ptr<double[]> coefs(
new double[max_constraint_size + 1]);
498 for (
int i = last_constraint_index_; i < total_num_rows; i++) {
499 ExtractOneConstraint(solver_->constraints_[i], indices.get(),
506 void GLPKInterface::ExtractObjective() {
509 for (
const auto& entry : solver_->objective_->coefficients_) {
510 glp_set_obj_coef(lp_, MPSolverIndexToGlpkIndex(entry.first->index()),
514 glp_set_obj_coef(lp_, 0, solver_->Objective().offset());
523 if (param.GetIntegerParam(MPSolverParameters::INCREMENTALITY) ==
524 MPSolverParameters::INCREMENTALITY_OFF) {
530 glp_term_out(GLP_OFF);
532 glp_term_out(GLP_ON);
536 VLOG(1) << absl::StrFormat(
"Model built in %.3f seconds.", timer.
Get());
541 ConfigureGLPKParameters(param);
545 int solver_status = glp_simplex(lp_, &lp_param_);
549 if (solver_status == 0) {
550 solver_status = glp_intopt(lp_, &mip_param_);
556 result_status_ = MPSolver::ABNORMAL;
557 if (solver_status == GLP_ETMLIM) {
558 result_status_ = MPSolver::NOT_SOLVED;
560 sync_status_ = SOLUTION_SYNCHRONIZED;
561 return result_status_;
564 VLOG(1) << absl::StrFormat(
"GLPK Status: %i (time spent: %.3f seconds).",
565 solver_status, timer.
Get());
569 objective_value_ = glp_mip_obj_val(lp_);
571 objective_value_ = glp_get_obj_val(lp_);
573 VLOG(1) <<
"objective=" << objective_value_;
574 for (
int i = 0; i < solver_->variables_.size(); ++i) {
575 MPVariable*
const var = solver_->variables_[i];
578 val = glp_mip_col_val(lp_, MPSolverIndexToGlpkIndex(i));
580 val = glp_get_col_prim(lp_, MPSolverIndexToGlpkIndex(i));
582 var->set_solution_value(val);
583 VLOG(3) <<
var->name() <<
": value =" << val;
586 reduced_cost = glp_get_col_dual(lp_, MPSolverIndexToGlpkIndex(i));
587 var->set_reduced_cost(reduced_cost);
588 VLOG(4) <<
var->name() <<
": reduced cost = " << reduced_cost;
591 for (
int i = 0; i < solver_->constraints_.size(); ++i) {
592 MPConstraint*
const ct = solver_->constraints_[i];
594 const double dual_value =
595 glp_get_row_dual(lp_, MPSolverIndexToGlpkIndex(i));
596 ct->set_dual_value(dual_value);
597 VLOG(4) <<
"row " << MPSolverIndexToGlpkIndex(i)
598 <<
": dual value = " << dual_value;
604 int tmp_status = glp_mip_status(lp_);
605 VLOG(1) <<
"GLPK result status: " << tmp_status;
606 if (tmp_status == GLP_OPT) {
608 }
else if (tmp_status == GLP_FEAS) {
610 }
else if (tmp_status == GLP_NOFEAS) {
615 }
else if (solver_status == GLP_ETMLIM) {
616 result_status_ = MPSolver::NOT_SOLVED;
618 result_status_ = MPSolver::ABNORMAL;
623 int tmp_status = glp_get_status(lp_);
624 VLOG(1) <<
"GLPK result status: " << tmp_status;
625 if (tmp_status == GLP_OPT) {
627 }
else if (tmp_status == GLP_FEAS) {
629 }
else if (tmp_status == GLP_NOFEAS || tmp_status == GLP_INFEAS) {
634 }
else if (tmp_status == GLP_UNBND) {
638 result_status_ = MPSolver::UNBOUNDED;
639 }
else if (solver_status == GLP_ETMLIM) {
640 result_status_ = MPSolver::NOT_SOLVED;
642 result_status_ = MPSolver::ABNORMAL;
646 sync_status_ = SOLUTION_SYNCHRONIZED;
648 return result_status_;
651 MPSolver::BasisStatus GLPKInterface::TransformGLPKBasisStatus(
652 int glpk_basis_status)
const {
653 switch (glpk_basis_status) {
655 return MPSolver::BASIC;
657 return MPSolver::AT_LOWER_BOUND;
659 return MPSolver::AT_UPPER_BOUND;
661 return MPSolver::FREE;
663 return MPSolver::FIXED_VALUE;
665 LOG(FATAL) <<
"Unknown GLPK basis status";
666 return MPSolver::FREE;
672 int64 GLPKInterface::iterations()
const {
673 #if GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION < 49
674 if (!mip_ && CheckSolutionIsSynchronized()) {
675 return lpx_get_int_parm(lp_, LPX_K_ITCNT);
677 #elif GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION >= 53
678 if (!mip_ && CheckSolutionIsSynchronized()) {
679 return glp_get_it_cnt(lp_);
682 LOG(WARNING) <<
"Total number of iterations is not available";
683 return kUnknownNumberOfIterations;
686 int64 GLPKInterface::nodes()
const {
688 if (!CheckSolutionIsSynchronized())
return kUnknownNumberOfNodes;
689 return mip_callback_info_->num_all_nodes_;
691 LOG(DFATAL) <<
"Number of nodes only available for discrete problems";
692 return kUnknownNumberOfNodes;
696 double GLPKInterface::best_objective_bound()
const {
698 if (!CheckSolutionIsSynchronized() || !CheckBestObjectiveBoundExists()) {
699 return trivial_worst_objective_bound();
701 if (solver_->variables_.empty() && solver_->constraints_.empty()) {
703 return solver_->Objective().offset();
705 return mip_callback_info_->best_objective_bound_;
708 LOG(DFATAL) <<
"Best objective bound only available for discrete problems";
709 return trivial_worst_objective_bound();
713 MPSolver::BasisStatus GLPKInterface::row_status(
int constraint_index)
const {
714 DCHECK_GE(constraint_index, 0);
715 DCHECK_LT(constraint_index, last_constraint_index_);
716 const int glpk_basis_status =
717 glp_get_row_stat(lp_, MPSolverIndexToGlpkIndex(constraint_index));
718 return TransformGLPKBasisStatus(glpk_basis_status);
721 MPSolver::BasisStatus GLPKInterface::column_status(
int variable_index)
const {
722 DCHECK_GE(variable_index, 0);
723 DCHECK_LT(variable_index, last_variable_index_);
724 const int glpk_basis_status =
725 glp_get_col_stat(lp_, MPSolverIndexToGlpkIndex(variable_index));
726 return TransformGLPKBasisStatus(glpk_basis_status);
729 bool GLPKInterface::CheckSolutionExists()
const {
730 if (result_status_ == MPSolver::ABNORMAL) {
731 LOG(WARNING) <<
"Ignoring ABNORMAL status from GLPK: This status may or may"
732 <<
" not indicate that a solution exists.";
736 return MPSolverInterface::CheckSolutionExists();
740 bool GLPKInterface::CheckBestObjectiveBoundExists()
const {
741 if (result_status_ == MPSolver::ABNORMAL) {
742 LOG(WARNING) <<
"Ignoring ABNORMAL status from GLPK: This status may or may"
743 <<
" not indicate that information is available on the best"
744 <<
" objective bound.";
748 return MPSolverInterface::CheckBestObjectiveBoundExists();
752 double GLPKInterface::ComputeExactConditionNumber()
const {
753 if (!IsContinuous()) {
755 LOG(DFATAL) <<
"ComputeExactConditionNumber not implemented for"
756 <<
" GLPK_MIXED_INTEGER_PROGRAMMING";
759 if (!CheckSolutionIsSynchronized())
return 0.0;
762 CheckSolutionExists();
763 const int num_rows = glp_get_num_rows(lp_);
764 const int num_cols = glp_get_num_cols(lp_);
766 std::unique_ptr<double[]> row_scaling_factor(
new double[num_rows + 1]);
767 std::unique_ptr<double[]> column_scaling_factor(
new double[num_cols + 1]);
768 for (
int row = 1;
row <= num_rows; ++
row) {
769 row_scaling_factor[
row] = glp_get_rii(lp_,
row);
771 for (
int col = 1;
col <= num_cols; ++
col) {
772 column_scaling_factor[
col] = glp_get_sjj(lp_,
col);
774 return ComputeInverseScaledBasisL1Norm(num_rows, num_cols,
775 row_scaling_factor.get(),
776 column_scaling_factor.get()) *
777 ComputeScaledBasisL1Norm(num_rows, num_cols, row_scaling_factor.get(),
778 column_scaling_factor.get());
781 double GLPKInterface::ComputeScaledBasisL1Norm(
782 int num_rows,
int num_cols,
double* row_scaling_factor,
783 double* column_scaling_factor)
const {
785 std::unique_ptr<double[]> values(
new double[num_rows + 1]);
786 std::unique_ptr<int[]> indices(
new int[num_rows + 1]);
787 for (
int col = 1;
col <= num_cols; ++
col) {
788 const int glpk_basis_status = glp_get_col_stat(lp_,
col);
790 if (glpk_basis_status == GLP_BS) {
792 const int num_nz = glp_get_mat_col(lp_,
col, indices.get(), values.get());
793 double column_norm = 0.0;
794 for (
int k = 1; k <= num_nz; k++) {
795 column_norm += fabs(values[k] * row_scaling_factor[indices[k]]);
797 column_norm *= fabs(column_scaling_factor[
col]);
803 for (
int row = 1;
row <= num_rows; ++
row) {
804 const int glpk_basis_status = glp_get_row_stat(lp_,
row);
806 if (glpk_basis_status == GLP_BS) {
810 const double column_norm = fabs(row_scaling_factor[
row]);
818 double GLPKInterface::ComputeInverseScaledBasisL1Norm(
819 int num_rows,
int num_cols,
double* row_scaling_factor,
820 double* column_scaling_factor)
const {
822 if (!glp_bf_exists(lp_)) {
823 const int factorize_status = glp_factorize(lp_);
824 switch (factorize_status) {
826 LOG(FATAL) <<
"Not able to factorize: error GLP_EBADB.";
831 <<
"Not able to factorize: "
832 <<
"the basis matrix is singular within the working precision.";
833 return MPSolver::infinity();
837 <<
"Not able to factorize: the basis matrix is ill-conditioned.";
838 return MPSolver::infinity();
844 std::unique_ptr<double[]> right_hand_side(
new double[num_rows + 1]);
858 for (
int k = 1; k <= num_rows; ++k) {
859 for (
int row = 1;
row <= num_rows; ++
row) {
860 right_hand_side[
row] = 0.0;
862 right_hand_side[k] = 1.0;
864 for (
int row = 1;
row <= num_rows; ++
row) {
865 right_hand_side[
row] /= row_scaling_factor[
row];
867 glp_ftran(lp_, right_hand_side.get());
871 for (
int row = 1;
row <= num_rows; ++
row) {
872 const int k = glp_get_bhead(lp_,
row);
875 right_hand_side[
row] *= row_scaling_factor[k];
878 right_hand_side[
row] /= column_scaling_factor[k - num_rows];
882 double column_norm = 0.0;
883 for (
int row = 1;
row <= num_rows; ++
row) {
884 column_norm += fabs(right_hand_side[
row]);
894 void GLPKInterface::ConfigureGLPKParameters(
const MPSolverParameters& param) {
896 glp_init_iocp(&mip_param_);
898 if (solver_->time_limit()) {
899 VLOG(1) <<
"Setting time limit = " << solver_->time_limit() <<
" ms.";
900 mip_param_.tm_lim = solver_->time_limit();
903 mip_param_.cb_func = GLPKGatherInformationCallback;
905 mip_param_.cb_info = mip_callback_info_.get();
911 glp_init_smcp(&lp_param_);
913 if (solver_->time_limit()) {
914 VLOG(1) <<
"Setting time limit = " << solver_->time_limit() <<
" ms.";
915 lp_param_.tm_lim = solver_->time_limit();
919 glp_scale_prob(lp_, GLP_SF_AUTO);
922 glp_adv_basis(lp_, 0);
925 SetParameters(param);
928 void GLPKInterface::SetParameters(
const MPSolverParameters& param) {
929 SetCommonParameters(param);
931 SetMIPParameters(param);
935 void GLPKInterface::SetRelativeMipGap(
double value) {
937 mip_param_.mip_gap =
value;
939 LOG(WARNING) <<
"The relative MIP gap is only available "
940 <<
"for discrete problems.";
944 void GLPKInterface::SetPrimalTolerance(
double value) {
945 lp_param_.tol_bnd =
value;
948 void GLPKInterface::SetDualTolerance(
double value) { lp_param_.tol_dj =
value; }
950 void GLPKInterface::SetPresolveMode(
int value) {
952 case MPSolverParameters::PRESOLVE_OFF: {
953 mip_param_.presolve = GLP_OFF;
954 lp_param_.presolve = GLP_OFF;
957 case MPSolverParameters::PRESOLVE_ON: {
958 mip_param_.presolve = GLP_ON;
959 lp_param_.presolve = GLP_ON;
963 SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE,
value);
968 void GLPKInterface::SetScalingMode(
int value) {
969 SetUnsupportedIntegerParam(MPSolverParameters::SCALING);
972 void GLPKInterface::SetLpAlgorithm(
int value) {
974 case MPSolverParameters::DUAL: {
976 lp_param_.meth = GLP_DUALP;
979 case MPSolverParameters::PRIMAL: {
980 lp_param_.meth = GLP_PRIMAL;
983 case MPSolverParameters::BARRIER:
985 SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
991 MPSolverInterface* BuildGLPKInterface(
bool mip, MPSolver*
const solver) {
992 return new GLPKInterface(solver, mip);
996 #endif // #if defined(USE_GLPK)