00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <math.h>
00016 #include <stddef.h>
00017 #include "base/hash.h"
00018 #include <limits>
00019 #include <string>
00020 #include <utility>
00021 #include <vector>
00022
00023 #include "base/commandlineflags.h"
00024 #include "base/integral_types.h"
00025 #include "base/logging.h"
00026 #include "base/scoped_ptr.h"
00027 #include "base/stringprintf.h"
00028 #include "base/timer.h"
00029 #include "base/concise_iterator.h"
00030 #include "base/hash.h"
00031 #include "linear_solver/linear_solver.h"
00032
00033 #if defined(USE_GLPK)
00034
00035 extern "C" {
00036 #include "glpk.h"
00037 }
00038
00039 DECLARE_double(solver_timeout_in_seconds);
00040 DECLARE_string(solver_write_model);
00041
00042 namespace operations_research {
00043
00044
00045 class GLPKInformation {
00046 public:
00047 explicit GLPKInformation(bool maximize): num_all_nodes_(0) {
00048 ResetBestObjectiveBound(maximize);
00049 }
00050 void Reset(bool maximize) {
00051 num_all_nodes_ = 0;
00052 ResetBestObjectiveBound(maximize);
00053 }
00054 void ResetBestObjectiveBound(bool maximize) {
00055 if (maximize) {
00056 best_objective_bound_ = std::numeric_limits<double>::infinity();
00057 } else {
00058 best_objective_bound_ = -std::numeric_limits<double>::infinity();
00059 }
00060 }
00061 int num_all_nodes_;
00062 double best_objective_bound_;
00063 };
00064
00065
00066
00067
00068 void GLPKGatherInformationCallback(glp_tree* tree, void* info) {
00069 CHECK_NOTNULL(tree);
00070 CHECK_NOTNULL(info);
00071 GLPKInformation* glpk_info = reinterpret_cast<GLPKInformation*>(info);
00072 switch (glp_ios_reason(tree)) {
00073
00074
00075 case GLP_ISELECT:
00076 case GLP_IROWGEN:
00077 case GLP_IBINGO: {
00078
00079 glp_ios_tree_size(tree, NULL, NULL, &glpk_info->num_all_nodes_);
00080
00081 int node_id = glp_ios_best_node(tree);
00082 if (node_id > 0) {
00083 glpk_info->best_objective_bound_ = glp_ios_node_bound(tree, node_id);
00084 }
00085 break;
00086 }
00087 default:
00088 break;
00089 }
00090 }
00091
00092
00093
00094 class GLPKInterface : public MPSolverInterface {
00095 public:
00096
00097 GLPKInterface(MPSolver* const solver, bool mip);
00098 ~GLPKInterface();
00099
00100
00101 virtual void SetOptimizationDirection(bool maximize);
00102
00103
00104
00105 virtual MPSolver::ResultStatus Solve(const MPSolverParameters& param);
00106
00107
00108
00109 virtual void Reset();
00110
00111
00112 virtual void SetVariableBounds(int var_index, double lb, double ub);
00113 virtual void SetVariableInteger(int var_index, bool integer);
00114 virtual void SetConstraintBounds(int row_index, double lb, double ub);
00115
00116
00117 void AddRowConstraint(MPConstraint* const ct);
00118
00119 void AddVariable(MPVariable* const var);
00120
00121 virtual void SetCoefficient(MPConstraint* const constraint,
00122 const MPVariable* const variable,
00123 double new_value,
00124 double old_value);
00125
00126 virtual void ClearConstraint(MPConstraint* const constraint);
00127
00128 virtual void SetObjectiveCoefficient(const MPVariable* const variable,
00129 double coefficient);
00130
00131 virtual void SetObjectiveOffset(double value);
00132
00133 virtual void ClearObjective();
00134
00135
00136
00137 virtual int64 iterations() const;
00138
00139 virtual int64 nodes() const;
00140
00141 virtual double best_objective_bound() const;
00142
00143
00144 virtual MPSolver::BasisStatus row_status(int constraint_index) const;
00145
00146 virtual MPSolver::BasisStatus column_status(int variable_index) const;
00147
00148
00149 virtual void CheckSolutionExists() const;
00150
00151 virtual void CheckBestObjectiveBoundExists() const;
00152
00153
00154
00155 virtual void WriteModel(const string& filename);
00156
00157
00158 virtual bool IsContinuous() const { return IsLP(); }
00159 virtual bool IsLP() const { return !mip_; }
00160 virtual bool IsMIP() const { return mip_; }
00161
00162 virtual void ExtractNewVariables();
00163 virtual void ExtractNewConstraints();
00164 virtual void ExtractObjective();
00165
00166 virtual string SolverVersion() const {
00167 return StringPrintf("GLPK %s", glp_version());
00168 }
00169
00170 virtual void* underlying_solver() {
00171 return reinterpret_cast<void*>(lp_);
00172 }
00173
00174 virtual double ComputeExactConditionNumber() const;
00175
00176 private:
00177
00178 void ConfigureGLPKParameters(const MPSolverParameters& param);
00179
00180
00181 virtual void SetParameters(const MPSolverParameters& param);
00182
00183 virtual void SetRelativeMipGap(double value);
00184 virtual void SetPrimalTolerance(double value);
00185 virtual void SetDualTolerance(double value);
00186 virtual void SetPresolveMode(int value);
00187 virtual void SetLpAlgorithm(int value);
00188
00189 void ExtractOldConstraints();
00190 void ExtractOneConstraint(MPConstraint* const constraint,
00191 int* const indices,
00192 double* const coefs);
00193
00194 MPSolver::BasisStatus TransformGLPKBasisStatus(int glpk_basis_status) const;
00195
00196
00197
00198
00199 double ComputeScaledBasisL1Norm(
00200 int num_rows, int num_cols,
00201 double* row_scaling_factor, double* column_scaling_factor) const;
00202
00203
00204
00205
00206 double ComputeInverseScaledBasisL1Norm(
00207 int num_rows, int num_cols,
00208 double* row_scaling_factor, double* column_scaling_factor) const;
00209
00210 glp_prob* lp_;
00211 bool mip_;
00212
00213
00214 glp_smcp lp_param_;
00215 glp_iocp mip_param_;
00216
00217 scoped_ptr<GLPKInformation> mip_callback_info_;
00218 };
00219
00220
00221 GLPKInterface::GLPKInterface(MPSolver* const solver, bool mip)
00222 : MPSolverInterface(solver), lp_(NULL), mip_(mip),
00223 mip_callback_info_(NULL) {
00224 lp_ = glp_create_prob();
00225 glp_set_prob_name(lp_, solver_->name_.c_str());
00226 glp_set_obj_dir(lp_, GLP_MIN);
00227 mip_callback_info_.reset(new GLPKInformation(maximize_));
00228 }
00229
00230
00231 GLPKInterface::~GLPKInterface() {
00232 CHECK_NOTNULL(lp_);
00233 glp_delete_prob(lp_);
00234 lp_ = NULL;
00235 }
00236
00237 void GLPKInterface::Reset() {
00238 CHECK_NOTNULL(lp_);
00239 glp_delete_prob(lp_);
00240 lp_ = glp_create_prob();
00241 glp_set_prob_name(lp_, solver_->name_.c_str());
00242 glp_set_obj_dir(lp_, maximize_ ? GLP_MAX : GLP_MIN);
00243 ResetExtractionInformation();
00244 }
00245
00246 void GLPKInterface::WriteModel(const string& filename) {
00247 if (HasSuffixString(filename, ".lp")) {
00248 glp_write_lp(lp_, NULL, filename.c_str());
00249 } else {
00250 glp_write_mps(lp_, GLP_MPS_FILE, NULL, filename.c_str());
00251 }
00252 }
00253
00254
00255
00256
00257 void GLPKInterface::SetOptimizationDirection(bool maximize) {
00258 InvalidateSolutionSynchronization();
00259 glp_set_obj_dir(lp_, maximize ? GLP_MAX : GLP_MIN);
00260 }
00261
00262 void GLPKInterface::SetVariableBounds(int var_index, double lb, double ub) {
00263 InvalidateSolutionSynchronization();
00264 if (var_index != kNoIndex) {
00265
00266 DCHECK(lp_ != NULL);
00267 const double infinity = solver_->infinity();
00268 if (lb != -infinity) {
00269 if (ub != infinity) {
00270 if (lb == ub) {
00271 glp_set_col_bnds(lp_, var_index, GLP_FX, lb, ub);
00272 } else {
00273 glp_set_col_bnds(lp_, var_index, GLP_DB, lb, ub);
00274 }
00275 } else {
00276 glp_set_col_bnds(lp_, var_index, GLP_LO, lb, 0.0);
00277 }
00278 } else if (ub != infinity) {
00279 glp_set_col_bnds(lp_, var_index, GLP_UP, 0.0, ub);
00280 } else {
00281 glp_set_col_bnds(lp_, var_index, GLP_FR, 0.0, 0.0);
00282 }
00283 } else {
00284 sync_status_ = MUST_RELOAD;
00285 }
00286 }
00287
00288 void GLPKInterface::SetVariableInteger(int var_index, bool integer) {
00289 InvalidateSolutionSynchronization();
00290 if (mip_) {
00291 if (var_index != kNoIndex) {
00292
00293 glp_set_col_kind(lp_, var_index, integer ? GLP_IV : GLP_CV);
00294 } else {
00295 sync_status_ = MUST_RELOAD;
00296 }
00297 }
00298 }
00299
00300 void GLPKInterface::SetConstraintBounds(int index, double lb, double ub) {
00301 InvalidateSolutionSynchronization();
00302 if (index != kNoIndex) {
00303
00304 DCHECK(lp_ != NULL);
00305 const double infinity = solver_->infinity();
00306 if (lb != -infinity) {
00307 if (ub != infinity) {
00308 if (lb == ub) {
00309 glp_set_row_bnds(lp_, index, GLP_FX, lb, ub);
00310 } else {
00311 glp_set_row_bnds(lp_, index, GLP_DB, lb, ub);
00312 }
00313 } else {
00314 glp_set_row_bnds(lp_, index, GLP_LO, lb, 0.0);
00315 }
00316 } else if (ub != infinity) {
00317 glp_set_row_bnds(lp_, index, GLP_UP, 0.0, ub);
00318 } else {
00319 glp_set_row_bnds(lp_, index, GLP_FR, 0.0, 0.0);
00320 }
00321 } else {
00322 sync_status_ = MUST_RELOAD;
00323 }
00324 }
00325
00326 void GLPKInterface::SetCoefficient(MPConstraint* const constraint,
00327 const MPVariable* const variable,
00328 double new_value,
00329 double old_value) {
00330 InvalidateSolutionSynchronization();
00331
00332
00333
00334
00335 if (constraint->index() != kNoIndex &&
00336 (sync_status_ == MODEL_SYNCHRONIZED ||
00337 !constraint->ContainsNewVariables())) {
00338 const int size = constraint->coefficients_.size();
00339 scoped_array<int> indices(new int[size + 1]);
00340 scoped_array<double> coefs(new double[size + 1]);
00341 ExtractOneConstraint(constraint, indices.get(), coefs.get());
00342 }
00343 }
00344
00345
00346 void GLPKInterface::ClearConstraint(MPConstraint* const constraint) {
00347 InvalidateSolutionSynchronization();
00348 const int constraint_index = constraint->index();
00349
00350 if (constraint_index != kNoIndex) {
00351 glp_set_mat_row(lp_, constraint_index, 0, NULL, NULL);
00352 }
00353 }
00354
00355
00356 void GLPKInterface::SetObjectiveCoefficient(const MPVariable* const variable,
00357 double coefficient) {
00358 sync_status_ = MUST_RELOAD;
00359 }
00360
00361
00362 void GLPKInterface::SetObjectiveOffset(double value) {
00363 sync_status_ = MUST_RELOAD;
00364 }
00365
00366
00367 void GLPKInterface::ClearObjective() {
00368 InvalidateSolutionSynchronization();
00369 for (ConstIter<hash_map<const MPVariable*, double> > it(
00370 solver_->objective_->coefficients_);
00371 !it.at_end(); ++it) {
00372 const int var_index = it->first->index();
00373
00374 if (var_index == kNoIndex) {
00375 DCHECK_NE(MODEL_SYNCHRONIZED, sync_status_);
00376 } else {
00377 glp_set_obj_coef(lp_, var_index, 0.0);
00378 }
00379 }
00380
00381 glp_set_obj_coef(lp_, 0, 0.0);
00382 }
00383
00384 void GLPKInterface::AddRowConstraint(MPConstraint* const ct) {
00385 sync_status_ = MUST_RELOAD;
00386 }
00387
00388 void GLPKInterface::AddVariable(MPVariable* const var) {
00389 sync_status_ = MUST_RELOAD;
00390 }
00391
00392
00393 void GLPKInterface::ExtractNewVariables() {
00394 int total_num_vars = solver_->variables_.size();
00395 if (total_num_vars > last_variable_index_) {
00396 glp_add_cols(lp_, total_num_vars - last_variable_index_);
00397 for (int j = last_variable_index_; j < solver_->variables_.size(); ++j) {
00398 MPVariable* const var = solver_->variables_[j];
00399
00400 const int var_index = j + 1;
00401 var->set_index(var_index);
00402 if (!var->name().empty()) {
00403 glp_set_col_name(lp_, var_index, var->name().c_str());
00404 }
00405 SetVariableBounds(var->index(), var->lb(), var->ub());
00406 SetVariableInteger(var->index(), var->integer());
00407
00408
00409 double tmp_obj_coef = 0.0;
00410 glp_set_obj_coef(lp_, var->index(), tmp_obj_coef);
00411 }
00412
00413 ExtractOldConstraints();
00414 }
00415 }
00416
00417
00418 void GLPKInterface::ExtractOldConstraints() {
00419 int max_constraint_size = solver_->ComputeMaxConstraintSize(
00420 0, last_constraint_index_);
00421
00422
00423 scoped_array<int> indices(new int[max_constraint_size + 1]);
00424 scoped_array<double> coefs(new double[max_constraint_size + 1]);
00425
00426 for (int i = 0; i < last_constraint_index_; ++i) {
00427 MPConstraint* const ct = solver_->constraints_[i];
00428 DCHECK_NE(kNoIndex, ct->index());
00429 const int size = ct->coefficients_.size();
00430 if (size == 0) {
00431 continue;
00432 }
00433
00434 if (ct->ContainsNewVariables()) {
00435 ExtractOneConstraint(ct, indices.get(), coefs.get());
00436 }
00437 }
00438 }
00439
00440
00441
00442
00443 void GLPKInterface::ExtractOneConstraint(MPConstraint* const constraint,
00444 int* const indices,
00445 double* const coefs) {
00446
00447 int k = 1;
00448 for (ConstIter<hash_map<const MPVariable*, double> > it(
00449 constraint->coefficients_);
00450 !it.at_end(); ++it) {
00451 const int var_index = it->first->index();
00452 DCHECK_NE(kNoIndex, var_index);
00453 indices[k] = var_index;
00454 coefs[k] = it->second;
00455 ++k;
00456 }
00457 glp_set_mat_row(lp_, constraint->index(), k-1, indices, coefs);
00458 }
00459
00460
00461 void GLPKInterface::ExtractNewConstraints() {
00462 int total_num_rows = solver_->constraints_.size();
00463 if (last_constraint_index_ < total_num_rows) {
00464
00465 glp_add_rows(lp_, total_num_rows - last_constraint_index_);
00466 int num_coefs = 0;
00467 for (int i = last_constraint_index_; i < total_num_rows; ++i) {
00468
00469 const int constraint_index = i + 1;
00470 MPConstraint* ct = solver_->constraints_[i];
00471 ct->set_index(constraint_index);
00472 if (ct->name().empty()) {
00473 glp_set_row_name(lp_, constraint_index,
00474 StringPrintf("ct_%i", i).c_str());
00475 } else {
00476 glp_set_row_name(lp_, constraint_index, ct->name().c_str());
00477 }
00478
00479 SetConstraintBounds(constraint_index, ct->lb(), ct->ub());
00480 num_coefs += ct->coefficients_.size();
00481 }
00482
00483
00484 if (last_variable_index_ == 0 && last_constraint_index_ == 0) {
00485
00486
00487
00488
00489
00490
00491 scoped_array<int> variable_indices(new int[num_coefs + 1]);
00492 scoped_array<int> constraint_indices(new int[num_coefs + 1]);
00493 scoped_array<double> coefs(new double[num_coefs + 1]);
00494 int k = 1;
00495 for (int i = 0; i < solver_->constraints_.size(); ++i) {
00496 MPConstraint* ct = solver_->constraints_[i];
00497 for (hash_map<const MPVariable*, double>::const_iterator it =
00498 ct->coefficients_.begin();
00499 it != ct->coefficients_.end();
00500 ++it) {
00501 DCHECK_NE(kNoIndex, it->first->index());
00502 constraint_indices[k] = ct->index();
00503 variable_indices[k] = it->first->index();
00504 coefs[k] = it->second;
00505 ++k;
00506 }
00507 }
00508 CHECK_EQ(num_coefs + 1, k);
00509 glp_load_matrix(lp_, num_coefs, constraint_indices.get(),
00510 variable_indices.get(), coefs.get());
00511 } else {
00512
00513 int max_constraint_size = solver_->ComputeMaxConstraintSize(
00514 last_constraint_index_, total_num_rows);
00515
00516
00517 scoped_array<int> indices(new int[max_constraint_size + 1]);
00518 scoped_array<double> coefs(new double[max_constraint_size + 1]);
00519 for (int i = last_constraint_index_; i < total_num_rows; i++) {
00520 ExtractOneConstraint(solver_->constraints_[i], indices.get(),
00521 coefs.get());
00522 }
00523 }
00524 }
00525 }
00526
00527 void GLPKInterface::ExtractObjective() {
00528
00529
00530 for (hash_map<const MPVariable*, double>::const_iterator it =
00531 solver_->objective_->coefficients_.begin();
00532 it != solver_->objective_->coefficients_.end();
00533 ++it) {
00534 glp_set_obj_coef(lp_, it->first->index(), it->second);
00535 }
00536
00537 glp_set_obj_coef(lp_, 0, solver_->Objective().offset());
00538 }
00539
00540
00541 MPSolver::ResultStatus GLPKInterface::Solve(const MPSolverParameters& param) {
00542 WallTimer timer;
00543 timer.Start();
00544
00545
00546 if (param.GetIntegerParam(MPSolverParameters::INCREMENTALITY) ==
00547 MPSolverParameters::INCREMENTALITY_OFF) {
00548 Reset();
00549 }
00550
00551
00552 if (quiet_) {
00553 glp_term_out(GLP_OFF);
00554 } else {
00555 glp_term_out(GLP_ON);
00556 }
00557
00558 ExtractModel();
00559 VLOG(1) << StringPrintf("Model built in %.3f seconds.", timer.Get());
00560
00561 WriteModelToPredefinedFiles();
00562
00563
00564
00565
00566 ConfigureGLPKParameters(param);
00567
00568
00569 timer.Restart();
00570 if (mip_) {
00571
00572 int simplex_status = glp_simplex(lp_, &lp_param_);
00573
00574 if (simplex_status == 0) {
00575 glp_intopt(lp_, &mip_param_);
00576 } else {
00577
00578
00579
00580
00581 result_status_ = MPSolver::ABNORMAL;
00582 sync_status_ = SOLUTION_SYNCHRONIZED;
00583 return result_status_;
00584 }
00585 } else {
00586 glp_simplex(lp_, &lp_param_);
00587 }
00588 VLOG(1) << StringPrintf("Solved in %.3f seconds.", timer.Get());
00589
00590
00591 if (mip_) {
00592 objective_value_ = glp_mip_obj_val(lp_);
00593 } else {
00594 objective_value_ = glp_get_obj_val(lp_);
00595 }
00596 VLOG(1) << "objective=" << objective_value_;
00597 for (int i = 0; i < solver_->variables_.size(); ++i) {
00598 MPVariable* const var = solver_->variables_[i];
00599 double val;
00600 if (mip_) {
00601 val = glp_mip_col_val(lp_, var->index());
00602 } else {
00603 val = glp_get_col_prim(lp_, var->index());
00604 }
00605 var->set_solution_value(val);
00606 VLOG(3) << var->name() << ": value =" << val;
00607 if (!mip_) {
00608 double reduced_cost;
00609 reduced_cost = glp_get_col_dual(lp_, var->index());
00610 var->set_reduced_cost(reduced_cost);
00611 VLOG(4) << var->name() << ": reduced cost = " << reduced_cost;
00612 }
00613 }
00614 for (int i = 0; i < solver_->constraints_.size(); ++i) {
00615 MPConstraint* const ct = solver_->constraints_[i];
00616 if (mip_) {
00617 const double row_activity = glp_mip_row_val(lp_, ct->index());
00618 ct->set_activity(row_activity);
00619 VLOG(4) << "row " << ct->index()
00620 << ": activity = " << row_activity;
00621 } else {
00622 const double row_activity = glp_get_row_prim(lp_, ct->index());
00623 ct->set_activity(row_activity);
00624 const double dual_value = glp_get_row_dual(lp_, ct->index());
00625 ct->set_dual_value(dual_value);
00626 VLOG(4) << "row " << ct->index()
00627 << ": activity = " << row_activity
00628 << ": dual value = " << dual_value;
00629 }
00630 }
00631
00632
00633 if (mip_) {
00634 int tmp_status = glp_mip_status(lp_);
00635 VLOG(1) << "gplk result status: " << tmp_status;
00636 if (tmp_status == GLP_OPT) {
00637 result_status_ = MPSolver::OPTIMAL;
00638 } else if (tmp_status == GLP_FEAS) {
00639 result_status_ = MPSolver::FEASIBLE;
00640 } else if (tmp_status == GLP_NOFEAS) {
00641
00642
00643
00644 result_status_ = MPSolver::INFEASIBLE;
00645 } else {
00646 result_status_ = MPSolver::ABNORMAL;
00647
00648
00649 }
00650 } else {
00651 int tmp_status = glp_get_status(lp_);
00652 VLOG(1) << "gplk result status: " << tmp_status;
00653 if (tmp_status == GLP_OPT) {
00654 result_status_ = MPSolver::OPTIMAL;
00655 } else if (tmp_status == GLP_FEAS) {
00656 result_status_ = MPSolver::FEASIBLE;
00657 } else if (tmp_status == GLP_NOFEAS ||
00658 tmp_status == GLP_INFEAS) {
00659
00660
00661
00662 result_status_ = MPSolver::INFEASIBLE;
00663 } else if (tmp_status == GLP_UNBND) {
00664
00665
00666
00667 result_status_ = MPSolver::UNBOUNDED;
00668 } else {
00669 result_status_ = MPSolver::ABNORMAL;
00670 }
00671 }
00672
00673 sync_status_ = SOLUTION_SYNCHRONIZED;
00674
00675 return result_status_;
00676 }
00677
00678 MPSolver::BasisStatus
00679 GLPKInterface::TransformGLPKBasisStatus(int glpk_basis_status) const {
00680 switch (glpk_basis_status) {
00681 case GLP_BS:
00682 return MPSolver::BASIC;
00683 case GLP_NL:
00684 return MPSolver::AT_LOWER_BOUND;
00685 case GLP_NU:
00686 return MPSolver::AT_UPPER_BOUND;
00687 case GLP_NF:
00688 return MPSolver::FREE;
00689 case GLP_NS:
00690 return MPSolver::FIXED_VALUE;
00691 default:
00692 LOG(FATAL) << "Unknown GLPK basis status";
00693 return MPSolver::FREE;
00694 }
00695 }
00696
00697 MPSolverInterface* BuildGLPKInterface(MPSolver* const solver, bool mip) {
00698 return new GLPKInterface(solver, mip);
00699 }
00700
00701
00702
00703 int64 GLPKInterface::iterations() const {
00704 if (mip_) {
00705 LOG(WARNING) << "Total number of iterations is not available";
00706 return kUnknownNumberOfIterations;
00707 } else {
00708 CheckSolutionIsSynchronized();
00709 return lpx_get_int_parm(lp_, LPX_K_ITCNT);
00710 }
00711 }
00712
00713 int64 GLPKInterface::nodes() const {
00714 if (mip_) {
00715 CheckSolutionIsSynchronized();
00716 return mip_callback_info_->num_all_nodes_;
00717 } else {
00718 LOG(FATAL) << "Number of nodes only available for discrete problems";
00719 return kUnknownNumberOfNodes;
00720 }
00721 }
00722
00723 double GLPKInterface::best_objective_bound() const {
00724 if (mip_) {
00725 CheckSolutionIsSynchronized();
00726 CheckBestObjectiveBoundExists();
00727 if (solver_->variables_.size() == 0 && solver_->constraints_.size() == 0) {
00728
00729 return solver_->Objective().offset();
00730 } else {
00731 return mip_callback_info_->best_objective_bound_;
00732 }
00733 } else {
00734 LOG(FATAL) << "Best objective bound only available for discrete problems";
00735 return 0.0;
00736 }
00737 }
00738
00739 MPSolver::BasisStatus GLPKInterface::row_status(int constraint_index) const {
00740
00741 DCHECK_LE(1, constraint_index);
00742 DCHECK_GT(last_constraint_index_ + 1, constraint_index);
00743 const int glpk_basis_status = glp_get_row_stat(lp_, constraint_index);
00744 return TransformGLPKBasisStatus(glpk_basis_status);
00745 }
00746
00747 MPSolver::BasisStatus GLPKInterface::column_status(int variable_index) const {
00748
00749 DCHECK_LE(1, variable_index);
00750 DCHECK_GT(last_variable_index_ + 1, variable_index);
00751 const int glpk_basis_status = glp_get_col_stat(lp_, variable_index);
00752 return TransformGLPKBasisStatus(glpk_basis_status);
00753 }
00754
00755
00756 void GLPKInterface::CheckSolutionExists() const {
00757 if (result_status_ == MPSolver::ABNORMAL) {
00758 LOG(WARNING) << "Ignoring ABNORMAL status from GLPK: This status may or may"
00759 << " not indicate that a solution exists.";
00760 } else {
00761
00762 MPSolverInterface::CheckSolutionExists();
00763 }
00764 }
00765
00766 void GLPKInterface::CheckBestObjectiveBoundExists() const {
00767 if (result_status_ == MPSolver::ABNORMAL) {
00768 LOG(WARNING) << "Ignoring ABNORMAL status from GLPK: This status may or may"
00769 << " not indicate that information is available on the best"
00770 << " objective bound.";
00771 } else {
00772
00773 MPSolverInterface::CheckBestObjectiveBoundExists();
00774 }
00775 }
00776
00777 double GLPKInterface::ComputeExactConditionNumber() const {
00778 CHECK(IsContinuous()) <<
00779 "Condition number only available for continuous problems";
00780 CheckSolutionIsSynchronized();
00781
00782
00783 CheckSolutionExists();
00784 const int num_rows = glp_get_num_rows(lp_);
00785 const int num_cols = glp_get_num_cols(lp_);
00786
00787 scoped_array<double> row_scaling_factor(new double[num_rows + 1]);
00788 scoped_array<double> column_scaling_factor(new double[num_cols + 1]);
00789 for (int row = 1; row <= num_rows; ++row) {
00790 row_scaling_factor[row] = glp_get_rii(lp_, row);
00791 }
00792 for (int col = 1; col <= num_cols; ++col) {
00793 column_scaling_factor[col] = glp_get_sjj(lp_, col);
00794 }
00795 return
00796 ComputeInverseScaledBasisL1Norm(
00797 num_rows, num_cols,
00798 row_scaling_factor.get(), column_scaling_factor.get()) *
00799 ComputeScaledBasisL1Norm(
00800 num_rows, num_cols,
00801 row_scaling_factor.get(), column_scaling_factor.get());
00802 }
00803
00804 double GLPKInterface::ComputeScaledBasisL1Norm(
00805 int num_rows, int num_cols,
00806 double* row_scaling_factor, double* column_scaling_factor) const {
00807 double norm = 0.0;
00808 scoped_array<double> values(new double[num_rows + 1]);
00809 scoped_array<int> indices(new int[num_rows + 1]);
00810 for (int col = 1; col <= num_cols; ++col) {
00811 const int glpk_basis_status = glp_get_col_stat(lp_, col);
00812
00813 if (glpk_basis_status == GLP_BS) {
00814
00815 const int num_nz = glp_get_mat_col(lp_, col, indices.get(), values.get());
00816 double column_norm = 0.0;
00817 for (int k = 1; k <= num_nz; k++) {
00818 column_norm += fabs(values[k] * row_scaling_factor[indices[k]]);
00819 }
00820 column_norm *= fabs(column_scaling_factor[col]);
00821
00822 norm = std::max(norm, column_norm);
00823 }
00824 }
00825
00826 for (int row = 1; row <= num_rows; ++row) {
00827 const int glpk_basis_status = glp_get_row_stat(lp_, row);
00828
00829 if (glpk_basis_status == GLP_BS) {
00830
00831
00832
00833 const double column_norm = fabs(row_scaling_factor[row]);
00834
00835 norm = std::max(norm, column_norm);
00836 }
00837 }
00838 return norm;
00839 }
00840
00841 double GLPKInterface::ComputeInverseScaledBasisL1Norm(
00842 int num_rows, int num_cols,
00843 double* row_scaling_factor, double* column_scaling_factor) const {
00844
00845 if (!glp_bf_exists(lp_)) {
00846 const int factorize_status = glp_factorize(lp_);
00847 switch (factorize_status) {
00848 case GLP_EBADB: {
00849 LOG(FATAL) << "Not able to factorize: error GLP_EBADB.";
00850 break;
00851 }
00852 case GLP_ESING: {
00853 LOG(WARNING)
00854 << "Not able to factorize: "
00855 << "the basis matrix is singular within the working precision.";
00856 return MPSolver::infinity();
00857 }
00858 case GLP_ECOND: {
00859 LOG(WARNING)
00860 << "Not able to factorize: the basis matrix is ill-conditioned.";
00861 return MPSolver::infinity();
00862 }
00863 default:
00864 break;
00865 }
00866 }
00867 scoped_array<double> right_hand_side(new double[num_rows + 1]);
00868 double norm = 0.0;
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881 for (int k = 1; k <= num_rows; ++k) {
00882 for (int row = 1; row <= num_rows; ++row) {
00883 right_hand_side[row] = 0.0;
00884 }
00885 right_hand_side[k] = 1.0;
00886
00887 for (int row = 1; row <= num_rows; ++row) {
00888 right_hand_side[row] /= row_scaling_factor[row];
00889 }
00890 glp_ftran(lp_, right_hand_side.get());
00891
00892
00893
00894 for (int row = 1; row <= num_rows; ++row) {
00895 const int k = glp_get_bhead(lp_, row);
00896 if (k <= num_rows) {
00897
00898 right_hand_side[row] *= row_scaling_factor[k];
00899 } else {
00900
00901 right_hand_side[row] /= column_scaling_factor[k - num_rows];
00902 }
00903 }
00904
00905 double column_norm = 0.0;
00906 for (int row = 1; row <= num_rows; ++row) {
00907 column_norm += fabs(right_hand_side[row]);
00908 }
00909
00910 norm = std::max(norm, column_norm);
00911 }
00912 return norm;
00913 }
00914
00915
00916
00917 void GLPKInterface::ConfigureGLPKParameters(const MPSolverParameters& param) {
00918 if (mip_) {
00919 glp_init_iocp(&mip_param_);
00920
00921 if (solver_->time_limit()) {
00922 VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
00923 mip_param_.tm_lim = solver_->time_limit();
00924 }
00925
00926 mip_param_.cb_func = GLPKGatherInformationCallback;
00927 mip_callback_info_->Reset(maximize_);
00928 mip_param_.cb_info = mip_callback_info_.get();
00929
00930 }
00931
00932
00933
00934 glp_init_smcp(&lp_param_);
00935
00936 if (solver_->time_limit()) {
00937 VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
00938 lp_param_.tm_lim = solver_->time_limit();
00939 }
00940
00941
00942 glp_scale_prob(lp_, GLP_SF_AUTO);
00943
00944
00945 glp_adv_basis(lp_, NULL);
00946
00947
00948 SetParameters(param);
00949 }
00950
00951 void GLPKInterface::SetParameters(const MPSolverParameters& param) {
00952 SetCommonParameters(param);
00953 if (mip_) {
00954 SetMIPParameters(param);
00955 }
00956 }
00957
00958 void GLPKInterface::SetRelativeMipGap(double value) {
00959 if (mip_) {
00960 mip_param_.mip_gap = value;
00961 } else {
00962 LOG(WARNING) << "The relative MIP gap is only available "
00963 << "for discrete problems.";
00964 }
00965 }
00966
00967 void GLPKInterface::SetPrimalTolerance(double value) {
00968 lp_param_.tol_bnd = value;
00969 }
00970
00971 void GLPKInterface::SetDualTolerance(double value) {
00972 lp_param_.tol_dj = value;
00973 }
00974
00975 void GLPKInterface::SetPresolveMode(int value) {
00976 switch (value) {
00977 case MPSolverParameters::PRESOLVE_OFF: {
00978 mip_param_.presolve = GLP_OFF;
00979 lp_param_.presolve = GLP_OFF;
00980 break;
00981 }
00982 case MPSolverParameters::PRESOLVE_ON: {
00983 mip_param_.presolve = GLP_ON;
00984 lp_param_.presolve = GLP_ON;
00985 break;
00986 }
00987 default: {
00988 SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value);
00989 }
00990 }
00991 }
00992
00993 void GLPKInterface::SetLpAlgorithm(int value) {
00994 switch (value) {
00995 case MPSolverParameters::DUAL: {
00996
00997 lp_param_.meth = GLP_DUALP;
00998 break;
00999 }
01000 case MPSolverParameters::PRIMAL: {
01001 lp_param_.meth = GLP_PRIMAL;
01002 break;
01003 }
01004 case MPSolverParameters::BARRIER:
01005 default: {
01006 SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
01007 value);
01008 }
01009 }
01010 }
01011
01012 }
01013 #endif // #if defined(USE_GLPK)