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