OR-Tools  8.0
glpk_interface.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 //
15 
16 #if defined(USE_GLPK)
17 
18 #include <cmath>
19 #include <cstddef>
20 #include <limits>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include "absl/memory/memory.h"
27 #include "absl/strings/str_format.h"
29 #include "ortools/base/hash.h"
31 #include "ortools/base/logging.h"
32 #include "ortools/base/timer.h"
34 
35 extern "C" {
36 #include "glpk.h"
37 }
38 
39 namespace operations_research {
40 // Class to store information gathered in the callback
41 class GLPKInformation {
42  public:
43  explicit GLPKInformation(bool maximize) : num_all_nodes_(0) {
44  ResetBestObjectiveBound(maximize);
45  }
46  void Reset(bool maximize) {
47  num_all_nodes_ = 0;
48  ResetBestObjectiveBound(maximize);
49  }
50  void ResetBestObjectiveBound(bool maximize) {
51  if (maximize) {
52  best_objective_bound_ = std::numeric_limits<double>::infinity();
53  } else {
54  best_objective_bound_ = -std::numeric_limits<double>::infinity();
55  }
56  }
57  int num_all_nodes_;
58  double best_objective_bound_;
59 };
60 
61 // Function to be called in the GLPK callback
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)) {
67  // The best bound and the number of nodes change only when GLPK
68  // branches, generates cuts or finds an integer solution.
69  case GLP_ISELECT:
70  case GLP_IROWGEN:
71  case GLP_IBINGO: {
72  // Get total number of nodes
73  glp_ios_tree_size(tree, nullptr, nullptr, &glpk_info->num_all_nodes_);
74  // Get best bound
75  int node_id = glp_ios_best_node(tree);
76  if (node_id > 0) {
77  glpk_info->best_objective_bound_ = glp_ios_node_bound(tree, node_id);
78  }
79  break;
80  }
81  default:
82  break;
83  }
84 }
85 
86 // ----- GLPK Solver -----
87 
88 namespace {
89 // GLPK indexes its variables and constraints starting at 1.
90 int MPSolverIndexToGlpkIndex(int index) { return index + 1; }
91 } // namespace
92 
93 class GLPKInterface : public MPSolverInterface {
94  public:
95  // Constructor that takes a name for the underlying glpk solver.
96  GLPKInterface(MPSolver* const solver, bool mip);
97  ~GLPKInterface() override;
98 
99  // Sets the optimization direction (min/max).
100  void SetOptimizationDirection(bool maximize) override;
101 
102  // ----- Solve -----
103  // Solve the problem using the parameter values specified.
104  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
105 
106  // ----- Model modifications and extraction -----
107  // Resets extracted model
108  void Reset() override;
109 
110  // Modify bounds.
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,
114  double ub) override;
115 
116  // Add Constraint incrementally.
117  void AddRowConstraint(MPConstraint* const ct) override;
118  // Add variable incrementally.
119  void AddVariable(MPVariable* const var) override;
120  // Change a coefficient in a constraint.
121  void SetCoefficient(MPConstraint* const constraint,
122  const MPVariable* const variable, double new_value,
123  double old_value) override;
124  // Clear a constraint from all its terms.
125  void ClearConstraint(MPConstraint* const constraint) override;
126  // Change a coefficient in the linear objective
127  void SetObjectiveCoefficient(const MPVariable* const variable,
128  double coefficient) override;
129  // Change the constant term in the linear objective.
130  void SetObjectiveOffset(double value) override;
131  // Clear the objective from all its terms.
132  void ClearObjective() override;
133 
134  // ------ Query statistics on the solution and the solve ------
135  // Number of simplex iterations
136  int64 iterations() const override;
137  // Number of branch-and-bound nodes. Only available for discrete problems.
138  int64 nodes() const override;
139  // Best objective bound. Only available for discrete problems.
140  double best_objective_bound() const override;
141 
142  // Returns the basis status of a row.
143  MPSolver::BasisStatus row_status(int constraint_index) const override;
144  // Returns the basis status of a column.
145  MPSolver::BasisStatus column_status(int variable_index) const override;
146 
147  // Checks whether a feasible solution exists.
148  bool CheckSolutionExists() const override;
149  // Checks whether information on the best objective bound exists.
150  bool CheckBestObjectiveBoundExists() const override;
151 
152  // ----- Misc -----
153  // Query problem type.
154  bool IsContinuous() const override { return IsLP(); }
155  bool IsLP() const override { return !mip_; }
156  bool IsMIP() const override { return mip_; }
157 
158  void ExtractNewVariables() override;
159  void ExtractNewConstraints() override;
160  void ExtractObjective() override;
161 
162  std::string SolverVersion() const override {
163  return absl::StrFormat("GLPK %s", glp_version());
164  }
165 
166  void* underlying_solver() override { return reinterpret_cast<void*>(lp_); }
167 
168  double ComputeExactConditionNumber() const override;
169 
170  private:
171  // Configure the solver's parameters.
172  void ConfigureGLPKParameters(const MPSolverParameters& param);
173 
174  // Set all parameters in the underlying solver.
175  void SetParameters(const MPSolverParameters& param) override;
176  // Set each parameter in the underlying solver.
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;
183 
184  void ExtractOldConstraints();
185  void ExtractOneConstraint(MPConstraint* const constraint, int* const indices,
186  double* const coefs);
187  // Transforms basis status from GLPK integer code to MPSolver::BasisStatus.
188  MPSolver::BasisStatus TransformGLPKBasisStatus(int glpk_basis_status) const;
189 
190  // Computes the L1-norm of the current scaled basis.
191  // The L1-norm |A| is defined as max_j sum_i |a_ij|
192  // This method is available only for continuous problems.
193  double ComputeScaledBasisL1Norm(int num_rows, int num_cols,
194  double* row_scaling_factor,
195  double* column_scaling_factor) const;
196 
197  // Computes the L1-norm of the inverse of the current scaled
198  // basis.
199  // This method is available only for continuous problems.
200  double ComputeInverseScaledBasisL1Norm(int num_rows, int num_cols,
201  double* row_scaling_factor,
202  double* column_scaling_factor) const;
203 
204  glp_prob* lp_;
205  bool mip_;
206 
207  // Parameters
208  glp_smcp lp_param_;
209  glp_iocp mip_param_;
210  // For the callback
211  std::unique_ptr<GLPKInformation> mip_callback_info_;
212 };
213 
214 // Creates a LP/MIP instance with the specified name and minimization objective.
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_);
221 }
222 
223 // Frees the LP memory allocations.
224 GLPKInterface::~GLPKInterface() {
225  CHECK(lp_ != nullptr);
226  glp_delete_prob(lp_);
227  lp_ = nullptr;
228 }
229 
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();
237 }
238 
239 // ------ Model modifications and extraction -----
240 
241 // Not cached
242 void GLPKInterface::SetOptimizationDirection(bool maximize) {
243  InvalidateSolutionSynchronization();
244  glp_set_obj_dir(lp_, maximize ? GLP_MAX : GLP_MIN);
245 }
246 
247 void GLPKInterface::SetVariableBounds(int mpsolver_var_index, double lb,
248  double ub) {
249  InvalidateSolutionSynchronization();
250  if (!variable_is_extracted(mpsolver_var_index)) {
251  sync_status_ = MUST_RELOAD;
252  return;
253  }
254  // Not cached if the variable has been extracted.
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) {
260  if (lb == ub) {
261  glp_set_col_bnds(lp_, glpk_var_index, GLP_FX, lb, ub);
262  } else {
263  glp_set_col_bnds(lp_, glpk_var_index, GLP_DB, lb, ub);
264  }
265  } else {
266  glp_set_col_bnds(lp_, glpk_var_index, GLP_LO, lb, 0.0);
267  }
268  } else if (ub != infinity) {
269  glp_set_col_bnds(lp_, glpk_var_index, GLP_UP, 0.0, ub);
270  } else {
271  glp_set_col_bnds(lp_, glpk_var_index, GLP_FR, 0.0, 0.0);
272  }
273 }
274 
275 void GLPKInterface::SetVariableInteger(int mpsolver_var_index, bool integer) {
276  InvalidateSolutionSynchronization();
277  if (mip_) {
278  if (variable_is_extracted(mpsolver_var_index)) {
279  // Not cached if the variable has been extracted.
280  glp_set_col_kind(lp_, MPSolverIndexToGlpkIndex(mpsolver_var_index),
281  integer ? GLP_IV : GLP_CV);
282  } else {
283  sync_status_ = MUST_RELOAD;
284  }
285  }
286 }
287 
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;
293  return;
294  }
295  // Not cached if the row has been extracted
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) {
302  if (lb == ub) {
303  glp_set_row_bnds(lp_, glpk_constraint_index, GLP_FX, lb, ub);
304  } else {
305  glp_set_row_bnds(lp_, glpk_constraint_index, GLP_DB, lb, ub);
306  }
307  } else {
308  glp_set_row_bnds(lp_, glpk_constraint_index, GLP_LO, lb, 0.0);
309  }
310  } else if (ub != infinity) {
311  glp_set_row_bnds(lp_, glpk_constraint_index, GLP_UP, 0.0, ub);
312  } else {
313  glp_set_row_bnds(lp_, glpk_constraint_index, GLP_FR, 0.0, 0.0);
314  }
315 }
316 
317 void GLPKInterface::SetCoefficient(MPConstraint* const constraint,
318  const MPVariable* const variable,
319  double new_value, double old_value) {
320  InvalidateSolutionSynchronization();
321  // GLPK does not allow to modify one coefficient at a time, so we
322  // extract the whole constraint again, if it has been extracted
323  // already and if it does not contain new variables. Otherwise, we
324  // cache the modification.
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());
332  }
333 }
334 
335 // Not cached
336 void GLPKInterface::ClearConstraint(MPConstraint* const constraint) {
337  InvalidateSolutionSynchronization();
338  // Constraint may have not been extracted yet.
339  if (constraint_is_extracted(constraint->index())) {
340  glp_set_mat_row(lp_, MPSolverIndexToGlpkIndex(constraint->index()), 0,
341  nullptr, nullptr);
342  }
343 }
344 
345 // Cached
346 void GLPKInterface::SetObjectiveCoefficient(const MPVariable* const variable,
347  double coefficient) {
348  sync_status_ = MUST_RELOAD;
349 }
350 
351 // Cached
352 void GLPKInterface::SetObjectiveOffset(double value) {
353  sync_status_ = MUST_RELOAD;
354 }
355 
356 // Clear objective of all its terms (linear)
357 void GLPKInterface::ClearObjective() {
358  InvalidateSolutionSynchronization();
359  for (const auto& entry : solver_->objective_->coefficients_) {
360  const int mpsolver_var_index = entry.first->index();
361  // Variable may have not been extracted yet.
362  if (!variable_is_extracted(mpsolver_var_index)) {
363  DCHECK_NE(MODEL_SYNCHRONIZED, sync_status_);
364  } else {
365  glp_set_obj_coef(lp_, MPSolverIndexToGlpkIndex(mpsolver_var_index), 0.0);
366  }
367  }
368  // Constant term.
369  glp_set_obj_coef(lp_, 0, 0.0);
370 }
371 
372 void GLPKInterface::AddRowConstraint(MPConstraint* const ct) {
373  sync_status_ = MUST_RELOAD;
374 }
375 
376 void GLPKInterface::AddVariable(MPVariable* const var) {
377  sync_status_ = MUST_RELOAD;
378 }
379 
380 // Define new variables and add them to existing constraints.
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());
390  }
391  SetVariableBounds(/*mpsolver_var_index=*/j, var->lb(), var->ub());
392  SetVariableInteger(/*mpsolver_var_index=*/j, var->integer());
393 
394  // The true objective coefficient will be set later in ExtractObjective.
395  double tmp_obj_coef = 0.0;
396  glp_set_obj_coef(lp_, MPSolverIndexToGlpkIndex(j), tmp_obj_coef);
397  }
398  // Add new variables to the existing constraints.
399  ExtractOldConstraints();
400  }
401 }
402 
403 // Extract again existing constraints if they contain new variables.
404 void GLPKInterface::ExtractOldConstraints() {
405  const int max_constraint_size =
406  solver_->ComputeMaxConstraintSize(0, last_constraint_index_);
407  // The first entry in the following arrays is dummy, to be
408  // consistent with glpk API.
409  std::unique_ptr<int[]> indices(new int[max_constraint_size + 1]);
410  std::unique_ptr<double[]> coefs(new double[max_constraint_size + 1]);
411 
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();
416  if (size == 0) {
417  continue;
418  }
419  // Update the constraint's coefficients if it contains new variables.
420  if (ct->ContainsNewVariables()) {
421  ExtractOneConstraint(ct, indices.get(), coefs.get());
422  }
423  }
424 }
425 
426 // Extract one constraint. Arrays indices and coefs must be
427 // preallocated to have enough space to contain the constraint's
428 // coefficients.
429 void GLPKInterface::ExtractOneConstraint(MPConstraint* const constraint,
430  int* const indices,
431  double* const coefs) {
432  // GLPK convention is to start indexing at 1.
433  int k = 1;
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;
438  ++k;
439  }
440  glp_set_mat_row(lp_, MPSolverIndexToGlpkIndex(constraint->index()), k - 1,
441  indices, coefs);
442 }
443 
444 // Define new constraints on old and new variables.
445 void GLPKInterface::ExtractNewConstraints() {
446  int total_num_rows = solver_->constraints_.size();
447  if (last_constraint_index_ < total_num_rows) {
448  // Define new constraints
449  glp_add_rows(lp_, total_num_rows - last_constraint_index_);
450  int num_coefs = 0;
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());
457  } else {
458  glp_set_row_name(lp_, MPSolverIndexToGlpkIndex(i), ct->name().c_str());
459  }
460  // All constraints are set to be of the type <= limit_ .
461  SetConstraintBounds(/*mpsolver_constraint_index=*/i, ct->lb(), ct->ub());
462  num_coefs += ct->coefficients_.size();
463  }
464 
465  // Fill new constraints with coefficients
466  if (last_variable_index_ == 0 && last_constraint_index_ == 0) {
467  // Faster extraction when nothing has been extracted yet: build
468  // and load whole matrix at once instead of constructing rows
469  // separately.
470 
471  // The first entry in the following arrays is dummy, to be
472  // consistent with glpk API.
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]);
476  int k = 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;
484  ++k;
485  }
486  }
487  CHECK_EQ(num_coefs + 1, k);
488  glp_load_matrix(lp_, num_coefs, constraint_indices.get(),
489  variable_indices.get(), coefs.get());
490  } else {
491  // Build each new row separately.
492  int max_constraint_size = solver_->ComputeMaxConstraintSize(
493  last_constraint_index_, total_num_rows);
494  // The first entry in the following arrays is dummy, to be
495  // consistent with glpk API.
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(),
500  coefs.get());
501  }
502  }
503  }
504 }
505 
506 void GLPKInterface::ExtractObjective() {
507  // Linear objective: set objective coefficients for all variables
508  // (some might have been modified).
509  for (const auto& entry : solver_->objective_->coefficients_) {
510  glp_set_obj_coef(lp_, MPSolverIndexToGlpkIndex(entry.first->index()),
511  entry.second);
512  }
513  // Constant term.
514  glp_set_obj_coef(lp_, 0, solver_->Objective().offset());
515 }
516 
517 // Solve the problem using the parameter values specified.
518 MPSolver::ResultStatus GLPKInterface::Solve(const MPSolverParameters& param) {
519  WallTimer timer;
520  timer.Start();
521 
522  // Note that GLPK provides incrementality for LP but not for MIP.
523  if (param.GetIntegerParam(MPSolverParameters::INCREMENTALITY) ==
524  MPSolverParameters::INCREMENTALITY_OFF) {
525  Reset();
526  }
527 
528  // Set log level.
529  if (quiet_) {
530  glp_term_out(GLP_OFF);
531  } else {
532  glp_term_out(GLP_ON);
533  }
534 
535  ExtractModel();
536  VLOG(1) << absl::StrFormat("Model built in %.3f seconds.", timer.Get());
537 
538  // Configure parameters at every solve, even when the model has not
539  // been changed, in case some of the parameters such as the time
540  // limit have been changed since the last solve.
541  ConfigureGLPKParameters(param);
542 
543  // Solve
544  timer.Restart();
545  int solver_status = glp_simplex(lp_, &lp_param_);
546  if (mip_) {
547  // glp_intopt requires to solve the root LP separately.
548  // If the root LP was solved successfully, solve the MIP.
549  if (solver_status == 0) {
550  solver_status = glp_intopt(lp_, &mip_param_);
551  } else {
552  // Something abnormal occurred during the root LP solve. It is
553  // highly unlikely that an integer feasible solution is
554  // available at this point, so we don't put any effort in trying
555  // to recover it.
556  result_status_ = MPSolver::ABNORMAL;
557  if (solver_status == GLP_ETMLIM) {
558  result_status_ = MPSolver::NOT_SOLVED;
559  }
560  sync_status_ = SOLUTION_SYNCHRONIZED;
561  return result_status_;
562  }
563  }
564  VLOG(1) << absl::StrFormat("GLPK Status: %i (time spent: %.3f seconds).",
565  solver_status, timer.Get());
566 
567  // Get the results.
568  if (mip_) {
569  objective_value_ = glp_mip_obj_val(lp_);
570  } else {
571  objective_value_ = glp_get_obj_val(lp_);
572  }
573  VLOG(1) << "objective=" << objective_value_;
574  for (int i = 0; i < solver_->variables_.size(); ++i) {
575  MPVariable* const var = solver_->variables_[i];
576  double val;
577  if (mip_) {
578  val = glp_mip_col_val(lp_, MPSolverIndexToGlpkIndex(i));
579  } else {
580  val = glp_get_col_prim(lp_, MPSolverIndexToGlpkIndex(i));
581  }
582  var->set_solution_value(val);
583  VLOG(3) << var->name() << ": value =" << val;
584  if (!mip_) {
585  double reduced_cost;
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;
589  }
590  }
591  for (int i = 0; i < solver_->constraints_.size(); ++i) {
592  MPConstraint* const ct = solver_->constraints_[i];
593  if (!mip_) {
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;
599  }
600  }
601 
602  // Check the status: optimal, infeasible, etc.
603  if (mip_) {
604  int tmp_status = glp_mip_status(lp_);
605  VLOG(1) << "GLPK result status: " << tmp_status;
606  if (tmp_status == GLP_OPT) {
607  result_status_ = MPSolver::OPTIMAL;
608  } else if (tmp_status == GLP_FEAS) {
609  result_status_ = MPSolver::FEASIBLE;
610  } else if (tmp_status == GLP_NOFEAS) {
611  // For infeasible problems, GLPK actually seems to return
612  // GLP_UNDEF. So this is never (?) reached. Return infeasible
613  // in case GLPK returns a correct status in future versions.
614  result_status_ = MPSolver::INFEASIBLE;
615  } else if (solver_status == GLP_ETMLIM) {
616  result_status_ = MPSolver::NOT_SOLVED;
617  } else {
618  result_status_ = MPSolver::ABNORMAL;
619  // GLPK does not have a status code for unbounded MIP models, so
620  // we return an abnormal status instead.
621  }
622  } else {
623  int tmp_status = glp_get_status(lp_);
624  VLOG(1) << "GLPK result status: " << tmp_status;
625  if (tmp_status == GLP_OPT) {
626  result_status_ = MPSolver::OPTIMAL;
627  } else if (tmp_status == GLP_FEAS) {
628  result_status_ = MPSolver::FEASIBLE;
629  } else if (tmp_status == GLP_NOFEAS || tmp_status == GLP_INFEAS) {
630  // For infeasible problems, GLPK actually seems to return
631  // GLP_UNDEF. So this is never (?) reached. Return infeasible
632  // in case GLPK returns a correct status in future versions.
633  result_status_ = MPSolver::INFEASIBLE;
634  } else if (tmp_status == GLP_UNBND) {
635  // For unbounded problems, GLPK actually seems to return
636  // GLP_UNDEF. So this is never (?) reached. Return unbounded
637  // in case GLPK returns a correct status in future versions.
638  result_status_ = MPSolver::UNBOUNDED;
639  } else if (solver_status == GLP_ETMLIM) {
640  result_status_ = MPSolver::NOT_SOLVED;
641  } else {
642  result_status_ = MPSolver::ABNORMAL;
643  }
644  }
645 
646  sync_status_ = SOLUTION_SYNCHRONIZED;
647 
648  return result_status_;
649 }
650 
651 MPSolver::BasisStatus GLPKInterface::TransformGLPKBasisStatus(
652  int glpk_basis_status) const {
653  switch (glpk_basis_status) {
654  case GLP_BS:
655  return MPSolver::BASIC;
656  case GLP_NL:
657  return MPSolver::AT_LOWER_BOUND;
658  case GLP_NU:
659  return MPSolver::AT_UPPER_BOUND;
660  case GLP_NF:
661  return MPSolver::FREE;
662  case GLP_NS:
663  return MPSolver::FIXED_VALUE;
664  default:
665  LOG(FATAL) << "Unknown GLPK basis status";
666  return MPSolver::FREE;
667  }
668 }
669 
670 // ------ Query statistics on the solution and the solve ------
671 
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);
676  }
677 #elif GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION >= 53
678  if (!mip_ && CheckSolutionIsSynchronized()) {
679  return glp_get_it_cnt(lp_);
680  }
681 #endif
682  LOG(WARNING) << "Total number of iterations is not available";
683  return kUnknownNumberOfIterations;
684 }
685 
686 int64 GLPKInterface::nodes() const {
687  if (mip_) {
688  if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfNodes;
689  return mip_callback_info_->num_all_nodes_;
690  } else {
691  LOG(DFATAL) << "Number of nodes only available for discrete problems";
692  return kUnknownNumberOfNodes;
693  }
694 }
695 
696 double GLPKInterface::best_objective_bound() const {
697  if (mip_) {
698  if (!CheckSolutionIsSynchronized() || !CheckBestObjectiveBoundExists()) {
699  return trivial_worst_objective_bound();
700  }
701  if (solver_->variables_.empty() && solver_->constraints_.empty()) {
702  // Special case for empty model.
703  return solver_->Objective().offset();
704  } else {
705  return mip_callback_info_->best_objective_bound_;
706  }
707  } else {
708  LOG(DFATAL) << "Best objective bound only available for discrete problems";
709  return trivial_worst_objective_bound();
710  }
711 }
712 
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);
719 }
720 
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);
727 }
728 
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.";
733  return true;
734  } else {
735  // Call default implementation
736  return MPSolverInterface::CheckSolutionExists();
737  }
738 }
739 
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.";
745  return true;
746  } else {
747  // Call default implementation
748  return MPSolverInterface::CheckBestObjectiveBoundExists();
749  }
750 }
751 
752 double GLPKInterface::ComputeExactConditionNumber() const {
753  if (!IsContinuous()) {
754  // TODO(user): support MIP.
755  LOG(DFATAL) << "ComputeExactConditionNumber not implemented for"
756  << " GLPK_MIXED_INTEGER_PROGRAMMING";
757  return 0.0;
758  }
759  if (!CheckSolutionIsSynchronized()) return 0.0;
760  // Simplex is the only LP algorithm supported in the wrapper for
761  // GLPK, so when a solution exists, a basis exists.
762  CheckSolutionExists();
763  const int num_rows = glp_get_num_rows(lp_);
764  const int num_cols = glp_get_num_cols(lp_);
765  // GLPK indexes everything starting from 1 instead of 0.
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);
770  }
771  for (int col = 1; col <= num_cols; ++col) {
772  column_scaling_factor[col] = glp_get_sjj(lp_, col);
773  }
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());
779 }
780 
781 double GLPKInterface::ComputeScaledBasisL1Norm(
782  int num_rows, int num_cols, double* row_scaling_factor,
783  double* column_scaling_factor) const {
784  double norm = 0.0;
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);
789  // Take into account only basic columns.
790  if (glpk_basis_status == GLP_BS) {
791  // Compute L1-norm of column 'col': sum_row |a_row,col|.
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]]);
796  }
797  column_norm *= fabs(column_scaling_factor[col]);
798  // Compute max_col column_norm
799  norm = std::max(norm, column_norm);
800  }
801  }
802  // Slack variables.
803  for (int row = 1; row <= num_rows; ++row) {
804  const int glpk_basis_status = glp_get_row_stat(lp_, row);
805  // Take into account only basic slack variables.
806  if (glpk_basis_status == GLP_BS) {
807  // Only one non-zero coefficient: +/- 1.0 in the corresponding
808  // row. The row has a scaling coefficient but the slack variable
809  // is never scaled on top of that.
810  const double column_norm = fabs(row_scaling_factor[row]);
811  // Compute max_col column_norm
812  norm = std::max(norm, column_norm);
813  }
814  }
815  return norm;
816 }
817 
818 double GLPKInterface::ComputeInverseScaledBasisL1Norm(
819  int num_rows, int num_cols, double* row_scaling_factor,
820  double* column_scaling_factor) const {
821  // Compute the LU factorization if it doesn't exist yet.
822  if (!glp_bf_exists(lp_)) {
823  const int factorize_status = glp_factorize(lp_);
824  switch (factorize_status) {
825  case GLP_EBADB: {
826  LOG(FATAL) << "Not able to factorize: error GLP_EBADB.";
827  break;
828  }
829  case GLP_ESING: {
830  LOG(WARNING)
831  << "Not able to factorize: "
832  << "the basis matrix is singular within the working precision.";
833  return MPSolver::infinity();
834  }
835  case GLP_ECOND: {
836  LOG(WARNING)
837  << "Not able to factorize: the basis matrix is ill-conditioned.";
838  return MPSolver::infinity();
839  }
840  default:
841  break;
842  }
843  }
844  std::unique_ptr<double[]> right_hand_side(new double[num_rows + 1]);
845  double norm = 0.0;
846  // Iteratively solve B x = e_k, where e_k is the kth unit vector.
847  // The result of this computation is the kth column of B^-1.
848  // glp_ftran works on original matrix. Scale input and result to
849  // obtain the norm of the kth column in the inverse scaled
850  // matrix. See glp_ftran documentation in glpapi12.c for how the
851  // scaling is done: inv(B'') = inv(SB) * inv(B) * inv(R) where:
852  // o B'' is the scaled basis
853  // o B is the original basis
854  // o R is the diagonal row scaling matrix
855  // o SB consists of the basic columns of the augmented column
856  // scaling matrix (auxiliary variables then structural variables):
857  // S~ = diag(inv(R) | S).
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;
861  }
862  right_hand_side[k] = 1.0;
863  // Multiply input by inv(R).
864  for (int row = 1; row <= num_rows; ++row) {
865  right_hand_side[row] /= row_scaling_factor[row];
866  }
867  glp_ftran(lp_, right_hand_side.get());
868  // glp_ftran stores the result in the same vector where the right
869  // hand side was provided.
870  // Multiply result by inv(SB).
871  for (int row = 1; row <= num_rows; ++row) {
872  const int k = glp_get_bhead(lp_, row);
873  if (k <= num_rows) {
874  // Auxiliary variable.
875  right_hand_side[row] *= row_scaling_factor[k];
876  } else {
877  // Structural variable.
878  right_hand_side[row] /= column_scaling_factor[k - num_rows];
879  }
880  }
881  // Compute sum_row |vector_row|.
882  double column_norm = 0.0;
883  for (int row = 1; row <= num_rows; ++row) {
884  column_norm += fabs(right_hand_side[row]);
885  }
886  // Compute max_col column_norm
887  norm = std::max(norm, column_norm);
888  }
889  return norm;
890 }
891 
892 // ------ Parameters ------
893 
894 void GLPKInterface::ConfigureGLPKParameters(const MPSolverParameters& param) {
895  if (mip_) {
896  glp_init_iocp(&mip_param_);
897  // Time limit
898  if (solver_->time_limit()) {
899  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
900  mip_param_.tm_lim = solver_->time_limit();
901  }
902  // Initialize structures related to the callback.
903  mip_param_.cb_func = GLPKGatherInformationCallback;
904  mip_callback_info_->Reset(maximize_);
905  mip_param_.cb_info = mip_callback_info_.get();
906  // TODO(user): switch some cuts on? All cuts are off by default!?
907  }
908 
909  // Configure LP parameters in all cases since they will be used to
910  // solve the root LP in the MIP case.
911  glp_init_smcp(&lp_param_);
912  // Time limit
913  if (solver_->time_limit()) {
914  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
915  lp_param_.tm_lim = solver_->time_limit();
916  }
917 
918  // Should give a numerically better representation of the problem.
919  glp_scale_prob(lp_, GLP_SF_AUTO);
920 
921  // Use advanced initial basis (options: standard / advanced / Bixby's).
922  glp_adv_basis(lp_, 0);
923 
924  // Set parameters specified by the user.
925  SetParameters(param);
926 }
927 
928 void GLPKInterface::SetParameters(const MPSolverParameters& param) {
929  SetCommonParameters(param);
930  if (mip_) {
931  SetMIPParameters(param);
932  }
933 }
934 
935 void GLPKInterface::SetRelativeMipGap(double value) {
936  if (mip_) {
937  mip_param_.mip_gap = value;
938  } else {
939  LOG(WARNING) << "The relative MIP gap is only available "
940  << "for discrete problems.";
941  }
942 }
943 
944 void GLPKInterface::SetPrimalTolerance(double value) {
945  lp_param_.tol_bnd = value;
946 }
947 
948 void GLPKInterface::SetDualTolerance(double value) { lp_param_.tol_dj = value; }
949 
950 void GLPKInterface::SetPresolveMode(int value) {
951  switch (value) {
952  case MPSolverParameters::PRESOLVE_OFF: {
953  mip_param_.presolve = GLP_OFF;
954  lp_param_.presolve = GLP_OFF;
955  break;
956  }
957  case MPSolverParameters::PRESOLVE_ON: {
958  mip_param_.presolve = GLP_ON;
959  lp_param_.presolve = GLP_ON;
960  break;
961  }
962  default: {
963  SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value);
964  }
965  }
966 }
967 
968 void GLPKInterface::SetScalingMode(int value) {
969  SetUnsupportedIntegerParam(MPSolverParameters::SCALING);
970 }
971 
972 void GLPKInterface::SetLpAlgorithm(int value) {
973  switch (value) {
974  case MPSolverParameters::DUAL: {
975  // Use dual, and if it fails, switch to primal.
976  lp_param_.meth = GLP_DUALP;
977  break;
978  }
979  case MPSolverParameters::PRIMAL: {
980  lp_param_.meth = GLP_PRIMAL;
981  break;
982  }
983  case MPSolverParameters::BARRIER:
984  default: {
985  SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
986  value);
987  }
988  }
989 }
990 
991 MPSolverInterface* BuildGLPKInterface(bool mip, MPSolver* const solver) {
992  return new GLPKInterface(solver, mip);
993 }
994 
995 } // namespace operations_research
996 #endif // #if defined(USE_GLPK)
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::sat::FEASIBLE
@ FEASIBLE
Definition: cp_model.pb.h:230
integral_types.h
max
int64 max
Definition: alldiff_cst.cc:139
logging.h
value
int64 value
Definition: demon_profiler.cc:43
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
int64
int64_t int64
Definition: integral_types.h:34
index
int index
Definition: pack.cc:508
WallTimer::Get
double Get() const
Definition: timer.h:45
operations_research::sat::INFEASIBLE
@ INFEASIBLE
Definition: cp_model.pb.h:231
WallTimer::Restart
void Restart()
Definition: timer.h:35
timer.h
WallTimer
Definition: timer.h:23
ct
const Constraint * ct
Definition: demon_profiler.cc:42
operations_research::sat::OPTIMAL
@ OPTIMAL
Definition: cp_model.pb.h:232
operations_research::MPSolver::ResultStatus
ResultStatus
The status of solving the problem.
Definition: linear_solver.h:425
WallTimer::Start
void Start()
Definition: timer.h:31
coefficient
int64 coefficient
Definition: routing_search.cc:973
col
ColIndex col
Definition: markowitz.cc:176
row
RowIndex row
Definition: markowitz.cc:175
hash.h
maximize_
const bool maximize_
Definition: search.cc:2493
operations_research::sat::Solve
CpSolverResponse Solve(const CpModelProto &model_proto)
Solves the given CpModelProto and returns an instance of CpSolverResponse.
Definition: cp_model_solver.cc:3150
linear_solver.h
operations_research::MPSolver::BasisStatus
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
Definition: linear_solver.h:640
commandlineflags.h