A year has passed again.
2 #ifndef LEMON_LP_SOLVER_WRAPPER_H
3 #define LEMON_LP_SOLVER_WRAPPER_H
7 ///\brief Dijkstra algorithm.
24 //#include <sage_graph.h>
25 //#include <lemon/list_graph.h>
26 //#include <lemon/graph_wrapper.h>
27 #include <lemon/invalid.h>
28 //#include <bfs_dfs.h>
30 //#include <lemon/max_flow.h>
31 //#include <augmenting_flow.h>
32 //#include <iter_map.h>
44 /// \brief A partitioned vector with iterable classes.
46 /// This class implements a container in which the data is stored in an
47 /// stl vector, the range is partitioned into sets and each set is
48 /// doubly linked in a list.
49 /// That is, each class is iterable by lemon iterators, and any member of
50 /// the vector can bo moved to an other class.
52 class IterablePartition {
56 int prev; //invalid az -1
59 std::vector<Node> nodes;
64 std::vector<Tip> tips;
66 /// The classes are indexed by integers from \c 0 to \c classNum()-1.
67 int classNum() const { return tips.size(); }
68 /// This lemon style iterator iterates through a class.
70 /// Constructor. The number of classes is to be given which is fixed
71 /// over the life of the container.
72 /// The partition classes are indexed from 0 to class_num-1.
73 IterablePartition(int class_num) {
74 for (int i=0; i<class_num; ++i) {
81 void befuz(ClassIt it, int class_id) {
82 if (tips[class_id].first==-1) {
83 if (tips[class_id].last==-1) {
84 nodes[it.i].prev=nodes[it.i].next=-1;
85 tips[class_id].first=tips[class_id].last=it.i;
88 nodes[it.i].prev=tips[class_id].last;
90 nodes[tips[class_id].last].next=it.i;
91 tips[class_id].last=it.i;
94 void kifuz(ClassIt it, int class_id) {
95 if (tips[class_id].first==it.i) {
96 if (tips[class_id].last==it.i) {
97 tips[class_id].first=tips[class_id].last=-1;
99 tips[class_id].first=nodes[it.i].next;
100 nodes[nodes[it.i].next].prev=-1;
103 if (tips[class_id].last==it.i) {
104 tips[class_id].last=nodes[it.i].prev;
105 nodes[nodes[it.i].prev].next=-1;
107 nodes[nodes[it.i].next].prev=nodes[it.i].prev;
108 nodes[nodes[it.i].prev].next=nodes[it.i].next;
113 /// A new element with data \c t is pushed into the vector and into class
115 ClassIt push_back(const T& t, int class_id) {
119 int i=nodes.size()-1;
123 /// A member is moved to an other class.
124 void set(ClassIt it, int old_class_id, int new_class_id) {
125 kifuz(it.i, old_class_id);
126 befuz(it.i, new_class_id);
128 /// Returns the data pointed by \c it.
129 T& operator[](ClassIt it) { return nodes[it.i].data; }
130 /// Returns the data pointed by \c it.
131 const T& operator[](ClassIt it) const { return nodes[it.i].data; }
134 friend class IterablePartition;
138 /// Default constructor.
140 /// This constructor constructs an iterator which points
141 /// to the member of th container indexed by the integer _i.
142 ClassIt(const int& _i) : i(_i) { }
143 /// Invalid constructor.
144 ClassIt(const Invalid&) : i(-1) { }
146 /// First member of class \c class_id.
147 ClassIt& first(ClassIt& it, int class_id) const {
148 it.i=tips[class_id].first;
152 ClassIt& next(ClassIt& it) const {
153 it.i=nodes[it.i].next;
156 /// True iff the iterator is valid.
157 bool valid(const ClassIt& it) const { return it.i!=-1; }
160 /// \brief Wrappers for LP solvers
162 /// This class implements a lemon wrapper for glpk.
163 /// Later other LP-solvers will be wrapped into lemon.
164 /// The aim of this class is to give a general surface to different
165 /// solvers, i.e. it makes possible to write algorithms using LP's,
166 /// in which the solver can be changed to an other one easily.
167 class LPSolverWrapper {
175 // Row(const Invalid&) : i(0) { }
176 // Row(const int& _i) : i(_i) { }
177 // operator int() const { return i; }
179 // class RowIt : public Row {
181 // RowIt(const Row& row) : Row(row) { }
189 // Col(const Invalid&) : i(0) { }
190 // Col(const int& _i) : i(_i) { }
191 // operator int() const { return i; }
193 // class ColIt : public Col {
194 // ColIt(const Col& col) : Col(col) { }
201 typedef IterablePartition<int>::ClassIt RowIt;
203 IterablePartition<int> row_iter_map;
205 typedef IterablePartition<int>::ClassIt ColIt;
207 IterablePartition<int> col_iter_map;
208 //std::vector<int> row_id_to_lp_row_id;
209 //std::vector<int> col_id_to_lp_col_id;
213 const int INVALID_ID;
217 LPSolverWrapper() : lp(lpx_create_prob()),
220 //row_id_to_lp_row_id(), col_id_to_lp_col_id(),
221 VALID_ID(0), INVALID_ID(1) {
222 lpx_set_int_parm(lp, LPX_K_DUAL, 1);
230 lpx_set_obj_dir(lp, LPX_MIN);
234 lpx_set_obj_dir(lp, LPX_MAX);
238 int i=lpx_add_cols(lp, 1);
240 col_iter_map.first(col_it, INVALID_ID);
241 if (col_iter_map.valid(col_it)) { //van hasznalhato hely
242 col_iter_map.set(col_it, INVALID_ID, VALID_ID);
243 col_iter_map[col_it]=i;
244 //col_id_to_lp_col_id[col_iter_map[col_it]]=i;
245 } else { //a cucc vegere kell inzertalni mert nincs szabad hely
246 //col_id_to_lp_col_id.push_back(i);
247 //int j=col_id_to_lp_col_id.size()-1;
248 col_it=col_iter_map.push_back(i, VALID_ID);
250 // edge_index_map.set(e, i);
251 // lpx_set_col_bnds(lp, i, LPX_DB, 0.0, 1.0);
252 // lpx_set_obj_coef(lp, i, cost[e]);
257 int i=lpx_add_rows(lp, 1);
259 row_iter_map.first(row_it, INVALID_ID);
260 if (row_iter_map.valid(row_it)) { //van hasznalhato hely
261 row_iter_map.set(row_it, INVALID_ID, VALID_ID);
262 row_iter_map[row_it]=i;
263 } else { //a cucc vegere kell inzertalni mert nincs szabad hely
264 row_it=row_iter_map.push_back(i, VALID_ID);
268 //pair<RowIt, double>-bol kell megadni egy std range-et
270 template <typename Begin, typename End>
271 void setColCoeffs(const ColIt& col_it,
272 Begin begin, End end) {
273 int mem_length=1+lpx_get_num_rows(lp);
274 int* indices = new int[mem_length];
275 double* doubles = new double[mem_length];
277 for ( ; begin!=end; ++begin) {
279 indices[length]=row_iter_map[begin->first];
280 doubles[length]=begin->second;
282 lpx_set_mat_col(lp, col_iter_map[col_it], length, indices, doubles);
286 //pair<ColIt, double>-bol kell megadni egy std range-et
288 template <typename Begin, typename End>
289 void setRowCoeffs(const RowIt& row_it,
290 Begin begin, End end) {
291 int mem_length=1+lpx_get_num_cols(lp);
292 int* indices = new int[mem_length];
293 double* doubles = new double[mem_length];
295 for ( ; begin!=end; ++begin) {
297 indices[length]=col_iter_map[begin->first];
298 doubles[length]=begin->second;
300 lpx_set_mat_row(lp, row_iter_map[row_it], length, indices, doubles);
305 void eraseCol(const ColIt& col_it) {
306 col_iter_map.set(col_it, VALID_ID, INVALID_ID);
308 cols[1]=col_iter_map[col_it];
309 lpx_del_cols(lp, 1, cols);
310 col_iter_map[col_it]=0; //glpk specifikus
312 for (col_iter_map.first(it, VALID_ID);
313 col_iter_map.valid(it); col_iter_map.next(it)) {
314 if (col_iter_map[it]>cols[1]) --col_iter_map[it];
318 void eraseRow(const RowIt& row_it) {
319 row_iter_map.set(row_it, VALID_ID, INVALID_ID);
321 rows[1]=row_iter_map[row_it];
322 lpx_del_rows(lp, 1, rows);
323 row_iter_map[row_it]=0; //glpk specifikus
325 for (row_iter_map.first(it, VALID_ID);
326 row_iter_map.valid(it); row_iter_map.next(it)) {
327 if (row_iter_map[it]>rows[1]) --row_iter_map[it];
331 void setColBounds(const ColIt& col_it, int bound_type,
332 double lo, double up) {
333 lpx_set_col_bnds(lp, col_iter_map[col_it], bound_type, lo, up);
336 double getObjCoef(const ColIt& col_it) {
337 return lpx_get_obj_coef(lp, col_iter_map[col_it]);
340 void setRowBounds(const RowIt& row_it, int bound_type,
341 double lo, double up) {
342 lpx_set_row_bnds(lp, row_iter_map[row_it], bound_type, lo, up);
345 void setObjCoef(const ColIt& col_it, double obj_coef) {
346 lpx_set_obj_coef(lp, col_iter_map[col_it], obj_coef);
349 void solveSimplex() { lpx_simplex(lp); }
351 void solvePrimalSimplex() { lpx_simplex(lp); }
353 void solveDualSimplex() { lpx_simplex(lp); }
355 double getPrimal(const ColIt& col_it) {
356 return lpx_get_col_prim(lp, col_iter_map[col_it]);
359 double getObjVal() { return lpx_get_obj_val(lp); }
361 int rowNum() const { return lpx_get_num_rows(lp); }
363 int colNum() const { return lpx_get_num_cols(lp); }
365 int warmUp() { return lpx_warm_up(lp); }
367 void printWarmUpStatus(int i) {
369 case LPX_E_OK: cout << "LPX_E_OK" << endl; break;
370 case LPX_E_EMPTY: cout << "LPX_E_EMPTY" << endl; break;
371 case LPX_E_BADB: cout << "LPX_E_BADB" << endl; break;
372 case LPX_E_SING: cout << "LPX_E_SING" << endl; break;
376 int getPrimalStatus() { return lpx_get_prim_stat(lp); }
378 void printPrimalStatus(int i) {
380 case LPX_P_UNDEF: cout << "LPX_P_UNDEF" << endl; break;
381 case LPX_P_FEAS: cout << "LPX_P_FEAS" << endl; break;
382 case LPX_P_INFEAS: cout << "LPX_P_INFEAS" << endl; break;
383 case LPX_P_NOFEAS: cout << "LPX_P_NOFEAS" << endl; break;
387 int getDualStatus() { return lpx_get_dual_stat(lp); }
389 void printDualStatus(int i) {
391 case LPX_D_UNDEF: cout << "LPX_D_UNDEF" << endl; break;
392 case LPX_D_FEAS: cout << "LPX_D_FEAS" << endl; break;
393 case LPX_D_INFEAS: cout << "LPX_D_INFEAS" << endl; break;
394 case LPX_D_NOFEAS: cout << "LPX_D_NOFEAS" << endl; break;
397 /// Returns the status of the slack variable assigned to row \c row_it.
398 int getRowStat(const RowIt& row_it) {
399 return lpx_get_row_stat(lp, row_iter_map[row_it]);
402 void printRowStatus(int i) {
404 case LPX_BS: cout << "LPX_BS" << endl; break;
405 case LPX_NL: cout << "LPX_NL" << endl; break;
406 case LPX_NU: cout << "LPX_NU" << endl; break;
407 case LPX_NF: cout << "LPX_NF" << endl; break;
408 case LPX_NS: cout << "LPX_NS" << endl; break;
411 /// Returns the status of the variable assigned to column \c col_it.
412 int getColStat(const ColIt& col_it) {
413 return lpx_get_col_stat(lp, col_iter_map[col_it]);
416 void printColStatus(int i) {
418 case LPX_BS: cout << "LPX_BS" << endl; break;
419 case LPX_NL: cout << "LPX_NL" << endl; break;
420 case LPX_NU: cout << "LPX_NU" << endl; break;
421 case LPX_NF: cout << "LPX_NF" << endl; break;
422 case LPX_NS: cout << "LPX_NS" << endl; break;
431 #endif //LEMON_LP_SOLVER_WRAPPER_H