src/work/marci/lp/lp_solver_base.h
author marci
Tue, 01 Feb 2005 12:53:30 +0000
changeset 1111 88ade201ffc6
parent 1110 src/work/marci/lp/lp_solver_wrapper_3.h@ba28dfbea5f2
child 1112 b258584569f2
permissions -rw-r--r--
lower and upper bound handling functions for rows
marci@1031
     1
// -*- c++ -*-
marci@1031
     2
#ifndef LEMON_LP_SOLVER_WRAPPER_H
marci@1031
     3
#define LEMON_LP_SOLVER_WRAPPER_H
marci@1031
     4
marci@1031
     5
///\ingroup misc
marci@1031
     6
///\file
marci@1031
     7
///\brief Dijkstra algorithm.
marci@1031
     8
marci@1031
     9
// #include <stdio.h>
marci@1031
    10
#include <stdlib.h>
marci@1097
    11
#include <iostream>
marci@1097
    12
#include <map>
marci@1104
    13
#include <limits>
marci@1031
    14
// #include <stdio>
marci@1031
    15
//#include <stdlib>
marci@1031
    16
extern "C" {
marci@1031
    17
#include "glpk.h"
marci@1031
    18
}
marci@1031
    19
marci@1031
    20
#include <iostream>
marci@1031
    21
#include <vector>
marci@1031
    22
#include <string>
marci@1031
    23
#include <list>
marci@1031
    24
#include <memory>
marci@1031
    25
#include <utility>
marci@1031
    26
marci@1031
    27
//#include <lemon/list_graph.h>
marci@1031
    28
#include <lemon/invalid.h>
marci@1099
    29
#include <expression.h>
marci@1031
    30
//#include <bfs_dfs.h>
marci@1031
    31
//#include <stp.h>
marci@1031
    32
//#include <lemon/max_flow.h>
marci@1031
    33
//#include <augmenting_flow.h>
marci@1031
    34
//#include <iter_map.h>
marci@1031
    35
marci@1031
    36
using std::cout;
marci@1031
    37
using std::cin;
marci@1031
    38
using std::endl;
marci@1031
    39
marci@1031
    40
namespace lemon {
marci@1031
    41
  
marci@1031
    42
  /// \addtogroup misc
marci@1031
    43
  /// @{
marci@1031
    44
marci@1031
    45
  /// \brief A partitioned vector with iterable classes.
marci@1031
    46
  ///
marci@1031
    47
  /// This class implements a container in which the data is stored in an 
marci@1031
    48
  /// stl vector, the range is partitioned into sets and each set is 
marci@1031
    49
  /// doubly linked in a list. 
marci@1031
    50
  /// That is, each class is iterable by lemon iterators, and any member of 
marci@1031
    51
  /// the vector can bo moved to an other class.
marci@1031
    52
  template <typename T>
marci@1031
    53
  class IterablePartition {
marci@1031
    54
  protected:
marci@1031
    55
    struct Node {
marci@1031
    56
      T data;
marci@1031
    57
      int prev; //invalid az -1
marci@1031
    58
      int next; 
marci@1031
    59
    };
marci@1031
    60
    std::vector<Node> nodes;
marci@1031
    61
    struct Tip {
marci@1031
    62
      int first;
marci@1031
    63
      int last;
marci@1031
    64
    };
marci@1031
    65
    std::vector<Tip> tips;
marci@1031
    66
  public:
marci@1031
    67
    /// The classes are indexed by integers from \c 0 to \c classNum()-1.
marci@1031
    68
    int classNum() const { return tips.size(); }
marci@1031
    69
    /// This lemon style iterator iterates through a class. 
marci@1031
    70
    class ClassIt;
marci@1031
    71
    /// Constructor. The number of classes is to be given which is fixed 
marci@1031
    72
    /// over the life of the container. 
marci@1031
    73
    /// The partition classes are indexed from 0 to class_num-1. 
marci@1031
    74
    IterablePartition(int class_num) { 
marci@1031
    75
      for (int i=0; i<class_num; ++i) {
marci@1031
    76
	Tip t;
marci@1031
    77
	t.first=t.last=-1;
marci@1031
    78
	tips.push_back(t);
marci@1031
    79
      }
marci@1031
    80
    }
marci@1031
    81
  protected:
marci@1031
    82
    void befuz(ClassIt it, int class_id) {
marci@1031
    83
      if (tips[class_id].first==-1) {
marci@1031
    84
	if (tips[class_id].last==-1) {
marci@1031
    85
	  nodes[it.i].prev=nodes[it.i].next=-1;
marci@1031
    86
	  tips[class_id].first=tips[class_id].last=it.i;
marci@1031
    87
	}
marci@1031
    88
      } else {
marci@1031
    89
	nodes[it.i].prev=tips[class_id].last;
marci@1031
    90
	nodes[it.i].next=-1;
marci@1031
    91
	nodes[tips[class_id].last].next=it.i;
marci@1031
    92
	tips[class_id].last=it.i;
marci@1031
    93
      }
marci@1031
    94
    }
marci@1031
    95
    void kifuz(ClassIt it, int class_id) {
marci@1031
    96
      if (tips[class_id].first==it.i) {
marci@1031
    97
	if (tips[class_id].last==it.i) {
marci@1031
    98
	  tips[class_id].first=tips[class_id].last=-1;
marci@1031
    99
	} else {
marci@1031
   100
	  tips[class_id].first=nodes[it.i].next;
marci@1031
   101
	  nodes[nodes[it.i].next].prev=-1;
marci@1031
   102
	}
marci@1031
   103
      } else {
marci@1031
   104
	if (tips[class_id].last==it.i) {
marci@1031
   105
	  tips[class_id].last=nodes[it.i].prev;
marci@1031
   106
	  nodes[nodes[it.i].prev].next=-1;
marci@1031
   107
	} else {
marci@1031
   108
	  nodes[nodes[it.i].next].prev=nodes[it.i].prev;
marci@1031
   109
	  nodes[nodes[it.i].prev].next=nodes[it.i].next;
marci@1031
   110
	}
marci@1031
   111
      }
marci@1031
   112
    }
marci@1031
   113
  public:
marci@1031
   114
    /// A new element with data \c t is pushed into the vector and into class 
marci@1031
   115
    /// \c class_id.
marci@1031
   116
    ClassIt push_back(const T& t, int class_id) { 
marci@1031
   117
      Node n;
marci@1031
   118
      n.data=t;
marci@1031
   119
      nodes.push_back(n);
marci@1031
   120
      int i=nodes.size()-1;
marci@1031
   121
      befuz(i, class_id);
marci@1031
   122
      return i;
marci@1031
   123
    }
marci@1031
   124
    /// A member is moved to an other class.
marci@1031
   125
    void set(ClassIt it, int old_class_id, int new_class_id) {
marci@1031
   126
      kifuz(it.i, old_class_id);
marci@1031
   127
      befuz(it.i, new_class_id);
marci@1031
   128
    }
marci@1031
   129
    /// Returns the data pointed by \c it.
marci@1031
   130
    T& operator[](ClassIt it) { return nodes[it.i].data; }
marci@1031
   131
    /// Returns the data pointed by \c it.
marci@1031
   132
    const T& operator[](ClassIt it) const { return nodes[it.i].data; }
marci@1031
   133
    ///.
marci@1031
   134
    class ClassIt {
marci@1031
   135
      friend class IterablePartition;
marci@1031
   136
    protected:
marci@1031
   137
      int i;
marci@1031
   138
    public:
marci@1031
   139
      /// Default constructor.
marci@1031
   140
      ClassIt() { }
marci@1031
   141
      /// This constructor constructs an iterator which points
marci@1031
   142
      /// to the member of th container indexed by the integer _i.
marci@1031
   143
      ClassIt(const int& _i) : i(_i) { }
marci@1031
   144
      /// Invalid constructor.
marci@1031
   145
      ClassIt(const Invalid&) : i(-1) { }
marci@1099
   146
      friend bool operator<(const ClassIt& x, const ClassIt& y);
marci@1099
   147
      friend std::ostream& operator<<(std::ostream& os, 
marci@1099
   148
				      const ClassIt& it);
marci@1031
   149
    };
marci@1099
   150
    friend bool operator<(const ClassIt& x, const ClassIt& y) {
marci@1099
   151
      return (x.i < y.i);
marci@1099
   152
    }
marci@1099
   153
    friend std::ostream& operator<<(std::ostream& os, 
marci@1099
   154
				    const ClassIt& it) {
marci@1099
   155
      os << it.i;
marci@1099
   156
      return os;
marci@1099
   157
    }
marci@1031
   158
    /// First member of class \c class_id.
marci@1031
   159
    ClassIt& first(ClassIt& it, int class_id) const {
marci@1031
   160
      it.i=tips[class_id].first;
marci@1031
   161
      return it;
marci@1031
   162
    }
marci@1031
   163
    /// Next member.
marci@1031
   164
    ClassIt& next(ClassIt& it) const {
marci@1031
   165
      it.i=nodes[it.i].next;
marci@1031
   166
      return it;
marci@1031
   167
    }
marci@1031
   168
    /// True iff the iterator is valid.
marci@1031
   169
    bool valid(const ClassIt& it) const { return it.i!=-1; }
marci@1031
   170
  };
marci@1031
   171
marci@1097
   172
marci@1031
   173
  /*! \e
marci@1111
   174
    \todo A[x,y]-t cserel. Jobboldal, baloldal csere.
marci@1111
   175
    \todo LEKERDEZESEK!!!
marci@1111
   176
    \todo DOKSI!!!! Doxygen group!!!
marci@1111
   177
    The aim of this class is to give a general surface to different 
marci@1111
   178
    solvers, i.e. it makes possible to write algorithms using LP's, 
marci@1111
   179
    in which the solver can be changed to an other one easily.
marci@1111
   180
  */
marci@1048
   181
  template <typename _Value>
marci@1031
   182
  class LPSolverBase {
marci@1031
   183
  public:
marci@1031
   184
    /// \e
marci@1048
   185
    typedef _Value Value;
marci@1048
   186
    /// \e
marci@1031
   187
    typedef IterablePartition<int>::ClassIt RowIt;
marci@1031
   188
    /// \e
marci@1031
   189
    typedef IterablePartition<int>::ClassIt ColIt;
marci@1074
   190
  public:
marci@1031
   191
    /// \e
marci@1031
   192
    IterablePartition<int> row_iter_map;
marci@1031
   193
    /// \e
marci@1031
   194
    IterablePartition<int> col_iter_map;
marci@1031
   195
    /// \e
marci@1074
   196
    const int VALID_CLASS;
marci@1031
   197
    /// \e
marci@1074
   198
    const int INVALID_CLASS;
marci@1104
   199
    /// \e 
marci@1104
   200
    static const _Value INF;
marci@1031
   201
  public:
marci@1031
   202
    /// \e
marci@1031
   203
    LPSolverBase() : row_iter_map(2), 
marci@1031
   204
		     col_iter_map(2), 
marci@1074
   205
		     VALID_CLASS(0), INVALID_CLASS(1) { }
marci@1031
   206
    /// \e
marci@1031
   207
    virtual ~LPSolverBase() { }
marci@1081
   208
marci@1081
   209
    //MATRIX INDEPEDENT MANIPULATING FUNCTIONS
marci@1081
   210
marci@1081
   211
  public:
marci@1031
   212
    /// \e
marci@1031
   213
    virtual void setMinimize() = 0;
marci@1031
   214
    /// \e
marci@1031
   215
    virtual void setMaximize() = 0;
marci@1081
   216
marci@1081
   217
    //LOW LEVEL INTERFACE, MATRIX MANIPULATING FUNCTIONS
marci@1081
   218
marci@1074
   219
  protected:
marci@1031
   220
    /// \e
marci@1111
   221
    virtual int _addCol() = 0;
marci@1111
   222
    /// \e
marci@1074
   223
    virtual int _addRow() = 0;
marci@1031
   224
    /// \e
marci@1111
   225
    virtual void _eraseCol(int i) = 0;
marci@1111
   226
    /// \e
marci@1111
   227
    virtual void _eraseRow(int i) = 0;
marci@1081
   228
    /// \e
marci@1081
   229
    virtual void _setRowCoeffs(int i, 
marci@1104
   230
			       const std::vector<std::pair<int, _Value> >& coeffs) = 0;
marci@1081
   231
    /// \e
marci@1081
   232
    virtual void _setColCoeffs(int i, 
marci@1104
   233
			       const std::vector<std::pair<int, _Value> >& coeffs) = 0;
marci@1081
   234
  public:
marci@1081
   235
    /// \e
marci@1081
   236
    enum Bound { FREE, LOWER, UPPER, DOUBLE, FIXED };
marci@1081
   237
  protected:
marci@1081
   238
    /// \e
marci@1110
   239
    /// The lower bound of a variable (column) have to be given by an 
marci@1110
   240
    /// extended number of type _Value, i.e. a finite number of type 
marci@1110
   241
    /// _Value or -INF.
marci@1110
   242
    virtual void _setColLowerBound(int i, _Value value) = 0;
marci@1110
   243
    /// \e
marci@1111
   244
    /// The lower bound of a variable (column) is an 
marci@1111
   245
    /// extended number of type _Value, i.e. a finite number of type 
marci@1111
   246
    /// _Value or -INF.
marci@1111
   247
    virtual _Value _getColLowerBound(int i) = 0;
marci@1111
   248
    /// \e
marci@1110
   249
    /// The upper bound of a variable (column) have to be given by an 
marci@1110
   250
    /// extended number of type _Value, i.e. a finite number of type 
marci@1110
   251
    /// _Value or INF.
marci@1110
   252
    virtual void _setColUpperBound(int i, _Value value) = 0;
marci@1110
   253
    /// \e
marci@1110
   254
    /// The upper bound of a variable (column) is an 
marci@1110
   255
    /// extended number of type _Value, i.e. a finite number of type 
marci@1110
   256
    /// _Value or INF.
marci@1110
   257
    virtual _Value _getColUpperBound(int i) = 0;
marci@1110
   258
    /// \e
marci@1111
   259
    /// The lower bound of a linear expression (row) have to be given by an 
marci@1111
   260
    /// extended number of type _Value, i.e. a finite number of type 
marci@1111
   261
    /// _Value or -INF.
marci@1111
   262
    virtual void _setRowLowerBound(int i, _Value value) = 0;
marci@1081
   263
    /// \e
marci@1111
   264
    /// The lower bound of a linear expression (row) is an 
marci@1111
   265
    /// extended number of type _Value, i.e. a finite number of type 
marci@1111
   266
    /// _Value or -INF.
marci@1111
   267
    virtual _Value _getRowLowerBound(int i) = 0;
marci@1111
   268
    /// \e
marci@1111
   269
    /// The upper bound of a linear expression (row) have to be given by an 
marci@1111
   270
    /// extended number of type _Value, i.e. a finite number of type 
marci@1111
   271
    /// _Value or INF.
marci@1111
   272
    virtual void _setRowUpperBound(int i, _Value value) = 0;
marci@1111
   273
    /// \e
marci@1111
   274
    /// The upper bound of a linear expression (row) is an 
marci@1111
   275
    /// extended number of type _Value, i.e. a finite number of type 
marci@1111
   276
    /// _Value or INF.
marci@1111
   277
    virtual _Value _getRowUpperBound(int i) = 0;
marci@1081
   278
    /// \e
marci@1081
   279
    virtual void _setObjCoef(int i, _Value obj_coef) = 0;
marci@1081
   280
    /// \e
marci@1081
   281
    virtual _Value _getObjCoef(int i) = 0;
marci@1081
   282
marci@1081
   283
    //LOW LEVEL, SOLUTION RETRIEVING FUNCTIONS
marci@1081
   284
marci@1081
   285
  protected:
marci@1111
   286
    /// \e
marci@1081
   287
    virtual _Value _getPrimal(int i) = 0;
marci@1081
   288
marci@1081
   289
    //HIGH LEVEL INTERFACE, MATRIX MANIPULATING FUNTIONS
marci@1081
   290
marci@1074
   291
  public:
marci@1074
   292
    /// \e
marci@1074
   293
    ColIt addCol() {
marci@1074
   294
      int i=_addCol();  
marci@1074
   295
      ColIt col_it;
marci@1074
   296
      col_iter_map.first(col_it, INVALID_CLASS);
marci@1074
   297
      if (col_iter_map.valid(col_it)) { //van hasznalhato hely
marci@1074
   298
	col_iter_map.set(col_it, INVALID_CLASS, VALID_CLASS);
marci@1074
   299
	col_iter_map[col_it]=i;
marci@1074
   300
      } else { //a cucc vegere kell inzertalni mert nincs szabad hely
marci@1074
   301
	col_it=col_iter_map.push_back(i, VALID_CLASS);
marci@1074
   302
      }
marci@1074
   303
      return col_it;
marci@1074
   304
    }
marci@1074
   305
    /// \e
marci@1111
   306
    RowIt addRow() {
marci@1111
   307
      int i=_addRow();
marci@1111
   308
      RowIt row_it;
marci@1111
   309
      row_iter_map.first(row_it, INVALID_CLASS);
marci@1111
   310
      if (row_iter_map.valid(row_it)) { //van hasznalhato hely
marci@1111
   311
	row_iter_map.set(row_it, INVALID_CLASS, VALID_CLASS);
marci@1111
   312
	row_iter_map[row_it]=i;
marci@1111
   313
      } else { //a cucc vegere kell inzertalni mert nincs szabad hely
marci@1111
   314
	row_it=row_iter_map.push_back(i, VALID_CLASS);
marci@1031
   315
      }
marci@1111
   316
      return row_it;
marci@1074
   317
    }
marci@1074
   318
    /// \e
marci@1074
   319
    void eraseCol(const ColIt& col_it) {
marci@1074
   320
      col_iter_map.set(col_it, VALID_CLASS, INVALID_CLASS);
marci@1074
   321
      int cols[2];
marci@1074
   322
      cols[1]=col_iter_map[col_it];
marci@1074
   323
      _eraseCol(cols[1]);
marci@1074
   324
      col_iter_map[col_it]=0; //glpk specifikus, de kell ez??
marci@1074
   325
      ColIt it;
marci@1074
   326
      for (col_iter_map.first(it, VALID_CLASS); 
marci@1074
   327
	   col_iter_map.valid(it); col_iter_map.next(it)) {
marci@1074
   328
	if (col_iter_map[it]>cols[1]) --col_iter_map[it];
marci@1074
   329
      }
marci@1031
   330
    }
marci@1031
   331
    /// \e
marci@1074
   332
    void eraseRow(const RowIt& row_it) {
marci@1074
   333
      row_iter_map.set(row_it, VALID_CLASS, INVALID_CLASS);
marci@1074
   334
      int rows[2];
marci@1074
   335
      rows[1]=row_iter_map[row_it];
marci@1074
   336
      _eraseRow(rows[1]);
marci@1074
   337
      row_iter_map[row_it]=0; //glpk specifikus, de kell ez??
marci@1074
   338
      RowIt it;
marci@1074
   339
      for (row_iter_map.first(it, VALID_CLASS); 
marci@1074
   340
	   row_iter_map.valid(it); row_iter_map.next(it)) {
marci@1074
   341
	if (row_iter_map[it]>rows[1]) --row_iter_map[it];
marci@1074
   342
      }
marci@1074
   343
    }
marci@1031
   344
    /// \e
marci@1111
   345
    template <typename Begin, typename End>
marci@1111
   346
    void setRowCoeffs(RowIt row_it, Begin begin, End end) {
marci@1111
   347
      std::vector<std::pair<int, double> > coeffs;
marci@1111
   348
      for ( ; begin!=end; ++begin) {
marci@1111
   349
	coeffs.push_back(std::
marci@1111
   350
			 make_pair(col_iter_map[begin->first], begin->second));
marci@1111
   351
      }
marci@1111
   352
      _setRowCoeffs(row_iter_map[row_it], coeffs);
marci@1111
   353
    }
marci@1111
   354
    /// \e
marci@1111
   355
    template <typename Begin, typename End>
marci@1111
   356
    void setColCoeffs(ColIt col_it, Begin begin, End end) {
marci@1111
   357
      std::vector<std::pair<int, double> > coeffs;
marci@1111
   358
      for ( ; begin!=end; ++begin) {
marci@1111
   359
	coeffs.push_back(std::
marci@1111
   360
			 make_pair(row_iter_map[begin->first], begin->second));
marci@1111
   361
      }
marci@1111
   362
      _setColCoeffs(col_iter_map[col_it], coeffs);
marci@1111
   363
    }
marci@1111
   364
    /// \e
marci@1110
   365
    void setColLowerBound(ColIt col_it, _Value lo) {
marci@1110
   366
      _setColLowerBound(col_iter_map[col_it], lo);
marci@1110
   367
    }
marci@1110
   368
    /// \e
marci@1111
   369
    _Value getColLowerBound(ColIt col_it) {
marci@1111
   370
      return _getColLowerBound(col_iter_map[col_it]);
marci@1111
   371
    }
marci@1111
   372
    /// \e
marci@1110
   373
    void setColUpperBound(ColIt col_it, _Value up) {
marci@1110
   374
      _setColUpperBound(col_iter_map[col_it], up);
marci@1110
   375
    }
marci@1110
   376
    /// \e
marci@1110
   377
    _Value getColUpperBound(ColIt col_it) {      
marci@1110
   378
      return _getColUpperBound(col_iter_map[col_it]);
marci@1110
   379
    }
marci@1110
   380
    /// \e
marci@1111
   381
    void setRowLowerBound(RowIt row_it, _Value lo) {
marci@1111
   382
      _setRowLowerBound(row_iter_map[row_it], lo);
marci@1081
   383
    }
marci@1031
   384
    /// \e
marci@1111
   385
    _Value getRowLowerBound(RowIt row_it) {
marci@1111
   386
      return _getRowLowerBound(row_iter_map[row_it]);
marci@1111
   387
    }
marci@1111
   388
    /// \e
marci@1111
   389
    void setRowUpperBound(RowIt row_it, _Value up) {
marci@1111
   390
      _setRowUpperBound(row_iter_map[row_it], up);
marci@1111
   391
    }
marci@1111
   392
    /// \e
marci@1111
   393
    _Value getRowUpperBound(RowIt row_it) {      
marci@1111
   394
      return _getRowUpperBound(row_iter_map[row_it]);
marci@1081
   395
    }
marci@1031
   396
    /// \e
marci@1081
   397
    void setObjCoef(const ColIt& col_it, _Value obj_coef) {
marci@1081
   398
      _setObjCoef(col_iter_map[col_it], obj_coef);
marci@1081
   399
    }
marci@1031
   400
    /// \e
marci@1081
   401
    _Value getObjCoef(const ColIt& col_it) {
marci@1081
   402
      return _getObjCoef(col_iter_map[col_it]);
marci@1081
   403
    }
marci@1081
   404
marci@1099
   405
    //MOST HIGH LEVEL, USER FRIEND FUNCTIONS
marci@1099
   406
marci@1099
   407
    /// \e
marci@1099
   408
    typedef Expr<ColIt, _Value> Expression;
marci@1099
   409
    /// \e
marci@1099
   410
    typedef Expr<RowIt, _Value> DualExpression;
marci@1099
   411
    /// \e
marci@1099
   412
    void setRowCoeffs(RowIt row_it, const Expression& expr) {
marci@1099
   413
      std::vector<std::pair<int, _Value> > row_coeffs;
marci@1099
   414
      for(typename Expression::Data::const_iterator i=expr.data.begin(); 
marci@1099
   415
	  i!=expr.data.end(); ++i) {
marci@1099
   416
	row_coeffs.push_back(std::make_pair
marci@1099
   417
			     (col_iter_map[(*i).first], (*i).second));
marci@1099
   418
      }
marci@1099
   419
      _setRowCoeffs(row_iter_map[row_it], row_coeffs);
marci@1099
   420
    }
marci@1099
   421
    /// \e
marci@1099
   422
    void setColCoeffs(ColIt col_it, const DualExpression& expr) {
marci@1099
   423
      std::vector<std::pair<int, _Value> > col_coeffs;
marci@1099
   424
      for(typename DualExpression::Data::const_iterator i=expr.data.begin(); 
marci@1099
   425
	  i!=expr.data.end(); ++i) {
marci@1099
   426
	col_coeffs.push_back(std::make_pair
marci@1099
   427
			     (row_iter_map[(*i).first], (*i).second));
marci@1099
   428
      }
marci@1099
   429
      _setColCoeffs(col_iter_map[col_it], col_coeffs);
marci@1099
   430
    }
marci@1099
   431
    /// \e
marci@1099
   432
    void setObjCoeffs(const Expression& expr) {
marci@1099
   433
      for(typename Expression::Data::const_iterator i=expr.data.begin(); 
marci@1099
   434
	  i!=expr.data.end(); ++i) {
marci@1099
   435
	setObjCoef((*i).first, (*i).second);
marci@1099
   436
      }
marci@1099
   437
    }
marci@1111
   438
marci@1081
   439
    //SOLVER FUNCTIONS
marci@1081
   440
marci@1031
   441
    /// \e
marci@1031
   442
    virtual void solveSimplex() = 0;
marci@1031
   443
    /// \e
marci@1031
   444
    virtual void solvePrimalSimplex() = 0;
marci@1031
   445
    /// \e
marci@1031
   446
    virtual void solveDualSimplex() = 0;
marci@1031
   447
    /// \e
marci@1081
   448
marci@1081
   449
    //HIGH LEVEL, SOLUTION RETRIEVING FUNCTIONS
marci@1081
   450
marci@1081
   451
  public:
marci@1111
   452
marci@1111
   453
    /// \e
marci@1081
   454
    _Value getPrimal(const ColIt& col_it) {
marci@1081
   455
      return _getPrimal(col_iter_map[col_it]);
marci@1081
   456
    }
marci@1031
   457
    /// \e
marci@1048
   458
    virtual _Value getObjVal() = 0;
marci@1081
   459
marci@1081
   460
    //OTHER FUNCTIONS
marci@1081
   461
marci@1031
   462
    /// \e
marci@1031
   463
    virtual int rowNum() const = 0;
marci@1031
   464
    /// \e
marci@1031
   465
    virtual int colNum() const = 0;
marci@1031
   466
    /// \e
marci@1031
   467
    virtual int warmUp() = 0;
marci@1031
   468
    /// \e
marci@1031
   469
    virtual void printWarmUpStatus(int i) = 0;
marci@1031
   470
    /// \e
marci@1031
   471
    virtual int getPrimalStatus() = 0;
marci@1031
   472
    /// \e
marci@1031
   473
    virtual void printPrimalStatus(int i) = 0;
marci@1031
   474
    /// \e
marci@1031
   475
    virtual int getDualStatus() = 0;
marci@1031
   476
    /// \e
marci@1031
   477
    virtual void printDualStatus(int i) = 0;
marci@1031
   478
    /// Returns the status of the slack variable assigned to row \c row_it.
marci@1031
   479
    virtual int getRowStat(const RowIt& row_it) = 0;
marci@1031
   480
    /// \e
marci@1031
   481
    virtual void printRowStatus(int i) = 0;
marci@1031
   482
    /// Returns the status of the variable assigned to column \c col_it.
marci@1031
   483
    virtual int getColStat(const ColIt& col_it) = 0;
marci@1031
   484
    /// \e
marci@1031
   485
    virtual void printColStatus(int i) = 0;
marci@1031
   486
  };
marci@1031
   487
  
marci@1104
   488
  template <typename _Value>
marci@1104
   489
  const _Value LPSolverBase<_Value>::INF=std::numeric_limits<_Value>::infinity();
marci@1104
   490
marci@1048
   491
marci@1111
   492
  /// \brief Wrapper for GLPK solver
marci@1031
   493
  /// 
marci@1111
   494
  /// This class implements a lemon wrapper for GLPK.
marci@1081
   495
  class LPGLPK : public LPSolverBase<double> {
marci@1031
   496
  public:
marci@1048
   497
    typedef LPSolverBase<double> Parent;
marci@1031
   498
marci@1031
   499
  public:
marci@1031
   500
    /// \e
marci@1031
   501
    LPX* lp;
marci@1031
   502
marci@1031
   503
  public:
marci@1031
   504
    /// \e
marci@1081
   505
    LPGLPK() : Parent(), 
marci@1031
   506
			lp(lpx_create_prob()) {
marci@1031
   507
      lpx_set_int_parm(lp, LPX_K_DUAL, 1);
marci@1031
   508
    }
marci@1031
   509
    /// \e
marci@1081
   510
    ~LPGLPK() {
marci@1031
   511
      lpx_delete_prob(lp);
marci@1031
   512
    }
marci@1081
   513
marci@1081
   514
    //MATRIX INDEPEDENT MANIPULATING FUNCTIONS
marci@1081
   515
marci@1031
   516
    /// \e
marci@1031
   517
    void setMinimize() { 
marci@1031
   518
      lpx_set_obj_dir(lp, LPX_MIN);
marci@1031
   519
    }
marci@1031
   520
    /// \e
marci@1031
   521
    void setMaximize() { 
marci@1031
   522
      lpx_set_obj_dir(lp, LPX_MAX);
marci@1031
   523
    }
marci@1081
   524
marci@1081
   525
    //LOW LEVEL INTERFACE, MATRIX MANIPULATING FUNCTIONS
marci@1081
   526
marci@1074
   527
  protected:
marci@1031
   528
    /// \e
marci@1074
   529
    int _addCol() { 
marci@1110
   530
      int i=lpx_add_cols(lp, 1);
marci@1110
   531
      _setColLowerBound(i, -INF);
marci@1110
   532
      _setColUpperBound(i, INF);
marci@1110
   533
      return i;
marci@1031
   534
    }
marci@1031
   535
    /// \e
marci@1074
   536
    int _addRow() { 
marci@1110
   537
      int i=lpx_add_rows(lp, 1);
marci@1110
   538
      return i;
marci@1074
   539
    }
marci@1074
   540
    /// \e
marci@1081
   541
    virtual void _setRowCoeffs(int i, 
marci@1104
   542
			       const std::vector<std::pair<int, double> >& coeffs) {
marci@1074
   543
      int mem_length=1+colNum();
marci@1074
   544
      int* indices = new int[mem_length];
marci@1074
   545
      double* doubles = new double[mem_length];
marci@1074
   546
      int length=0;
marci@1074
   547
      for (std::vector<std::pair<int, double> >::
marci@1074
   548
	     const_iterator it=coeffs.begin(); it!=coeffs.end(); ++it) {
marci@1074
   549
	++length;
marci@1074
   550
	indices[length]=it->first;
marci@1074
   551
	doubles[length]=it->second;
marci@1081
   552
// 	std::cout << "  " << indices[length] << " " 
marci@1081
   553
// 		  << doubles[length] << std::endl;
marci@1031
   554
      }
marci@1081
   555
//      std::cout << i << " " << length << std::endl;
marci@1074
   556
      lpx_set_mat_row(lp, i, length, indices, doubles);
marci@1074
   557
      delete [] indices;
marci@1074
   558
      delete [] doubles;
marci@1031
   559
    }
marci@1074
   560
    /// \e
marci@1081
   561
    virtual void _setColCoeffs(int i, 
marci@1104
   562
			       const std::vector<std::pair<int, double> >& coeffs) {
marci@1074
   563
      int mem_length=1+rowNum();
marci@1074
   564
      int* indices = new int[mem_length];
marci@1074
   565
      double* doubles = new double[mem_length];
marci@1074
   566
      int length=0;
marci@1074
   567
      for (std::vector<std::pair<int, double> >::
marci@1074
   568
	     const_iterator it=coeffs.begin(); it!=coeffs.end(); ++it) {
marci@1074
   569
	++length;
marci@1074
   570
	indices[length]=it->first;
marci@1074
   571
	doubles[length]=it->second;
marci@1074
   572
      }
marci@1074
   573
      lpx_set_mat_col(lp, i, length, indices, doubles);
marci@1074
   574
      delete [] indices;
marci@1074
   575
      delete [] doubles;
marci@1031
   576
    }
marci@1031
   577
    /// \e
marci@1074
   578
    virtual void _eraseCol(int i) {
marci@1031
   579
      int cols[2];
marci@1074
   580
      cols[1]=i;
marci@1031
   581
      lpx_del_cols(lp, 1, cols);
marci@1031
   582
    }
marci@1074
   583
    virtual void _eraseRow(int i) {
marci@1031
   584
      int rows[2];
marci@1074
   585
      rows[1]=i;
marci@1031
   586
      lpx_del_rows(lp, 1, rows);
marci@1031
   587
    }
marci@1110
   588
    virtual void _setColLowerBound(int i, double lo) {
marci@1110
   589
      if (lo==INF) {
marci@1110
   590
	//FIXME error
marci@1110
   591
      }
marci@1110
   592
      int b=lpx_get_col_type(lp, i);
marci@1110
   593
      double up=lpx_get_col_ub(lp, i);	
marci@1110
   594
      if (lo==-INF) {
marci@1110
   595
	switch (b) {
marci@1110
   596
	case LPX_FR:
marci@1110
   597
	case LPX_LO:
marci@1110
   598
	  lpx_set_col_bnds(lp, i, LPX_FR, lo, up);
marci@1110
   599
	  break;
marci@1110
   600
	case LPX_UP:
marci@1110
   601
	  break;
marci@1110
   602
	case LPX_DB:
marci@1110
   603
	case LPX_FX:
marci@1110
   604
	  lpx_set_col_bnds(lp, i, LPX_UP, lo, up);
marci@1110
   605
	  break;
marci@1110
   606
	default: ;
marci@1110
   607
	  //FIXME error
marci@1110
   608
	}
marci@1110
   609
      } else {
marci@1110
   610
	switch (b) {
marci@1110
   611
	case LPX_FR:
marci@1110
   612
	case LPX_LO:
marci@1110
   613
	  lpx_set_col_bnds(lp, i, LPX_LO, lo, up);
marci@1110
   614
	  break;
marci@1110
   615
	case LPX_UP:	  
marci@1110
   616
	case LPX_DB:
marci@1110
   617
	case LPX_FX:
marci@1110
   618
	  if (lo==up) 
marci@1110
   619
	    lpx_set_col_bnds(lp, i, LPX_FX, lo, up);
marci@1110
   620
	  else 
marci@1110
   621
	    lpx_set_col_bnds(lp, i, LPX_DB, lo, up);
marci@1110
   622
	  break;
marci@1110
   623
	default: ;
marci@1110
   624
	  //FIXME error
marci@1110
   625
	}
marci@1110
   626
      }
marci@1110
   627
    }
marci@1111
   628
    virtual double _getColLowerBound(int i) {
marci@1111
   629
      int b=lpx_get_col_type(lp, i);
marci@1111
   630
      switch (b) {
marci@1111
   631
      case LPX_FR:
marci@1111
   632
	return -INF;
marci@1111
   633
      case LPX_LO:
marci@1111
   634
	return lpx_get_col_lb(lp, i);
marci@1111
   635
      case LPX_UP:
marci@1111
   636
	return -INF;
marci@1111
   637
      case LPX_DB:
marci@1111
   638
      case LPX_FX:
marci@1111
   639
	return lpx_get_col_lb(lp, i);
marci@1111
   640
      default: ;
marci@1111
   641
	//FIXME error
marci@1111
   642
	return 0.0;
marci@1111
   643
      }
marci@1111
   644
    }
marci@1110
   645
    virtual void _setColUpperBound(int i, double up) {
marci@1110
   646
      if (up==-INF) {
marci@1110
   647
	//FIXME error
marci@1110
   648
      }
marci@1110
   649
      int b=lpx_get_col_type(lp, i);
marci@1110
   650
      double lo=lpx_get_col_lb(lp, i);
marci@1110
   651
      if (up==INF) {
marci@1110
   652
	switch (b) {
marci@1110
   653
	case LPX_FR:
marci@1110
   654
	case LPX_LO:
marci@1110
   655
	  break;
marci@1110
   656
	case LPX_UP:
marci@1110
   657
	  lpx_set_col_bnds(lp, i, LPX_FR, lo, up);
marci@1110
   658
	  break;
marci@1110
   659
	case LPX_DB:
marci@1110
   660
	case LPX_FX:
marci@1110
   661
	  lpx_set_col_bnds(lp, i, LPX_LO, lo, up);
marci@1110
   662
	  break;
marci@1110
   663
	default: ;
marci@1110
   664
	  //FIXME error
marci@1110
   665
	}
marci@1110
   666
      } else {
marci@1110
   667
	switch (b) {
marci@1110
   668
	case LPX_FR:
marci@1110
   669
	  lpx_set_col_bnds(lp, i, LPX_UP, lo, up);
marci@1110
   670
	case LPX_LO:
marci@1110
   671
	  if (lo==up) 
marci@1110
   672
	    lpx_set_col_bnds(lp, i, LPX_FX, lo, up);
marci@1110
   673
	  else
marci@1110
   674
	    lpx_set_col_bnds(lp, i, LPX_DB, lo, up);
marci@1110
   675
	  break;
marci@1110
   676
	case LPX_UP:
marci@1110
   677
	  lpx_set_col_bnds(lp, i, LPX_UP, lo, up);
marci@1110
   678
	  break;
marci@1110
   679
	case LPX_DB:
marci@1110
   680
	case LPX_FX:
marci@1110
   681
	  if (lo==up) 
marci@1110
   682
	    lpx_set_col_bnds(lp, i, LPX_FX, lo, up);
marci@1110
   683
	  else 
marci@1110
   684
	    lpx_set_col_bnds(lp, i, LPX_DB, lo, up);
marci@1110
   685
	  break;
marci@1110
   686
	default: ;
marci@1110
   687
	  //FIXME error
marci@1110
   688
	}
marci@1110
   689
      }
marci@1110
   690
    }
marci@1110
   691
    virtual double _getColUpperBound(int i) {
marci@1110
   692
      int b=lpx_get_col_type(lp, i);
marci@1110
   693
      switch (b) {
marci@1110
   694
      case LPX_FR:
marci@1110
   695
      case LPX_LO:
marci@1110
   696
	return INF;
marci@1110
   697
      case LPX_UP:
marci@1110
   698
      case LPX_DB:
marci@1110
   699
      case LPX_FX:
marci@1110
   700
	return lpx_get_col_ub(lp, i);
marci@1110
   701
      default: ;
marci@1110
   702
	//FIXME error
marci@1110
   703
	return 0.0;
marci@1110
   704
      }
marci@1110
   705
    }
marci@1111
   706
    virtual void _setRowLowerBound(int i, double lo) {
marci@1111
   707
      if (lo==INF) {
marci@1111
   708
	//FIXME error
marci@1081
   709
      }
marci@1111
   710
      int b=lpx_get_row_type(lp, i);
marci@1111
   711
      double up=lpx_get_row_ub(lp, i);	
marci@1111
   712
      if (lo==-INF) {
marci@1111
   713
	switch (b) {
marci@1111
   714
	case LPX_FR:
marci@1111
   715
	case LPX_LO:
marci@1111
   716
	  lpx_set_row_bnds(lp, i, LPX_FR, lo, up);
marci@1111
   717
	  break;
marci@1111
   718
	case LPX_UP:
marci@1111
   719
	  break;
marci@1111
   720
	case LPX_DB:
marci@1111
   721
	case LPX_FX:
marci@1111
   722
	  lpx_set_row_bnds(lp, i, LPX_UP, lo, up);
marci@1111
   723
	  break;
marci@1111
   724
	default: ;
marci@1111
   725
	  //FIXME error
marci@1111
   726
	}
marci@1111
   727
      } else {
marci@1111
   728
	switch (b) {
marci@1111
   729
	case LPX_FR:
marci@1111
   730
	case LPX_LO:
marci@1111
   731
	  lpx_set_row_bnds(lp, i, LPX_LO, lo, up);
marci@1111
   732
	  break;
marci@1111
   733
	case LPX_UP:	  
marci@1111
   734
	case LPX_DB:
marci@1111
   735
	case LPX_FX:
marci@1111
   736
	  if (lo==up) 
marci@1111
   737
	    lpx_set_row_bnds(lp, i, LPX_FX, lo, up);
marci@1111
   738
	  else 
marci@1111
   739
	    lpx_set_row_bnds(lp, i, LPX_DB, lo, up);
marci@1111
   740
	  break;
marci@1111
   741
	default: ;
marci@1111
   742
	  //FIXME error
marci@1111
   743
	}
marci@1081
   744
      }
marci@1111
   745
    }
marci@1111
   746
    virtual double _getRowLowerBound(int i) {
marci@1111
   747
      int b=lpx_get_row_type(lp, i);
marci@1111
   748
      switch (b) {
marci@1111
   749
      case LPX_FR:
marci@1111
   750
	return -INF;
marci@1111
   751
      case LPX_LO:
marci@1111
   752
	return lpx_get_row_lb(lp, i);
marci@1111
   753
      case LPX_UP:
marci@1111
   754
	return -INF;
marci@1111
   755
      case LPX_DB:
marci@1111
   756
      case LPX_FX:
marci@1111
   757
	return lpx_get_row_lb(lp, i);
marci@1111
   758
      default: ;
marci@1111
   759
	//FIXME error
marci@1111
   760
	return 0.0;
marci@1111
   761
      }
marci@1111
   762
    }
marci@1111
   763
    virtual void _setRowUpperBound(int i, double up) {
marci@1111
   764
      if (up==-INF) {
marci@1111
   765
	//FIXME error
marci@1111
   766
      }
marci@1111
   767
      int b=lpx_get_row_type(lp, i);
marci@1111
   768
      double lo=lpx_get_row_lb(lp, i);
marci@1111
   769
      if (up==INF) {
marci@1111
   770
	switch (b) {
marci@1111
   771
	case LPX_FR:
marci@1111
   772
	case LPX_LO:
marci@1111
   773
	  break;
marci@1111
   774
	case LPX_UP:
marci@1111
   775
	  lpx_set_row_bnds(lp, i, LPX_FR, lo, up);
marci@1111
   776
	  break;
marci@1111
   777
	case LPX_DB:
marci@1111
   778
	case LPX_FX:
marci@1111
   779
	  lpx_set_row_bnds(lp, i, LPX_LO, lo, up);
marci@1111
   780
	  break;
marci@1111
   781
	default: ;
marci@1111
   782
	  //FIXME error
marci@1111
   783
	}
marci@1111
   784
      } else {
marci@1111
   785
	switch (b) {
marci@1111
   786
	case LPX_FR:
marci@1111
   787
	  lpx_set_row_bnds(lp, i, LPX_UP, lo, up);
marci@1111
   788
	case LPX_LO:
marci@1111
   789
	  if (lo==up) 
marci@1111
   790
	    lpx_set_row_bnds(lp, i, LPX_FX, lo, up);
marci@1111
   791
	  else
marci@1111
   792
	    lpx_set_row_bnds(lp, i, LPX_DB, lo, up);
marci@1111
   793
	  break;
marci@1111
   794
	case LPX_UP:
marci@1111
   795
	  lpx_set_row_bnds(lp, i, LPX_UP, lo, up);
marci@1111
   796
	  break;
marci@1111
   797
	case LPX_DB:
marci@1111
   798
	case LPX_FX:
marci@1111
   799
	  if (lo==up) 
marci@1111
   800
	    lpx_set_row_bnds(lp, i, LPX_FX, lo, up);
marci@1111
   801
	  else 
marci@1111
   802
	    lpx_set_row_bnds(lp, i, LPX_DB, lo, up);
marci@1111
   803
	  break;
marci@1111
   804
	default: ;
marci@1111
   805
	  //FIXME error
marci@1111
   806
	}
marci@1111
   807
      }
marci@1111
   808
    }
marci@1111
   809
    virtual double _getRowUpperBound(int i) {
marci@1111
   810
      int b=lpx_get_row_type(lp, i);
marci@1111
   811
      switch (b) {
marci@1111
   812
      case LPX_FR:
marci@1111
   813
      case LPX_LO:
marci@1111
   814
	return INF;
marci@1111
   815
      case LPX_UP:
marci@1111
   816
      case LPX_DB:
marci@1111
   817
      case LPX_FX:
marci@1111
   818
	return lpx_get_row_ub(lp, i);
marci@1111
   819
      default: ;
marci@1111
   820
	//FIXME error
marci@1111
   821
	return 0.0;
marci@1111
   822
      }
marci@1111
   823
    }
marci@1031
   824
    /// \e
marci@1081
   825
    virtual double _getObjCoef(int i) { 
marci@1081
   826
      return lpx_get_obj_coef(lp, i);
marci@1031
   827
    }
marci@1031
   828
    /// \e
marci@1081
   829
    virtual void _setObjCoef(int i, double obj_coef) { 
marci@1081
   830
      lpx_set_obj_coef(lp, i, obj_coef);
marci@1031
   831
    }
marci@1081
   832
  public:
marci@1031
   833
    /// \e
marci@1031
   834
    void solveSimplex() { lpx_simplex(lp); }
marci@1031
   835
    /// \e
marci@1031
   836
    void solvePrimalSimplex() { lpx_simplex(lp); }
marci@1031
   837
    /// \e
marci@1031
   838
    void solveDualSimplex() { lpx_simplex(lp); }
marci@1031
   839
    /// \e
marci@1081
   840
  protected:
marci@1081
   841
    virtual double _getPrimal(int i) {
marci@1081
   842
      return lpx_get_col_prim(lp, i);
marci@1031
   843
    }
marci@1081
   844
  public:
marci@1031
   845
    /// \e
marci@1031
   846
    double getObjVal() { return lpx_get_obj_val(lp); }
marci@1031
   847
    /// \e
marci@1031
   848
    int rowNum() const { return lpx_get_num_rows(lp); }
marci@1031
   849
    /// \e
marci@1031
   850
    int colNum() const { return lpx_get_num_cols(lp); }
marci@1031
   851
    /// \e
marci@1031
   852
    int warmUp() { return lpx_warm_up(lp); }
marci@1031
   853
    /// \e
marci@1031
   854
    void printWarmUpStatus(int i) {
marci@1031
   855
      switch (i) {
marci@1031
   856
      case LPX_E_OK: cout << "LPX_E_OK" << endl; break;
marci@1031
   857
      case LPX_E_EMPTY: cout << "LPX_E_EMPTY" << endl; break;	
marci@1031
   858
      case LPX_E_BADB: cout << "LPX_E_BADB" << endl; break;
marci@1031
   859
      case LPX_E_SING: cout << "LPX_E_SING" << endl; break;
marci@1031
   860
      }
marci@1031
   861
    }
marci@1031
   862
    /// \e
marci@1031
   863
    int getPrimalStatus() { return lpx_get_prim_stat(lp); }
marci@1031
   864
    /// \e
marci@1031
   865
    void printPrimalStatus(int i) {
marci@1031
   866
      switch (i) {
marci@1031
   867
      case LPX_P_UNDEF: cout << "LPX_P_UNDEF" << endl; break;
marci@1031
   868
      case LPX_P_FEAS: cout << "LPX_P_FEAS" << endl; break;	
marci@1031
   869
      case LPX_P_INFEAS: cout << "LPX_P_INFEAS" << endl; break;
marci@1031
   870
      case LPX_P_NOFEAS: cout << "LPX_P_NOFEAS" << endl; break;
marci@1031
   871
      }
marci@1031
   872
    }
marci@1031
   873
    /// \e
marci@1031
   874
    int getDualStatus() { return lpx_get_dual_stat(lp); }
marci@1031
   875
    /// \e
marci@1031
   876
    void printDualStatus(int i) {
marci@1031
   877
      switch (i) {
marci@1031
   878
      case LPX_D_UNDEF: cout << "LPX_D_UNDEF" << endl; break;
marci@1031
   879
      case LPX_D_FEAS: cout << "LPX_D_FEAS" << endl; break;	
marci@1031
   880
      case LPX_D_INFEAS: cout << "LPX_D_INFEAS" << endl; break;
marci@1031
   881
      case LPX_D_NOFEAS: cout << "LPX_D_NOFEAS" << endl; break;
marci@1031
   882
      }
marci@1031
   883
    }
marci@1031
   884
    /// Returns the status of the slack variable assigned to row \c row_it.
marci@1031
   885
    int getRowStat(const RowIt& row_it) { 
marci@1031
   886
      return lpx_get_row_stat(lp, row_iter_map[row_it]); 
marci@1031
   887
    }
marci@1031
   888
    /// \e
marci@1031
   889
    void printRowStatus(int i) {
marci@1031
   890
      switch (i) {
marci@1031
   891
      case LPX_BS: cout << "LPX_BS" << endl; break;
marci@1031
   892
      case LPX_NL: cout << "LPX_NL" << endl; break;	
marci@1031
   893
      case LPX_NU: cout << "LPX_NU" << endl; break;
marci@1031
   894
      case LPX_NF: cout << "LPX_NF" << endl; break;
marci@1031
   895
      case LPX_NS: cout << "LPX_NS" << endl; break;
marci@1031
   896
      }
marci@1031
   897
    }
marci@1031
   898
    /// Returns the status of the variable assigned to column \c col_it.
marci@1031
   899
    int getColStat(const ColIt& col_it) { 
marci@1031
   900
      return lpx_get_col_stat(lp, col_iter_map[col_it]); 
marci@1031
   901
    }
marci@1031
   902
    /// \e
marci@1031
   903
    void printColStatus(int i) {
marci@1031
   904
      switch (i) {
marci@1031
   905
      case LPX_BS: cout << "LPX_BS" << endl; break;
marci@1031
   906
      case LPX_NL: cout << "LPX_NL" << endl; break;	
marci@1031
   907
      case LPX_NU: cout << "LPX_NU" << endl; break;
marci@1031
   908
      case LPX_NF: cout << "LPX_NF" << endl; break;
marci@1031
   909
      case LPX_NS: cout << "LPX_NS" << endl; break;
marci@1031
   910
      }
marci@1031
   911
    }
marci@1031
   912
  };
marci@1031
   913
  
marci@1031
   914
  /// @}
marci@1031
   915
marci@1031
   916
} //namespace lemon
marci@1031
   917
marci@1031
   918
#endif //LEMON_LP_SOLVER_WRAPPER_H