All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Pages
glp.hpp
Go to the documentation of this file.
1 //=======================================================================
2 // Copyright (c) 2013 Piotr Wygocki, Piotr Godlewski
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //=======================================================================
15 #ifndef PAAL_GLP_HPP
16 #define PAAL_GLP_HPP
17 
19 #include "paal/lp/constraints.hpp"
20 #include "paal/lp/ids.hpp"
21 #include "paal/lp/lp_base.hpp"
22 #include "paal/lp/problem_type.hpp"
23 #include "paal/utils/irange.hpp"
24 
25 #include <boost/range/iterator_range.hpp>
26 #include <boost/range/adaptor/indexed.hpp>
27 
28 #include <glpk.h>
29 
30 namespace paal {
31 namespace lp {
32 
33 namespace detail {
34 
39 class glp_impl {
40  using Ids = std::vector<int>;
41  using Vals = std::vector<double>;
42  using IdsVals = std::vector<std::pair<row_id, double>>;
43  using RowsInColumnIterator = IdsVals::const_iterator;
44 
45  public:
50  : m_lp(glp_create_prob()), m_total_col_nr(0), m_total_row_nr(0),
51  m_idx_cols_tmp(1), m_idx_rows_tmp(1), m_val_cols_tmp(1),
52  m_val_rows_tmp(1), m_rows_tmp(1) {
53  glp_term_out(GLP_OFF);
54  glp_init_smcp(&m_glpk_control);
55  glp_load_matrix(m_lp, 0, NULL, NULL, NULL);
56  m_glpk_control.msg_lev = GLP_MSG_OFF;
57  }
58 
62  ~glp_impl() { glp_delete_prob(m_lp); }
63 
68  static void free_env() { glp_free_env(); }
69 
74  glp_set_obj_dir(m_lp, opt_type == MINIMIZE ? GLP_MIN : GLP_MAX);
75  }
76 
86  col_id add_column(double cost_coef, double lb, double ub) {
87  int colNr = glp_add_cols(m_lp, 1);
88 
89  glp_set_col_bnds(m_lp, colNr, bounds_to_glp_type(lb, ub), lb, ub);
90  glp_set_obj_coef(m_lp, colNr, cost_coef);
91  glp_set_mat_col(m_lp, colNr, 0, NULL, NULL);
92 
93  resize_col_tmp();
94  ++m_total_col_nr;
95  m_col_idx.add(m_total_col_nr - 1);
96  return col_id(m_total_col_nr - 1);
97  }
98 
107  int rowNr = glp_add_rows(m_lp, 1);
108  auto lb = constraint.get_lower_bound();
109  auto ub = constraint.get_upper_bound();
110  glp_set_row_bnds(m_lp, rowNr, bounds_to_glp_type(lb, ub), lb, ub);
111 
112  resize_row_tmp();
113  ++m_total_row_nr;
114  m_row_idx.add(m_total_row_nr - 1);
115  auto row = row_id(m_total_row_nr - 1);
116 
117  set_row_expression(row, constraint.get_expression());
118 
119  return row;
120  }
121 
128  void set_col_lower_bound(col_id col, double lb) {
129  auto ub = get_col_upper_bound(col);
130  glp_set_col_bnds(m_lp, get_col(col), bounds_to_glp_type(lb, ub), lb,
131  ub);
132  }
133 
140  void set_col_upper_bound(col_id col, double ub) {
141  auto lb = get_col_lower_bound(col);
142  glp_set_col_bnds(m_lp, get_col(col), bounds_to_glp_type(lb, ub), lb,
143  ub);
144  }
145 
152  void set_col_cost(col_id col, double cost_coef) {
153  glp_set_obj_coef(m_lp, get_col(col), cost_coef);
154  }
155 
162  void set_row_lower_bound(row_id row, double lb) {
163  auto ub = get_row_upper_bound(row);
164  glp_set_row_bnds(m_lp, get_row(row), bounds_to_glp_type(lb, ub), lb,
165  ub);
166  }
167 
174  void set_row_upper_bound(row_id row, double ub) {
175  auto lb = get_row_lower_bound(row);
176  glp_set_row_bnds(m_lp, get_row(row), bounds_to_glp_type(lb, ub), lb,
177  ub);
178  }
179 
186  void set_row_expression(row_id row, const linear_expression &expr) {
187  auto elems = expr.get_elements();
188  int expr_size = boost::distance(elems);
189 
190  for (auto elem : elems | boost::adaptors::indexed(1)) {
191  m_idx_cols_tmp[elem.index()] = get_col(elem.value().first);
192  m_val_cols_tmp[elem.index()] = elem.value().second;
193  }
194 
195  glp_set_mat_row(m_lp, get_row(row), expr_size, &m_idx_cols_tmp[0],
196  &m_val_cols_tmp[0]);
197  }
198 
204  void delete_col(col_id col) {
205  int arr[2];
206  arr[1] = get_col(col);
207  m_col_idx.erase(col.get());
208  glp_del_cols(m_lp, 1, arr);
209  }
210 
216  void delete_row(row_id row) {
217  int arr[2];
218  arr[1] = get_row(row);
219  m_row_idx.erase(row.get());
220  glp_del_rows(m_lp, 1, arr);
221  }
222 
231  return run_simplex(type, false);
232  }
233 
243  return run_simplex(type, true);
244  }
245 
251  double get_obj_value() const { return glp_get_obj_val(m_lp); }
252 
258  double get_col_value(col_id col) const {
259  return glp_get_col_prim(m_lp, get_col(col));
260  }
261 
265  double get_col_coef(col_id col) const {
266  return glp_get_obj_coef(m_lp, get_col(col));
267  }
268 
272  double get_col_lower_bound(col_id col) const {
273  return get_col_bounds(col).first;
274  }
275 
279  double get_col_upper_bound(col_id col) const {
280  return get_col_bounds(col).second;
281  }
282 
288  double get_row_dual_value(row_id row) const {
289  return glp_get_row_dual(m_lp, get_row(row));
290  }
291 
295  double get_row_lower_bound(row_id row) const {
296  return get_row_bounds(row).first;
297  }
298 
302  double get_row_upper_bound(row_id row) const {
303  return get_row_bounds(row).second;
304  }
305 
310  linear_expression exp;
311  int size = glp_get_mat_row(m_lp, get_row(row), &m_idx_cols_tmp[0],
312  &m_val_cols_tmp[0]);
313  for (auto i : irange(1, size + 1)) {
314  exp += m_val_cols_tmp[i] * get_col_id(m_idx_cols_tmp[i]);
315  }
316  return exp;
317  }
318 
323  boost::iterator_range<RowsInColumnIterator>
325  int size = glp_get_mat_col(m_lp, get_col(col), &m_idx_rows_tmp[0],
326  &m_val_rows_tmp[0]);
327  for (auto i : irange(1, size + 1)) {
328  m_rows_tmp[i].first = get_row_id(m_idx_rows_tmp[i]);
329  m_rows_tmp[i].second = m_val_rows_tmp[i];
330  }
331  return boost::make_iterator_range(m_rows_tmp.begin() + 1,
332  m_rows_tmp.begin() + size + 1);
333  }
334 
335  private:
336  glp_impl(glp_impl &&) {}
337  glp_impl(const glp_impl &) {}
338 
342  static int bounds_to_glp_type(double lb, double ub) {
343  if (lb == ub) {
344  return GLP_FX;
345  } else if (lb == lp_traits::MINUS_INF) {
346  if (ub == lp_traits::PLUS_INF) {
347  return GLP_FR;
348  } else {
349  return GLP_UP;
350  }
351  } else {
352  if (ub == lp_traits::PLUS_INF) {
353  return GLP_LO;
354  } else {
355  return GLP_DB;
356  }
357  }
358  }
359 
364  static std::pair<double, double> glp_type_to_bounds(double lb, double ub,
365  int type) {
366  switch (type) {
367  case GLP_FX:
368  return { lb, lb };
369  case GLP_FR:
370  return { lp_traits::MINUS_INF, lp_traits::PLUS_INF };
371  case GLP_UP:
372  return { lp_traits::MINUS_INF, ub };
373  case GLP_LO:
374  return { lb, lp_traits::PLUS_INF };
375  case GLP_DB:
376  return { lb, ub };
377  default:
378  assert(false);
379  return { 0, 0 };
380  }
381  }
382 
386  static int simplex_type_to_glp(simplex_type type) {
387  switch (type) {
388  case PRIMAL:
389  return GLP_PRIMAL;
390  case DUAL:
391  return GLP_DUAL;
392  default:
393  assert(false);
394  return GLP_PRIMAL;
395  }
396  }
397 
401  std::pair<double, double> get_col_bounds(col_id col) const {
402  auto column = get_col(col);
403  return glp_type_to_bounds(glp_get_col_lb(m_lp, column),
404  glp_get_col_ub(m_lp, column),
405  glp_get_col_type(m_lp, column));
406  }
407 
411  std::pair<double, double> get_row_bounds(row_id row) const {
412  auto row_num = get_row(row);
413  return glp_type_to_bounds(glp_get_row_lb(m_lp, row_num),
414  glp_get_row_ub(m_lp, row_num),
415  glp_get_row_type(m_lp, row_num));
416  }
417 
421  int get_col(col_id col) const { return m_col_idx.get_idx(col.get()) + 1; }
422 
426  int get_row(row_id row) const { return m_row_idx.get_idx(row.get()) + 1; }
427 
431  col_id get_col_id(int col) const {
432  return col_id(m_col_idx.get_val(col - 1));
433  }
434 
438  row_id get_row_id(int row) const {
439  return row_id(m_row_idx.get_val(row - 1));
440  }
441 
447  problem_type run_simplex(simplex_type type, bool resolve) {
448  m_glpk_control.meth = simplex_type_to_glp(type);
449  static const std::string buggy_version = "4.52";
450  if (!resolve || glp_version() == buggy_version) {
451  //TODO waiting for response to on
452  //http://lists.gnu.org/archive/html/bug-glpk/2014-06/msg00000.html
453  glp_adv_basis(m_lp, 0);
454  }
455  int ret = glp_simplex(m_lp, &m_glpk_control);
456  if (resolve && ret != 0) {
457  // if basis is not valid, create basis and try again
458  glp_adv_basis(m_lp, 0);
459  ret = glp_simplex(m_lp, &m_glpk_control);
460  }
461  assert(ret == 0);
462  return get_primal_type();
463  }
464 
470  problem_type get_primal_type() {
471  if (glp_get_status(m_lp) == GLP_OPT) {
472  return OPTIMAL;
473  }
474 
475  switch (glp_get_prim_stat(m_lp)) {
476  case GLP_UNDEF:
477  return UNDEFINED;
478  case GLP_NOFEAS:
479  return INFEASIBLE;
480  case GLP_FEAS:
481  case GLP_INFEAS:
482  if (glp_get_dual_stat(m_lp) == GLP_NOFEAS) {
483  return UNBOUNDED;
484  } else {
485  return UNDEFINED;
486  }
487  default:
488  assert(false);
489  return UNDEFINED;
490  }
491  }
492 
493  void resize_col_tmp() {
494  m_idx_cols_tmp.push_back(0);
495  m_val_cols_tmp.push_back(0);
496  }
497 
498  void resize_row_tmp() {
499  m_idx_rows_tmp.push_back(0);
500  m_val_rows_tmp.push_back(0);
501  m_rows_tmp.push_back({ row_id(0), 0 });
502  }
503 
505  glp_prob *m_lp;
506  glp_smcp m_glpk_control;
507 
509  data_structures::eraseable_bimap<int> m_col_idx;
511  data_structures::eraseable_bimap<int> m_row_idx;
512 
513  int m_total_col_nr;
514  int m_total_row_nr;
515 
516  mutable Ids m_idx_cols_tmp;
517  mutable Ids m_idx_rows_tmp;
518  mutable Vals m_val_cols_tmp;
519  mutable Vals m_val_rows_tmp;
520  mutable IdsVals m_rows_tmp;
521 };
522 } // detail
523 
524 using glp = detail::lp_base<detail::glp_impl>;
525 
526 } // lp
527 } // paal
528 
529 #endif // PAAL_GLP_HPP
void delete_row(row_id row)
Definition: glp.hpp:216
double get_obj_value() const
Definition: glp.hpp:251
double get_upper_bound() const
Upper bound getter.
void set_row_expression(row_id row, const linear_expression &expr)
Definition: glp.hpp:186
const Elements & get_elements() const
Returns the iterator range of the elements in the expression.
Definition: expressions.hpp:92
void set_col_cost(col_id col, double cost_coef)
Definition: glp.hpp:152
double get_row_lower_bound(row_id row) const
Definition: glp.hpp:295
problem_type solve_simplex(simplex_type type=PRIMAL)
Definition: glp.hpp:230
Idx get_idx(const T &t) const
gets index of element t
Definition: bimap.hpp:153
LP implementation using GLPK.
Definition: glp.hpp:39
const T & get_val(Idx i) const
get value for index i
Definition: bimap.hpp:166
problem_type
LP problem type.
linear_expression get_expression() const
Expression getter.
double get_row_upper_bound(row_id row) const
Definition: glp.hpp:302
void set_col_upper_bound(col_id col, double ub)
Definition: glp.hpp:140
Idx add(const T &t)
adds element to collection
Definition: bimap.hpp:188
linear_expression get_row_expression(row_id row) const
Definition: glp.hpp:309
double get_col_upper_bound(col_id col) const
Definition: glp.hpp:279
auto irange(T begin, T end)
irange
Definition: irange.hpp:22
simplex_type
simplex method type
Definition: lp_base.hpp:39
row_id add_row(const double_bounded_expression &constraint)
Definition: glp.hpp:106
optimization_type
optimization type
Definition: lp_base.hpp:33
double get_col_coef(col_id col) const
Definition: glp.hpp:265
double get_col_lower_bound(col_id col) const
Definition: glp.hpp:272
void set_optimization_type(optimization_type opt_type)
Definition: glp.hpp:73
problem_type resolve_simplex(simplex_type type=PRIMAL)
Definition: glp.hpp:242
void set_col_lower_bound(col_id col, double lb)
Definition: glp.hpp:128
int get() const
Returns the id number.
Definition: ids.hpp:36
double get_row_dual_value(row_id row) const
Definition: glp.hpp:288
boost::iterator_range< RowsInColumnIterator > get_rows_in_column(col_id col) const
Definition: glp.hpp:324
void erase(const T &t)
erases element (takes linear time)
Definition: bimap.hpp:230
void set_row_lower_bound(row_id row, double lb)
Definition: glp.hpp:162
void delete_col(col_id col)
Definition: glp.hpp:204
col_id add_column(double cost_coef, double lb, double ub)
Definition: glp.hpp:86
void set_row_upper_bound(row_id row, double ub)
Definition: glp.hpp:174
double get_lower_bound() const
Lower bound getter.
double get_col_value(col_id col) const
Definition: glp.hpp:258
static void free_env()
Definition: glp.hpp:68