COIN-OR::LEMON - Graph Library

source: lemon-0.x/src/work/marci/lp/lp_solver_wrapper.h @ 764:615aca7091d2

Last change on this file since 764:615aca7091d2 was 764:615aca7091d2, checked in by marci, 20 years ago

An experimental LPSolverWrapper class which uses glpk. For a short
demo, max flow problems are solved with it. This demo does not
demonstrates, but the main aims of this class are row and column
generation capabilities, i.e. to be a core for easily
implementable branch-and-cut a column generetion algorithms.

File size: 11.8 KB
Line 
1// -*- c++ -*-
2#ifndef HUGO_LP_SOLVER_WRAPPER_H
3#define HUGO_LP_SOLVER_WRAPPER
4
5// #include <stdio.h>
6#include <stdlib.h>
7// #include <stdio>
8//#include <stdlib>
9#include "glpk.h"
10
11#include <iostream>
12#include <vector>
13#include <string>
14#include <list>
15#include <memory>
16#include <utility>
17
18//#include <sage_graph.h>
19//#include <hugo/list_graph.h>
20//#include <hugo/graph_wrapper.h>
21#include <hugo/invalid.h>
22//#include <bfs_dfs.h>
23//#include <stp.h>
24//#include <hugo/max_flow.h>
25//#include <augmenting_flow.h>
26//#include <iter_map.h>
27
28using std::cout;
29using std::cin;
30using std::endl;
31
32namespace hugo {
33
34  /// \brief A partitioned vector with iterable classes.
35  ///
36  /// This class implements a container in which the data is stored in an
37  /// stl vector, the range is partitioned into sets and each set is
38  /// doubly linked in a list.
39  /// That is, each class is iterable by hugo iterators, and any member of
40  /// the vector can bo moved to an other class.
41  template <typename T>
42  class IterablePartition {
43  protected:
44    struct Node {
45      T data;
46      int prev; //invalid az -1
47      int next;
48    };
49    std::vector<Node> nodes;
50    struct Tip {
51      int first;
52      int last;
53    };
54    std::vector<Tip> tips;
55  public:
56    /// The classes are indexed by integers from \c 0 to \c classNum()-1.
57    int classNum() const { return tips.size(); }
58    /// This hugo style iterator iterates through a class.
59    class ClassIt;
60    /// Constructor. The number of classes is to be given which is fixed
61    /// over the life of the container.
62    /// The partition classes are indexed from 0 to class_num-1.
63    IterablePartition(int class_num) {
64      for (int i=0; i<class_num; ++i) {
65        Tip t;
66        t.first=t.last=-1;
67        tips.push_back(t);
68      }
69    }
70  protected:
71    void befuz(ClassIt it, int class_id) {
72      if (tips[class_id].first==-1) {
73        if (tips[class_id].last==-1) {
74          nodes[it.i].prev=nodes[it.i].next=-1;
75          tips[class_id].first=tips[class_id].last=it.i;
76        }
77      } else {
78        nodes[it.i].prev=tips[class_id].last;
79        nodes[it.i].next=-1;
80        nodes[tips[class_id].last].next=it.i;
81        tips[class_id].last=it.i;
82      }
83    }
84    void kifuz(ClassIt it, int class_id) {
85      if (tips[class_id].first==it.i) {
86        if (tips[class_id].last==it.i) {
87          tips[class_id].first=tips[class_id].last=-1;
88        } else {
89          tips[class_id].first=nodes[it.i].next;
90          nodes[nodes[it.i].next].prev=-1;
91        }
92      } else {
93        if (tips[class_id].last==it.i) {
94          tips[class_id].last=nodes[it.i].prev;
95          nodes[nodes[it.i].prev].next=-1;
96        } else {
97          nodes[nodes[it.i].next].prev=nodes[it.i].prev;
98          nodes[nodes[it.i].prev].next=nodes[it.i].next;
99        }
100      }
101    }
102  public:
103    /// A new element with data \c t is pushed into the vector and into class
104    /// \c class_id.
105    ClassIt push_back(const T& t, int class_id) {
106      Node n;
107      n.data=t;
108      nodes.push_back(n);
109      int i=nodes.size()-1;
110      befuz(i, class_id);
111      return i;
112    }
113    /// A member is moved to an other class.
114    void set(ClassIt it, int old_class_id, int new_class_id) {
115      kifuz(it.i, old_class_id);
116      befuz(it.i, new_class_id);
117    }
118    /// Returns the data pointed by \c it.
119    T& operator[](ClassIt it) { return nodes[it.i].data; }
120    /// Returns the data pointed by \c it.
121    const T& operator[](ClassIt it) const { return nodes[it.i].data; }
122    class ClassIt {
123      friend class IterablePartition;
124    protected:
125      int i;
126    public:
127      /// Default constructor.
128      ClassIt() { }
129      /// This constructor constructs an iterator which points
130      /// to the member of th container indexed by the integer _i.
131      ClassIt(const int& _i) : i(_i) { }
132      /// Invalid constructor.
133      ClassIt(const Invalid&) : i(-1) { }
134    };
135    /// First member of class \c class_id.
136    ClassIt& first(ClassIt& it, int class_id) const {
137      it.i=tips[class_id].first;
138      return it;
139    }
140    /// Next member.
141    ClassIt& next(ClassIt& it) const {
142      it.i=nodes[it.i].next;
143      return it;
144    }
145    /// True iff the iterator is valid.
146    bool valid(const ClassIt& it) const { return it.i!=-1; }
147  };
148 
149  /// \brief Wrappers for LP solvers
150  ///
151  /// This class implements a hugo wrapper for glpk.
152  /// Later other LP-solvers will be wrapped into hugo.
153  /// The aim of this class is to give a general surface to different
154  /// solvers, i.e. it makes possible to write algorithms using LP's,
155  /// in which the solver can be changed to an other one easily.
156  class LPSolverWrapper {
157  public:
158
159//   class Row {
160//   protected:
161//     int i;
162//   public:
163//     Row() { }
164//     Row(const Invalid&) : i(0) { }
165//     Row(const int& _i) : i(_i) { }
166//     operator int() const { return i; }
167//   };
168//   class RowIt : public Row {
169//   public:
170//     RowIt(const Row& row) : Row(row) { }
171//   };
172
173//   class Col {
174//   protected:
175//     int i;
176//   public:
177//     Col() { }
178//     Col(const Invalid&) : i(0) { }
179//     Col(const int& _i) : i(_i) { }
180//     operator int() const { return i; }
181//   };
182//   class ColIt : public Col {
183//     ColIt(const Col& col) : Col(col) { }
184//   };
185
186  public:
187    LPX* lp;
188    typedef IterablePartition<int>::ClassIt RowIt;
189    IterablePartition<int> row_iter_map;
190    typedef IterablePartition<int>::ClassIt ColIt;
191    IterablePartition<int> col_iter_map;
192    //std::vector<int> row_id_to_lp_row_id;
193    //std::vector<int> col_id_to_lp_col_id;
194    const int VALID_ID;
195    const int INVALID_ID;
196
197  public:
198    LPSolverWrapper() : lp(lpx_create_prob()),
199                        row_iter_map(2),
200                        col_iter_map(2),
201                        //row_id_to_lp_row_id(), col_id_to_lp_col_id(),
202                        VALID_ID(0), INVALID_ID(1) {
203      lpx_set_int_parm(lp, LPX_K_DUAL, 1);
204    }
205    ~LPSolverWrapper() {
206      lpx_delete_prob(lp);
207    }
208    void setMinimize() {
209      lpx_set_obj_dir(lp, LPX_MIN);
210    }
211    void setMaximize() {
212      lpx_set_obj_dir(lp, LPX_MAX);
213    }
214    ColIt addCol() {
215      int i=lpx_add_cols(lp, 1); 
216      ColIt col_it;
217      col_iter_map.first(col_it, INVALID_ID);
218      if (col_iter_map.valid(col_it)) { //van hasznalhato hely
219        col_iter_map.set(col_it, INVALID_ID, VALID_ID);
220        col_iter_map[col_it]=i;
221        //col_id_to_lp_col_id[col_iter_map[col_it]]=i;
222      } else { //a cucc vegere kell inzertalni mert nincs szabad hely
223        //col_id_to_lp_col_id.push_back(i);
224        //int j=col_id_to_lp_col_id.size()-1;
225        col_it=col_iter_map.push_back(i, VALID_ID);
226      }
227//    edge_index_map.set(e, i);
228//    lpx_set_col_bnds(lp, i, LPX_DB, 0.0, 1.0);
229//    lpx_set_obj_coef(lp, i, cost[e]);   
230      return col_it;
231    }
232    RowIt addRow() {
233      int i=lpx_add_rows(lp, 1); 
234      RowIt row_it;
235      row_iter_map.first(row_it, INVALID_ID);
236      if (row_iter_map.valid(row_it)) { //van hasznalhato hely
237        row_iter_map.set(row_it, INVALID_ID, VALID_ID);
238        row_iter_map[row_it]=i;
239      } else { //a cucc vegere kell inzertalni mert nincs szabad hely
240        row_it=row_iter_map.push_back(i, VALID_ID);
241      }
242      return row_it;
243    }
244    //pair<RowIt, double>-bol kell megadni egy std range-et
245    template <typename Begin, typename End>
246    void setColCoeffs(const ColIt& col_it,
247                      Begin begin, End end) {
248      int mem_length=1+lpx_get_num_rows(lp);
249      int* indices = new int[mem_length];
250      double* doubles = new double[mem_length];
251      int length=0;
252      for ( ; begin!=end; ++begin) {
253        ++length;
254        indices[length]=row_iter_map[begin->first];
255        doubles[length]=begin->second;
256      }
257      lpx_set_mat_col(lp, col_iter_map[col_it], length, indices, doubles);
258      delete [] indices;
259      delete [] doubles;
260    }
261    //pair<ColIt, double>-bol kell megadni egy std range-et
262    template <typename Begin, typename End>
263    void setRowCoeffs(const RowIt& row_it,
264                      Begin begin, End end) {
265      int mem_length=1+lpx_get_num_cols(lp);
266      int* indices = new int[mem_length];
267      double* doubles = new double[mem_length];
268      int length=0;
269      for ( ; begin!=end; ++begin) {
270        ++length;
271        indices[length]=col_iter_map[begin->first];
272        doubles[length]=begin->second;
273      }
274      lpx_set_mat_row(lp, row_iter_map[row_it], length, indices, doubles);
275      delete [] indices;
276      delete [] doubles;
277    }
278    void eraseCol(const ColIt& col_it) {
279      col_iter_map.set(col_it, VALID_ID, INVALID_ID);
280      int cols[2];
281      cols[1]=col_iter_map[col_it];
282      lpx_del_cols(lp, 1, cols);
283      col_iter_map[col_it]=0; //glpk specifikus
284      ColIt it;
285      for (col_iter_map.first(it, VALID_ID);
286           col_iter_map.valid(it); col_iter_map.next(it)) {
287        if (col_iter_map[it]>cols[1]) --col_iter_map[it];
288      }
289    }
290    void eraseRow(const RowIt& row_it) {
291      row_iter_map.set(row_it, VALID_ID, INVALID_ID);
292      int rows[2];
293      rows[1]=row_iter_map[row_it];
294      lpx_del_rows(lp, 1, rows);
295      row_iter_map[row_it]=0; //glpk specifikus
296      RowIt it;
297      for (row_iter_map.first(it, VALID_ID);
298           row_iter_map.valid(it); row_iter_map.next(it)) {
299        if (row_iter_map[it]>rows[1]) --row_iter_map[it];
300      }
301    }
302    void setColBounds(const ColIt& col_it, int bound_type,
303                      double lo, double up) {
304      lpx_set_col_bnds(lp, col_iter_map[col_it], bound_type, lo, up);
305    }
306    void setObjCoef(const ColIt& col_it, double obj_coef) {
307      lpx_set_obj_coef(lp, col_iter_map[col_it], obj_coef);
308    }
309    void setRowBounds(const RowIt& row_it, int bound_type,
310                      double lo, double up) {
311      lpx_set_row_bnds(lp, row_iter_map[row_it], bound_type, lo, up);
312    }
313//   void setObjCoef(const RowIt& row_it, double obj_coef) {
314//     lpx_set_obj_coef(lp, row_iter_map[row_it], obj_coef);
315//   }
316    void solveSimplex() { lpx_simplex(lp); }
317    void solvePrimalSimplex() { lpx_simplex(lp); }
318    void solveDualSimplex() { lpx_simplex(lp); }
319    double getPrimal(const ColIt& col_it) {
320      return lpx_get_col_prim(lp, col_iter_map[col_it]);
321    }
322    double getObjVal() { return lpx_get_obj_val(lp); }
323    int rowNum() const { return lpx_get_num_rows(lp); }
324    int colNum() const { return lpx_get_num_cols(lp); }
325    int warmUp() { return lpx_warm_up(lp); }
326    void printWarmUpStatus(int i) {
327      switch (i) {
328        case LPX_E_OK: cout << "LPX_E_OK" << endl; break;
329        case LPX_E_EMPTY: cout << "LPX_E_EMPTY" << endl; break;
330        case LPX_E_BADB: cout << "LPX_E_BADB" << endl; break;
331        case LPX_E_SING: cout << "LPX_E_SING" << endl; break;
332      }
333    }
334    int getPrimalStatus() { return lpx_get_prim_stat(lp); }
335    void printPrimalStatus(int i) {
336      switch (i) {
337        case LPX_P_UNDEF: cout << "LPX_P_UNDEF" << endl; break;
338        case LPX_P_FEAS: cout << "LPX_P_FEAS" << endl; break;   
339        case LPX_P_INFEAS: cout << "LPX_P_INFEAS" << endl; break;
340        case LPX_P_NOFEAS: cout << "LPX_P_NOFEAS" << endl; break;
341      }
342    }
343    int getDualStatus() { return lpx_get_dual_stat(lp); }
344    void printDualStatus(int i) {
345      switch (i) {
346        case LPX_D_UNDEF: cout << "LPX_D_UNDEF" << endl; break;
347        case LPX_D_FEAS: cout << "LPX_D_FEAS" << endl; break;   
348        case LPX_D_INFEAS: cout << "LPX_D_INFEAS" << endl; break;
349        case LPX_D_NOFEAS: cout << "LPX_D_NOFEAS" << endl; break;
350      }
351    }
352    /// Returns the status of the slack variable assigned to row \c row_it.
353    int getRowStat(const RowIt& row_it) {
354      return lpx_get_row_stat(lp, row_iter_map[row_it]);
355    }
356    void printRowStatus(int i) {
357      switch (i) {
358        case LPX_BS: cout << "LPX_BS" << endl; break;
359        case LPX_NL: cout << "LPX_NL" << endl; break;   
360        case LPX_NU: cout << "LPX_NU" << endl; break;
361        case LPX_NF: cout << "LPX_NF" << endl; break;
362        case LPX_NS: cout << "LPX_NS" << endl; break;
363      }
364    }
365    /// Returns the status of the variable assigned to column \c col_it.
366    int getColStat(const ColIt& col_it) {
367      return lpx_get_col_stat(lp, col_iter_map[col_it]);
368    }
369    void printColStatus(int i) {
370      switch (i) {
371        case LPX_BS: cout << "LPX_BS" << endl; break;
372        case LPX_NL: cout << "LPX_NL" << endl; break;   
373        case LPX_NU: cout << "LPX_NU" << endl; break;
374        case LPX_NF: cout << "LPX_NF" << endl; break;
375        case LPX_NS: cout << "LPX_NS" << endl; break;
376      }
377    }
378  };
379
380} //namespace hugo
381
382#endif //HUGO_LP_SOLVER_WRAPPER_H
Note: See TracBrowser for help on using the repository browser.