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