gravatar
alpar (Alpar Juttner)
alpar@cs.elte.hu
Remove lp_ prefix from the solver's header name
8 4 8
default
20 files changed with 3609 insertions and 3609 deletions:
↑ Collapse diff ↑
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#include <lemon/clp.h>
20
#include <coin/ClpSimplex.hpp>
21

	
22
namespace lemon {
23

	
24
  LpClp::LpClp() {
25
    _prob = new ClpSimplex();
26
    _init_temporals();
27
    messageLevel(MESSAGE_NO_OUTPUT);
28
  }
29

	
30
  LpClp::LpClp(const LpClp& other) {
31
    _prob = new ClpSimplex(*other._prob);
32
    rows = other.rows;
33
    cols = other.cols;
34
    _init_temporals();
35
    messageLevel(MESSAGE_NO_OUTPUT);
36
  }
37

	
38
  LpClp::~LpClp() {
39
    delete _prob;
40
    _clear_temporals();
41
  }
42

	
43
  void LpClp::_init_temporals() {
44
    _primal_ray = 0;
45
    _dual_ray = 0;
46
  }
47

	
48
  void LpClp::_clear_temporals() {
49
    if (_primal_ray) {
50
      delete[] _primal_ray;
51
      _primal_ray = 0;
52
    }
53
    if (_dual_ray) {
54
      delete[] _dual_ray;
55
      _dual_ray = 0;
56
    }
57
  }
58

	
59
  LpClp* LpClp::_newSolver() const {
60
    LpClp* newlp = new LpClp;
61
    return newlp;
62
  }
63

	
64
  LpClp* LpClp::_cloneSolver() const {
65
    LpClp* copylp = new LpClp(*this);
66
    return copylp;
67
  }
68

	
69
  const char* LpClp::_solverName() const { return "LpClp"; }
70

	
71
  int LpClp::_addCol() {
72
    _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0);
73
    return _prob->numberColumns() - 1;
74
  }
75

	
76
  int LpClp::_addRow() {
77
    _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX);
78
    return _prob->numberRows() - 1;
79
  }
80

	
81

	
82
  void LpClp::_eraseCol(int c) {
83
    _col_names_ref.erase(_prob->getColumnName(c));
84
    _prob->deleteColumns(1, &c);
85
  }
86

	
87
  void LpClp::_eraseRow(int r) {
88
    _row_names_ref.erase(_prob->getRowName(r));
89
    _prob->deleteRows(1, &r);
90
  }
91

	
92
  void LpClp::_eraseColId(int i) {
93
    cols.eraseIndex(i);
94
    cols.shiftIndices(i);
95
  }
96

	
97
  void LpClp::_eraseRowId(int i) {
98
    rows.eraseIndex(i);
99
    rows.shiftIndices(i);
100
  }
101

	
102
  void LpClp::_getColName(int c, std::string& name) const {
103
    name = _prob->getColumnName(c);
104
  }
105

	
106
  void LpClp::_setColName(int c, const std::string& name) {
107
    _prob->setColumnName(c, const_cast<std::string&>(name));
108
    _col_names_ref[name] = c;
109
  }
110

	
111
  int LpClp::_colByName(const std::string& name) const {
112
    std::map<std::string, int>::const_iterator it = _col_names_ref.find(name);
113
    return it != _col_names_ref.end() ? it->second : -1;
114
  }
115

	
116
  void LpClp::_getRowName(int r, std::string& name) const {
117
    name = _prob->getRowName(r);
118
  }
119

	
120
  void LpClp::_setRowName(int r, const std::string& name) {
121
    _prob->setRowName(r, const_cast<std::string&>(name));
122
    _row_names_ref[name] = r;
123
  }
124

	
125
  int LpClp::_rowByName(const std::string& name) const {
126
    std::map<std::string, int>::const_iterator it = _row_names_ref.find(name);
127
    return it != _row_names_ref.end() ? it->second : -1;
128
  }
129

	
130

	
131
  void LpClp::_setRowCoeffs(int ix, ExprIterator b, ExprIterator e) {
132
    std::map<int, Value> coeffs;
133

	
134
    int n = _prob->clpMatrix()->getNumCols();
135

	
136
    const int* indices = _prob->clpMatrix()->getIndices();
137
    const double* elements = _prob->clpMatrix()->getElements();
138

	
139
    for (int i = 0; i < n; ++i) {
140
      CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i];
141
      CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i];
142

	
143
      const int* it = std::lower_bound(indices + begin, indices + end, ix);
144
      if (it != indices + end && *it == ix && elements[it - indices] != 0.0) {
145
        coeffs[i] = 0.0;
146
      }
147
    }
148

	
149
    for (ExprIterator it = b; it != e; ++it) {
150
      coeffs[it->first] = it->second;
151
    }
152

	
153
    for (std::map<int, Value>::iterator it = coeffs.begin();
154
         it != coeffs.end(); ++it) {
155
      _prob->modifyCoefficient(ix, it->first, it->second);
156
    }
157
  }
158

	
159
  void LpClp::_getRowCoeffs(int ix, InsertIterator b) const {
160
    int n = _prob->clpMatrix()->getNumCols();
161

	
162
    const int* indices = _prob->clpMatrix()->getIndices();
163
    const double* elements = _prob->clpMatrix()->getElements();
164

	
165
    for (int i = 0; i < n; ++i) {
166
      CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i];
167
      CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i];
168

	
169
      const int* it = std::lower_bound(indices + begin, indices + end, ix);
170
      if (it != indices + end && *it == ix) {
171
        *b = std::make_pair(i, elements[it - indices]);
172
      }
173
    }
174
  }
175

	
176
  void LpClp::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) {
177
    std::map<int, Value> coeffs;
178

	
179
    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
180
    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
181

	
182
    const int* indices = _prob->clpMatrix()->getIndices();
183
    const double* elements = _prob->clpMatrix()->getElements();
184

	
185
    for (CoinBigIndex i = begin; i != end; ++i) {
186
      if (elements[i] != 0.0) {
187
        coeffs[indices[i]] = 0.0;
188
      }
189
    }
190
    for (ExprIterator it = b; it != e; ++it) {
191
      coeffs[it->first] = it->second;
192
    }
193
    for (std::map<int, Value>::iterator it = coeffs.begin();
194
         it != coeffs.end(); ++it) {
195
      _prob->modifyCoefficient(it->first, ix, it->second);
196
    }
197
  }
198

	
199
  void LpClp::_getColCoeffs(int ix, InsertIterator b) const {
200
    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
201
    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
202

	
203
    const int* indices = _prob->clpMatrix()->getIndices();
204
    const double* elements = _prob->clpMatrix()->getElements();
205

	
206
    for (CoinBigIndex i = begin; i != end; ++i) {
207
      *b = std::make_pair(indices[i], elements[i]);
208
      ++b;
209
    }
210
  }
211

	
212
  void LpClp::_setCoeff(int ix, int jx, Value value) {
213
    _prob->modifyCoefficient(ix, jx, value);
214
  }
215

	
216
  LpClp::Value LpClp::_getCoeff(int ix, int jx) const {
217
    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
218
    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
219

	
220
    const int* indices = _prob->clpMatrix()->getIndices();
221
    const double* elements = _prob->clpMatrix()->getElements();
222

	
223
    const int* it = std::lower_bound(indices + begin, indices + end, jx);
224
    if (it != indices + end && *it == jx) {
225
      return elements[it - indices];
226
    } else {
227
      return 0.0;
228
    }
229
  }
230

	
231
  void LpClp::_setColLowerBound(int i, Value lo) {
232
    _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
233
  }
234

	
235
  LpClp::Value LpClp::_getColLowerBound(int i) const {
236
    double val = _prob->getColLower()[i];
237
    return val == - COIN_DBL_MAX ? - INF : val;
238
  }
239

	
240
  void LpClp::_setColUpperBound(int i, Value up) {
241
    _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up);
242
  }
243

	
244
  LpClp::Value LpClp::_getColUpperBound(int i) const {
245
    double val = _prob->getColUpper()[i];
246
    return val == COIN_DBL_MAX ? INF : val;
247
  }
248

	
249
  void LpClp::_setRowLowerBound(int i, Value lo) {
250
    _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
251
  }
252

	
253
  LpClp::Value LpClp::_getRowLowerBound(int i) const {
254
    double val = _prob->getRowLower()[i];
255
    return val == - COIN_DBL_MAX ? - INF : val;
256
  }
257

	
258
  void LpClp::_setRowUpperBound(int i, Value up) {
259
    _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up);
260
  }
261

	
262
  LpClp::Value LpClp::_getRowUpperBound(int i) const {
263
    double val = _prob->getRowUpper()[i];
264
    return val == COIN_DBL_MAX ? INF : val;
265
  }
266

	
267
  void LpClp::_setObjCoeffs(ExprIterator b, ExprIterator e) {
268
    int num = _prob->clpMatrix()->getNumCols();
269
    for (int i = 0; i < num; ++i) {
270
      _prob->setObjectiveCoefficient(i, 0.0);
271
    }
272
    for (ExprIterator it = b; it != e; ++it) {
273
      _prob->setObjectiveCoefficient(it->first, it->second);
274
    }
275
  }
276

	
277
  void LpClp::_getObjCoeffs(InsertIterator b) const {
278
    int num = _prob->clpMatrix()->getNumCols();
279
    for (int i = 0; i < num; ++i) {
280
      Value coef = _prob->getObjCoefficients()[i];
281
      if (coef != 0.0) {
282
        *b = std::make_pair(i, coef);
283
        ++b;
284
      }
285
    }
286
  }
287

	
288
  void LpClp::_setObjCoeff(int i, Value obj_coef) {
289
    _prob->setObjectiveCoefficient(i, obj_coef);
290
  }
291

	
292
  LpClp::Value LpClp::_getObjCoeff(int i) const {
293
    return _prob->getObjCoefficients()[i];
294
  }
295

	
296
  LpClp::SolveExitStatus LpClp::_solve() {
297
    return _prob->primal() >= 0 ? SOLVED : UNSOLVED;
298
  }
299

	
300
  LpClp::SolveExitStatus LpClp::solvePrimal() {
301
    return _prob->primal() >= 0 ? SOLVED : UNSOLVED;
302
  }
303

	
304
  LpClp::SolveExitStatus LpClp::solveDual() {
305
    return _prob->dual() >= 0 ? SOLVED : UNSOLVED;
306
  }
307

	
308
  LpClp::SolveExitStatus LpClp::solveBarrier() {
309
    return _prob->barrier() >= 0 ? SOLVED : UNSOLVED;
310
  }
311

	
312
  LpClp::Value LpClp::_getPrimal(int i) const {
313
    return _prob->primalColumnSolution()[i];
314
  }
315
  LpClp::Value LpClp::_getPrimalValue() const {
316
    return _prob->objectiveValue();
317
  }
318

	
319
  LpClp::Value LpClp::_getDual(int i) const {
320
    return _prob->dualRowSolution()[i];
321
  }
322

	
323
  LpClp::Value LpClp::_getPrimalRay(int i) const {
324
    if (!_primal_ray) {
325
      _primal_ray = _prob->unboundedRay();
326
      LEMON_ASSERT(_primal_ray != 0, "Primal ray is not provided");
327
    }
328
    return _primal_ray[i];
329
  }
330

	
331
  LpClp::Value LpClp::_getDualRay(int i) const {
332
    if (!_dual_ray) {
333
      _dual_ray = _prob->infeasibilityRay();
334
      LEMON_ASSERT(_dual_ray != 0, "Dual ray is not provided");
335
    }
336
    return _dual_ray[i];
337
  }
338

	
339
  LpClp::VarStatus LpClp::_getColStatus(int i) const {
340
    switch (_prob->getColumnStatus(i)) {
341
    case ClpSimplex::basic:
342
      return BASIC;
343
    case ClpSimplex::isFree:
344
      return FREE;
345
    case ClpSimplex::atUpperBound:
346
      return UPPER;
347
    case ClpSimplex::atLowerBound:
348
      return LOWER;
349
    case ClpSimplex::isFixed:
350
      return FIXED;
351
    case ClpSimplex::superBasic:
352
      return FREE;
353
    default:
354
      LEMON_ASSERT(false, "Wrong column status");
355
      return VarStatus();
356
    }
357
  }
358

	
359
  LpClp::VarStatus LpClp::_getRowStatus(int i) const {
360
    switch (_prob->getColumnStatus(i)) {
361
    case ClpSimplex::basic:
362
      return BASIC;
363
    case ClpSimplex::isFree:
364
      return FREE;
365
    case ClpSimplex::atUpperBound:
366
      return UPPER;
367
    case ClpSimplex::atLowerBound:
368
      return LOWER;
369
    case ClpSimplex::isFixed:
370
      return FIXED;
371
    case ClpSimplex::superBasic:
372
      return FREE;
373
    default:
374
      LEMON_ASSERT(false, "Wrong row status");
375
      return VarStatus();
376
    }
377
  }
378

	
379

	
380
  LpClp::ProblemType LpClp::_getPrimalType() const {
381
    if (_prob->isProvenOptimal()) {
382
      return OPTIMAL;
383
    } else if (_prob->isProvenPrimalInfeasible()) {
384
      return INFEASIBLE;
385
    } else if (_prob->isProvenDualInfeasible()) {
386
      return UNBOUNDED;
387
    } else {
388
      return UNDEFINED;
389
    }
390
  }
391

	
392
  LpClp::ProblemType LpClp::_getDualType() const {
393
    if (_prob->isProvenOptimal()) {
394
      return OPTIMAL;
395
    } else if (_prob->isProvenDualInfeasible()) {
396
      return INFEASIBLE;
397
    } else if (_prob->isProvenPrimalInfeasible()) {
398
      return INFEASIBLE;
399
    } else {
400
      return UNDEFINED;
401
    }
402
  }
403

	
404
  void LpClp::_setSense(LpClp::Sense sense) {
405
    switch (sense) {
406
    case MIN:
407
      _prob->setOptimizationDirection(1);
408
      break;
409
    case MAX:
410
      _prob->setOptimizationDirection(-1);
411
      break;
412
    }
413
  }
414

	
415
  LpClp::Sense LpClp::_getSense() const {
416
    double dir = _prob->optimizationDirection();
417
    if (dir > 0.0) {
418
      return MIN;
419
    } else {
420
      return MAX;
421
    }
422
  }
423

	
424
  void LpClp::_clear() {
425
    delete _prob;
426
    _prob = new ClpSimplex();
427
    rows.clear();
428
    cols.clear();
429
    _col_names_ref.clear();
430
    _clear_temporals();
431
  }
432

	
433
  void LpClp::messageLevel(MessageLevel m) {
434
    _prob->setLogLevel(static_cast<int>(m));
435
  }
436

	
437
} //END OF NAMESPACE LEMON
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#ifndef LEMON_CLP_H
20
#define LEMON_CLP_H
21

	
22
///\file
23
///\brief Header of the LEMON-CLP lp solver interface.
24

	
25
#include <vector>
26
#include <string>
27

	
28
#include <lemon/lp_base.h>
29

	
30
class ClpSimplex;
31

	
32
namespace lemon {
33

	
34
  /// \ingroup lp_group
35
  ///
36
  /// \brief Interface for the CLP solver
37
  ///
38
  /// This class implements an interface for the Clp LP solver.  The
39
  /// Clp library is an object oriented lp solver library developed at
40
  /// the IBM. The CLP is part of the COIN-OR package and it can be
41
  /// used with Common Public License.
42
  class LpClp : public LpSolver {
43
  protected:
44

	
45
    ClpSimplex* _prob;
46

	
47
    std::map<std::string, int> _col_names_ref;
48
    std::map<std::string, int> _row_names_ref;
49

	
50
  public:
51

	
52
    /// \e
53
    LpClp();
54
    /// \e
55
    LpClp(const LpClp&);
56
    /// \e
57
    ~LpClp();
58

	
59
  protected:
60

	
61
    mutable double* _primal_ray;
62
    mutable double* _dual_ray;
63

	
64
    void _init_temporals();
65
    void _clear_temporals();
66

	
67
  protected:
68

	
69
    virtual LpClp* _newSolver() const;
70
    virtual LpClp* _cloneSolver() const;
71

	
72
    virtual const char* _solverName() const;
73

	
74
    virtual int _addCol();
75
    virtual int _addRow();
76

	
77
    virtual void _eraseCol(int i);
78
    virtual void _eraseRow(int i);
79

	
80
    virtual void _eraseColId(int i);
81
    virtual void _eraseRowId(int i);
82

	
83
    virtual void _getColName(int col, std::string& name) const;
84
    virtual void _setColName(int col, const std::string& name);
85
    virtual int _colByName(const std::string& name) const;
86

	
87
    virtual void _getRowName(int row, std::string& name) const;
88
    virtual void _setRowName(int row, const std::string& name);
89
    virtual int _rowByName(const std::string& name) const;
90

	
91
    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
92
    virtual void _getRowCoeffs(int i, InsertIterator b) const;
93

	
94
    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
95
    virtual void _getColCoeffs(int i, InsertIterator b) const;
96

	
97
    virtual void _setCoeff(int row, int col, Value value);
98
    virtual Value _getCoeff(int row, int col) const;
99

	
100
    virtual void _setColLowerBound(int i, Value value);
101
    virtual Value _getColLowerBound(int i) const;
102
    virtual void _setColUpperBound(int i, Value value);
103
    virtual Value _getColUpperBound(int i) const;
104

	
105
    virtual void _setRowLowerBound(int i, Value value);
106
    virtual Value _getRowLowerBound(int i) const;
107
    virtual void _setRowUpperBound(int i, Value value);
108
    virtual Value _getRowUpperBound(int i) const;
109

	
110
    virtual void _setObjCoeffs(ExprIterator, ExprIterator);
111
    virtual void _getObjCoeffs(InsertIterator) const;
112

	
113
    virtual void _setObjCoeff(int i, Value obj_coef);
114
    virtual Value _getObjCoeff(int i) const;
115

	
116
    virtual void _setSense(Sense sense);
117
    virtual Sense _getSense() const;
118

	
119
    virtual SolveExitStatus _solve();
120

	
121
    virtual Value _getPrimal(int i) const;
122
    virtual Value _getDual(int i) const;
123

	
124
    virtual Value _getPrimalValue() const;
125

	
126
    virtual Value _getPrimalRay(int i) const;
127
    virtual Value _getDualRay(int i) const;
128

	
129
    virtual VarStatus _getColStatus(int i) const;
130
    virtual VarStatus _getRowStatus(int i) const;
131

	
132
    virtual ProblemType _getPrimalType() const;
133
    virtual ProblemType _getDualType() const;
134

	
135
    virtual void _clear();
136

	
137
  public:
138

	
139
    ///Solves LP with primal simplex method.
140
    SolveExitStatus solvePrimal();
141

	
142
    ///Solves LP with dual simplex method.
143
    SolveExitStatus solveDual();
144

	
145
    ///Solves LP with barrier method.
146
    SolveExitStatus solveBarrier();
147

	
148
    ///Returns the constraint identifier understood by CLP.
149
    int clpRow(Row r) const { return rows(id(r)); }
150

	
151
    ///Returns the variable identifier understood by CLP.
152
    int clpCol(Col c) const { return cols(id(c)); }
153

	
154
    ///Enum for \c messageLevel() parameter
155
    enum MessageLevel {
156
      /// no output (default value)
157
      MESSAGE_NO_OUTPUT = 0,
158
      /// print final solution
159
      MESSAGE_FINAL_SOLUTION = 1,
160
      /// print factorization
161
      MESSAGE_FACTORIZATION = 2,
162
      /// normal output
163
      MESSAGE_NORMAL_OUTPUT = 3,
164
      /// verbose output
165
      MESSAGE_VERBOSE_OUTPUT = 4
166
    };
167
    ///Set the verbosity of the messages
168

	
169
    ///Set the verbosity of the messages
170
    ///
171
    ///\param m is the level of the messages output by the solver routines.
172
    void messageLevel(MessageLevel m);
173

	
174
  };
175

	
176
} //END OF NAMESPACE LEMON
177

	
178
#endif //LEMON_CLP_H
179

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#include <iostream>
20
#include <vector>
21
#include <cstring>
22

	
23
#include <lemon/cplex.h>
24

	
25
extern "C" {
26
#include <ilcplex/cplex.h>
27
}
28

	
29

	
30
///\file
31
///\brief Implementation of the LEMON-CPLEX lp solver interface.
32
namespace lemon {
33

	
34
  CplexEnv::LicenseError::LicenseError(int status) {
35
    if (!CPXgeterrorstring(0, status, _message)) {
36
      std::strcpy(_message, "Cplex unknown error");
37
    }
38
  }
39

	
40
  CplexEnv::CplexEnv() {
41
    int status;
42
    _cnt = new int;
43
    _env = CPXopenCPLEX(&status);
44
    if (_env == 0) {
45
      delete _cnt;
46
      _cnt = 0;
47
      throw LicenseError(status);
48
    }
49
  }
50

	
51
  CplexEnv::CplexEnv(const CplexEnv& other) {
52
    _env = other._env;
53
    _cnt = other._cnt;
54
    ++(*_cnt);
55
  }
56

	
57
  CplexEnv& CplexEnv::operator=(const CplexEnv& other) {
58
    _env = other._env;
59
    _cnt = other._cnt;
60
    ++(*_cnt);
61
    return *this;
62
  }
63

	
64
  CplexEnv::~CplexEnv() {
65
    --(*_cnt);
66
    if (*_cnt == 0) {
67
      delete _cnt;
68
      CPXcloseCPLEX(&_env);
69
    }
70
  }
71

	
72
  CplexBase::CplexBase() : LpBase() {
73
    int status;
74
    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
75
  }
76

	
77
  CplexBase::CplexBase(const CplexEnv& env)
78
    : LpBase(), _env(env) {
79
    int status;
80
    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
81
  }
82

	
83
  CplexBase::CplexBase(const CplexBase& cplex)
84
    : LpBase() {
85
    int status;
86
    _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status);
87
    rows = cplex.rows;
88
    cols = cplex.cols;
89
  }
90

	
91
  CplexBase::~CplexBase() {
92
    CPXfreeprob(cplexEnv(),&_prob);
93
  }
94

	
95
  int CplexBase::_addCol() {
96
    int i = CPXgetnumcols(cplexEnv(), _prob);
97
    double lb = -INF, ub = INF;
98
    CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0);
99
    return i;
100
  }
101

	
102

	
103
  int CplexBase::_addRow() {
104
    int i = CPXgetnumrows(cplexEnv(), _prob);
105
    const double ub = INF;
106
    const char s = 'L';
107
    CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
108
    return i;
109
  }
110

	
111

	
112
  void CplexBase::_eraseCol(int i) {
113
    CPXdelcols(cplexEnv(), _prob, i, i);
114
  }
115

	
116
  void CplexBase::_eraseRow(int i) {
117
    CPXdelrows(cplexEnv(), _prob, i, i);
118
  }
119

	
120
  void CplexBase::_eraseColId(int i) {
121
    cols.eraseIndex(i);
122
    cols.shiftIndices(i);
123
  }
124
  void CplexBase::_eraseRowId(int i) {
125
    rows.eraseIndex(i);
126
    rows.shiftIndices(i);
127
  }
128

	
129
  void CplexBase::_getColName(int col, std::string &name) const {
130
    int size;
131
    CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col);
132
    if (size == 0) {
133
      name.clear();
134
      return;
135
    }
136

	
137
    size *= -1;
138
    std::vector<char> buf(size);
139
    char *cname;
140
    int tmp;
141
    CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size,
142
                  &tmp, col, col);
143
    name = cname;
144
  }
145

	
146
  void CplexBase::_setColName(int col, const std::string &name) {
147
    char *cname;
148
    cname = const_cast<char*>(name.c_str());
149
    CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname);
150
  }
151

	
152
  int CplexBase::_colByName(const std::string& name) const {
153
    int index;
154
    if (CPXgetcolindex(cplexEnv(), _prob,
155
                       const_cast<char*>(name.c_str()), &index) == 0) {
156
      return index;
157
    }
158
    return -1;
159
  }
160

	
161
  void CplexBase::_getRowName(int row, std::string &name) const {
162
    int size;
163
    CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row);
164
    if (size == 0) {
165
      name.clear();
166
      return;
167
    }
168

	
169
    size *= -1;
170
    std::vector<char> buf(size);
171
    char *cname;
172
    int tmp;
173
    CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size,
174
                  &tmp, row, row);
175
    name = cname;
176
  }
177

	
178
  void CplexBase::_setRowName(int row, const std::string &name) {
179
    char *cname;
180
    cname = const_cast<char*>(name.c_str());
181
    CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname);
182
  }
183

	
184
  int CplexBase::_rowByName(const std::string& name) const {
185
    int index;
186
    if (CPXgetrowindex(cplexEnv(), _prob,
187
                       const_cast<char*>(name.c_str()), &index) == 0) {
188
      return index;
189
    }
190
    return -1;
191
  }
192

	
193
  void CplexBase::_setRowCoeffs(int i, ExprIterator b,
194
                                      ExprIterator e)
195
  {
196
    std::vector<int> indices;
197
    std::vector<int> rowlist;
198
    std::vector<Value> values;
199

	
200
    for(ExprIterator it=b; it!=e; ++it) {
201
      indices.push_back(it->first);
202
      values.push_back(it->second);
203
      rowlist.push_back(i);
204
    }
205

	
206
    CPXchgcoeflist(cplexEnv(), _prob, values.size(),
207
                   &rowlist.front(), &indices.front(), &values.front());
208
  }
209

	
210
  void CplexBase::_getRowCoeffs(int i, InsertIterator b) const {
211
    int tmp1, tmp2, tmp3, length;
212
    CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
213

	
214
    length = -length;
215
    std::vector<int> indices(length);
216
    std::vector<double> values(length);
217

	
218
    CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2,
219
               &indices.front(), &values.front(),
220
               length, &tmp3, i, i);
221

	
222
    for (int i = 0; i < length; ++i) {
223
      *b = std::make_pair(indices[i], values[i]);
224
      ++b;
225
    }
226
  }
227

	
228
  void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) {
229
    std::vector<int> indices;
230
    std::vector<int> collist;
231
    std::vector<Value> values;
232

	
233
    for(ExprIterator it=b; it!=e; ++it) {
234
      indices.push_back(it->first);
235
      values.push_back(it->second);
236
      collist.push_back(i);
237
    }
238

	
239
    CPXchgcoeflist(cplexEnv(), _prob, values.size(),
240
                   &indices.front(), &collist.front(), &values.front());
241
  }
242

	
243
  void CplexBase::_getColCoeffs(int i, InsertIterator b) const {
244

	
245
    int tmp1, tmp2, tmp3, length;
246
    CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
247

	
248
    length = -length;
249
    std::vector<int> indices(length);
250
    std::vector<double> values(length);
251

	
252
    CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2,
253
               &indices.front(), &values.front(),
254
               length, &tmp3, i, i);
255

	
256
    for (int i = 0; i < length; ++i) {
257
      *b = std::make_pair(indices[i], values[i]);
258
      ++b;
259
    }
260

	
261
  }
262

	
263
  void CplexBase::_setCoeff(int row, int col, Value value) {
264
    CPXchgcoef(cplexEnv(), _prob, row, col, value);
265
  }
266

	
267
  CplexBase::Value CplexBase::_getCoeff(int row, int col) const {
268
    CplexBase::Value value;
269
    CPXgetcoef(cplexEnv(), _prob, row, col, &value);
270
    return value;
271
  }
272

	
273
  void CplexBase::_setColLowerBound(int i, Value value) {
274
    const char s = 'L';
275
    CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
276
  }
277

	
278
  CplexBase::Value CplexBase::_getColLowerBound(int i) const {
279
    CplexBase::Value res;
280
    CPXgetlb(cplexEnv(), _prob, &res, i, i);
281
    return res <= -CPX_INFBOUND ? -INF : res;
282
  }
283

	
284
  void CplexBase::_setColUpperBound(int i, Value value)
285
  {
286
    const char s = 'U';
287
    CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
288
  }
289

	
290
  CplexBase::Value CplexBase::_getColUpperBound(int i) const {
291
    CplexBase::Value res;
292
    CPXgetub(cplexEnv(), _prob, &res, i, i);
293
    return res >= CPX_INFBOUND ? INF : res;
294
  }
295

	
296
  CplexBase::Value CplexBase::_getRowLowerBound(int i) const {
297
    char s;
298
    CPXgetsense(cplexEnv(), _prob, &s, i, i);
299
    CplexBase::Value res;
300

	
301
    switch (s) {
302
    case 'G':
303
    case 'R':
304
    case 'E':
305
      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
306
      return res <= -CPX_INFBOUND ? -INF : res;
307
    default:
308
      return -INF;
309
    }
310
  }
311

	
312
  CplexBase::Value CplexBase::_getRowUpperBound(int i) const {
313
    char s;
314
    CPXgetsense(cplexEnv(), _prob, &s, i, i);
315
    CplexBase::Value res;
316

	
317
    switch (s) {
318
    case 'L':
319
    case 'E':
320
      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
321
      return res >= CPX_INFBOUND ? INF : res;
322
    case 'R':
323
      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
324
      {
325
        double rng;
326
        CPXgetrngval(cplexEnv(), _prob, &rng, i, i);
327
        res += rng;
328
      }
329
      return res >= CPX_INFBOUND ? INF : res;
330
    default:
331
      return INF;
332
    }
333
  }
334

	
335
  //This is easier to implement
336
  void CplexBase::_set_row_bounds(int i, Value lb, Value ub) {
337
    if (lb == -INF) {
338
      const char s = 'L';
339
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
340
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub);
341
    } else if (ub == INF) {
342
      const char s = 'G';
343
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
344
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
345
    } else if (lb == ub){
346
      const char s = 'E';
347
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
348
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
349
    } else {
350
      const char s = 'R';
351
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
352
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
353
      double len = ub - lb;
354
      CPXchgrngval(cplexEnv(), _prob, 1, &i, &len);
355
    }
356
  }
357

	
358
  void CplexBase::_setRowLowerBound(int i, Value lb)
359
  {
360
    LEMON_ASSERT(lb != INF, "Invalid bound");
361
    _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i));
362
  }
363

	
364
  void CplexBase::_setRowUpperBound(int i, Value ub)
365
  {
366

	
367
    LEMON_ASSERT(ub != -INF, "Invalid bound");
368
    _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub);
369
  }
370

	
371
  void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e)
372
  {
373
    std::vector<int> indices;
374
    std::vector<Value> values;
375
    for(ExprIterator it=b; it!=e; ++it) {
376
      indices.push_back(it->first);
377
      values.push_back(it->second);
378
    }
379
    CPXchgobj(cplexEnv(), _prob, values.size(),
380
              &indices.front(), &values.front());
381

	
382
  }
383

	
384
  void CplexBase::_getObjCoeffs(InsertIterator b) const
385
  {
386
    int num = CPXgetnumcols(cplexEnv(), _prob);
387
    std::vector<Value> x(num);
388

	
389
    CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1);
390
    for (int i = 0; i < num; ++i) {
391
      if (x[i] != 0.0) {
392
        *b = std::make_pair(i, x[i]);
393
        ++b;
394
      }
395
    }
396
  }
397

	
398
  void CplexBase::_setObjCoeff(int i, Value obj_coef)
399
  {
400
    CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef);
401
  }
402

	
403
  CplexBase::Value CplexBase::_getObjCoeff(int i) const
404
  {
405
    Value x;
406
    CPXgetobj(cplexEnv(), _prob, &x, i, i);
407
    return x;
408
  }
409

	
410
  void CplexBase::_setSense(CplexBase::Sense sense) {
411
    switch (sense) {
412
    case MIN:
413
      CPXchgobjsen(cplexEnv(), _prob, CPX_MIN);
414
      break;
415
    case MAX:
416
      CPXchgobjsen(cplexEnv(), _prob, CPX_MAX);
417
      break;
418
    }
419
  }
420

	
421
  CplexBase::Sense CplexBase::_getSense() const {
422
    switch (CPXgetobjsen(cplexEnv(), _prob)) {
423
    case CPX_MIN:
424
      return MIN;
425
    case CPX_MAX:
426
      return MAX;
427
    default:
428
      LEMON_ASSERT(false, "Invalid sense");
429
      return CplexBase::Sense();
430
    }
431
  }
432

	
433
  void CplexBase::_clear() {
434
    CPXfreeprob(cplexEnv(),&_prob);
435
    int status;
436
    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
437
    rows.clear();
438
    cols.clear();
439
  }
440

	
441
  // LpCplex members
442

	
443
  LpCplex::LpCplex()
444
    : LpBase(), CplexBase(), LpSolver() {}
445

	
446
  LpCplex::LpCplex(const CplexEnv& env)
447
    : LpBase(), CplexBase(env), LpSolver() {}
448

	
449
  LpCplex::LpCplex(const LpCplex& other)
450
    : LpBase(), CplexBase(other), LpSolver() {}
451

	
452
  LpCplex::~LpCplex() {}
453

	
454
  LpCplex* LpCplex::_newSolver() const { return new LpCplex; }
455
  LpCplex* LpCplex::_cloneSolver() const {return new LpCplex(*this); }
456

	
457
  const char* LpCplex::_solverName() const { return "LpCplex"; }
458

	
459
  void LpCplex::_clear_temporals() {
460
    _col_status.clear();
461
    _row_status.clear();
462
    _primal_ray.clear();
463
    _dual_ray.clear();
464
  }
465

	
466
  // The routine returns zero unless an error occurred during the
467
  // optimization. Examples of errors include exhausting available
468
  // memory (CPXERR_NO_MEMORY) or encountering invalid data in the
469
  // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a
470
  // user-specified CPLEX limit, or proving the model infeasible or
471
  // unbounded, are not considered errors. Note that a zero return
472
  // value does not necessarily mean that a solution exists. Use query
473
  // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain
474
  // further information about the status of the optimization.
475
  LpCplex::SolveExitStatus LpCplex::convertStatus(int status) {
476
#if CPX_VERSION >= 800
477
    if (status == 0) {
478
      switch (CPXgetstat(cplexEnv(), _prob)) {
479
      case CPX_STAT_OPTIMAL:
480
      case CPX_STAT_INFEASIBLE:
481
      case CPX_STAT_UNBOUNDED:
482
        return SOLVED;
483
      default:
484
        return UNSOLVED;
485
      }
486
    } else {
487
      return UNSOLVED;
488
    }
489
#else
490
    if (status == 0) {
491
      //We want to exclude some cases
492
      switch (CPXgetstat(cplexEnv(), _prob)) {
493
      case CPX_OBJ_LIM:
494
      case CPX_IT_LIM_FEAS:
495
      case CPX_IT_LIM_INFEAS:
496
      case CPX_TIME_LIM_FEAS:
497
      case CPX_TIME_LIM_INFEAS:
498
        return UNSOLVED;
499
      default:
500
        return SOLVED;
501
      }
502
    } else {
503
      return UNSOLVED;
504
    }
505
#endif
506
  }
507

	
508
  LpCplex::SolveExitStatus LpCplex::_solve() {
509
    _clear_temporals();
510
    return convertStatus(CPXlpopt(cplexEnv(), _prob));
511
  }
512

	
513
  LpCplex::SolveExitStatus LpCplex::solvePrimal() {
514
    _clear_temporals();
515
    return convertStatus(CPXprimopt(cplexEnv(), _prob));
516
  }
517

	
518
  LpCplex::SolveExitStatus LpCplex::solveDual() {
519
    _clear_temporals();
520
    return convertStatus(CPXdualopt(cplexEnv(), _prob));
521
  }
522

	
523
  LpCplex::SolveExitStatus LpCplex::solveBarrier() {
524
    _clear_temporals();
525
    return convertStatus(CPXbaropt(cplexEnv(), _prob));
526
  }
527

	
528
  LpCplex::Value LpCplex::_getPrimal(int i) const {
529
    Value x;
530
    CPXgetx(cplexEnv(), _prob, &x, i, i);
531
    return x;
532
  }
533

	
534
  LpCplex::Value LpCplex::_getDual(int i) const {
535
    Value y;
536
    CPXgetpi(cplexEnv(), _prob, &y, i, i);
537
    return y;
538
  }
539

	
540
  LpCplex::Value LpCplex::_getPrimalValue() const {
541
    Value objval;
542
    CPXgetobjval(cplexEnv(), _prob, &objval);
543
    return objval;
544
  }
545

	
546
  LpCplex::VarStatus LpCplex::_getColStatus(int i) const {
547
    if (_col_status.empty()) {
548
      _col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
549
      CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
550
    }
551
    switch (_col_status[i]) {
552
    case CPX_BASIC:
553
      return BASIC;
554
    case CPX_FREE_SUPER:
555
      return FREE;
556
    case CPX_AT_LOWER:
557
      return LOWER;
558
    case CPX_AT_UPPER:
559
      return UPPER;
560
    default:
561
      LEMON_ASSERT(false, "Wrong column status");
562
      return LpCplex::VarStatus();
563
    }
564
  }
565

	
566
  LpCplex::VarStatus LpCplex::_getRowStatus(int i) const {
567
    if (_row_status.empty()) {
568
      _row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
569
      CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
570
    }
571
    switch (_row_status[i]) {
572
    case CPX_BASIC:
573
      return BASIC;
574
    case CPX_AT_LOWER:
575
      {
576
        char s;
577
        CPXgetsense(cplexEnv(), _prob, &s, i, i);
578
        return s != 'L' ? LOWER : UPPER;
579
      }
580
    case CPX_AT_UPPER:
581
      return UPPER;
582
    default:
583
      LEMON_ASSERT(false, "Wrong row status");
584
      return LpCplex::VarStatus();
585
    }
586
  }
587

	
588
  LpCplex::Value LpCplex::_getPrimalRay(int i) const {
589
    if (_primal_ray.empty()) {
590
      _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
591
      CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
592
    }
593
    return _primal_ray[i];
594
  }
595

	
596
  LpCplex::Value LpCplex::_getDualRay(int i) const {
597
    if (_dual_ray.empty()) {
598

	
599
    }
600
    return _dual_ray[i];
601
  }
602

	
603
  //7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!)
604
  // This table lists the statuses, returned by the CPXgetstat()
605
  // routine, for solutions to LP problems or mixed integer problems. If
606
  // no solution exists, the return value is zero.
607

	
608
  // For Simplex, Barrier
609
  // 1          CPX_OPTIMAL
610
  //          Optimal solution found
611
  // 2          CPX_INFEASIBLE
612
  //          Problem infeasible
613
  // 3    CPX_UNBOUNDED
614
  //          Problem unbounded
615
  // 4          CPX_OBJ_LIM
616
  //          Objective limit exceeded in Phase II
617
  // 5          CPX_IT_LIM_FEAS
618
  //          Iteration limit exceeded in Phase II
619
  // 6          CPX_IT_LIM_INFEAS
620
  //          Iteration limit exceeded in Phase I
621
  // 7          CPX_TIME_LIM_FEAS
622
  //          Time limit exceeded in Phase II
623
  // 8          CPX_TIME_LIM_INFEAS
624
  //          Time limit exceeded in Phase I
625
  // 9          CPX_NUM_BEST_FEAS
626
  //          Problem non-optimal, singularities in Phase II
627
  // 10         CPX_NUM_BEST_INFEAS
628
  //          Problem non-optimal, singularities in Phase I
629
  // 11         CPX_OPTIMAL_INFEAS
630
  //          Optimal solution found, unscaled infeasibilities
631
  // 12         CPX_ABORT_FEAS
632
  //          Aborted in Phase II
633
  // 13         CPX_ABORT_INFEAS
634
  //          Aborted in Phase I
635
  // 14          CPX_ABORT_DUAL_INFEAS
636
  //          Aborted in barrier, dual infeasible
637
  // 15          CPX_ABORT_PRIM_INFEAS
638
  //          Aborted in barrier, primal infeasible
639
  // 16          CPX_ABORT_PRIM_DUAL_INFEAS
640
  //          Aborted in barrier, primal and dual infeasible
641
  // 17          CPX_ABORT_PRIM_DUAL_FEAS
642
  //          Aborted in barrier, primal and dual feasible
643
  // 18          CPX_ABORT_CROSSOVER
644
  //          Aborted in crossover
645
  // 19          CPX_INForUNBD
646
  //          Infeasible or unbounded
647
  // 20   CPX_PIVOT
648
  //       User pivot used
649
  //
650
  //     Ezeket hova tegyem:
651
  // ??case CPX_ABORT_DUAL_INFEAS
652
  // ??case CPX_ABORT_CROSSOVER
653
  // ??case CPX_INForUNBD
654
  // ??case CPX_PIVOT
655

	
656
  //Some more interesting stuff:
657

	
658
  // CPX_PARAM_PROBMETHOD  1062  int  LPMETHOD
659
  // 0 Automatic
660
  // 1 Primal Simplex
661
  // 2 Dual Simplex
662
  // 3 Network Simplex
663
  // 4 Standard Barrier
664
  // Default: 0
665
  // Description: Method for linear optimization.
666
  // Determines which algorithm is used when CPXlpopt() (or "optimize"
667
  // in the Interactive Optimizer) is called. Currently the behavior of
668
  // the "Automatic" setting is that CPLEX simply invokes the dual
669
  // simplex method, but this capability may be expanded in the future
670
  // so that CPLEX chooses the method based on problem characteristics
671
#if CPX_VERSION < 900
672
  void statusSwitch(CPXENVptr cplexEnv(),int& stat){
673
    int lpmethod;
674
    CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod);
675
    if (lpmethod==2){
676
      if (stat==CPX_UNBOUNDED){
677
        stat=CPX_INFEASIBLE;
678
      }
679
      else{
680
        if (stat==CPX_INFEASIBLE)
681
          stat=CPX_UNBOUNDED;
682
      }
683
    }
684
  }
685
#else
686
  void statusSwitch(CPXENVptr,int&){}
687
#endif
688

	
689
  LpCplex::ProblemType LpCplex::_getPrimalType() const {
690
    // Unboundedness not treated well: the following is from cplex 9.0 doc
691
    // About Unboundedness
692

	
693
    // The treatment of models that are unbounded involves a few
694
    // subtleties. Specifically, a declaration of unboundedness means that
695
    // ILOG CPLEX has determined that the model has an unbounded
696
    // ray. Given any feasible solution x with objective z, a multiple of
697
    // the unbounded ray can be added to x to give a feasible solution
698
    // with objective z-1 (or z+1 for maximization models). Thus, if a
699
    // feasible solution exists, then the optimal objective is
700
    // unbounded. Note that ILOG CPLEX has not necessarily concluded that
701
    // a feasible solution exists. Users can call the routine CPXsolninfo
702
    // to determine whether ILOG CPLEX has also concluded that the model
703
    // has a feasible solution.
704

	
705
    int stat = CPXgetstat(cplexEnv(), _prob);
706
#if CPX_VERSION >= 800
707
    switch (stat)
708
      {
709
      case CPX_STAT_OPTIMAL:
710
        return OPTIMAL;
711
      case CPX_STAT_UNBOUNDED:
712
        return UNBOUNDED;
713
      case CPX_STAT_INFEASIBLE:
714
        return INFEASIBLE;
715
      default:
716
        return UNDEFINED;
717
      }
718
#else
719
    statusSwitch(cplexEnv(),stat);
720
    //CPXgetstat(cplexEnv(), _prob);
721
    //printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL);
722
    switch (stat) {
723
    case 0:
724
      return UNDEFINED; //Undefined
725
    case CPX_OPTIMAL://Optimal
726
      return OPTIMAL;
727
    case CPX_UNBOUNDED://Unbounded
728
      return INFEASIBLE;//In case of dual simplex
729
      //return UNBOUNDED;
730
    case CPX_INFEASIBLE://Infeasible
731
      //    case CPX_IT_LIM_INFEAS:
732
      //     case CPX_TIME_LIM_INFEAS:
733
      //     case CPX_NUM_BEST_INFEAS:
734
      //     case CPX_OPTIMAL_INFEAS:
735
      //     case CPX_ABORT_INFEAS:
736
      //     case CPX_ABORT_PRIM_INFEAS:
737
      //     case CPX_ABORT_PRIM_DUAL_INFEAS:
738
      return UNBOUNDED;//In case of dual simplex
739
      //return INFEASIBLE;
740
      //     case CPX_OBJ_LIM:
741
      //     case CPX_IT_LIM_FEAS:
742
      //     case CPX_TIME_LIM_FEAS:
743
      //     case CPX_NUM_BEST_FEAS:
744
      //     case CPX_ABORT_FEAS:
745
      //     case CPX_ABORT_PRIM_DUAL_FEAS:
746
      //       return FEASIBLE;
747
    default:
748
      return UNDEFINED; //Everything else comes here
749
      //FIXME error
750
    }
751
#endif
752
  }
753

	
754
  //9.0-as cplex verzio statusai
755
  // CPX_STAT_ABORT_DUAL_OBJ_LIM
756
  // CPX_STAT_ABORT_IT_LIM
757
  // CPX_STAT_ABORT_OBJ_LIM
758
  // CPX_STAT_ABORT_PRIM_OBJ_LIM
759
  // CPX_STAT_ABORT_TIME_LIM
760
  // CPX_STAT_ABORT_USER
761
  // CPX_STAT_FEASIBLE_RELAXED
762
  // CPX_STAT_INFEASIBLE
763
  // CPX_STAT_INForUNBD
764
  // CPX_STAT_NUM_BEST
765
  // CPX_STAT_OPTIMAL
766
  // CPX_STAT_OPTIMAL_FACE_UNBOUNDED
767
  // CPX_STAT_OPTIMAL_INFEAS
768
  // CPX_STAT_OPTIMAL_RELAXED
769
  // CPX_STAT_UNBOUNDED
770

	
771
  LpCplex::ProblemType LpCplex::_getDualType() const {
772
    int stat = CPXgetstat(cplexEnv(), _prob);
773
#if CPX_VERSION >= 800
774
    switch (stat) {
775
    case CPX_STAT_OPTIMAL:
776
      return OPTIMAL;
777
    case CPX_STAT_UNBOUNDED:
778
      return INFEASIBLE;
779
    default:
780
      return UNDEFINED;
781
    }
782
#else
783
    statusSwitch(cplexEnv(),stat);
784
    switch (stat) {
785
    case 0:
786
      return UNDEFINED; //Undefined
787
    case CPX_OPTIMAL://Optimal
788
      return OPTIMAL;
789
    case CPX_UNBOUNDED:
790
      return INFEASIBLE;
791
    default:
792
      return UNDEFINED; //Everything else comes here
793
      //FIXME error
794
    }
795
#endif
796
  }
797

	
798
  // MipCplex members
799

	
800
  MipCplex::MipCplex()
801
    : LpBase(), CplexBase(), MipSolver() {
802

	
803
#if CPX_VERSION < 800
804
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
805
#else
806
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
807
#endif
808
  }
809

	
810
  MipCplex::MipCplex(const CplexEnv& env)
811
    : LpBase(), CplexBase(env), MipSolver() {
812

	
813
#if CPX_VERSION < 800
814
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
815
#else
816
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
817
#endif
818

	
819
  }
820

	
821
  MipCplex::MipCplex(const MipCplex& other)
822
    : LpBase(), CplexBase(other), MipSolver() {}
823

	
824
  MipCplex::~MipCplex() {}
825

	
826
  MipCplex* MipCplex::_newSolver() const { return new MipCplex; }
827
  MipCplex* MipCplex::_cloneSolver() const {return new MipCplex(*this); }
828

	
829
  const char* MipCplex::_solverName() const { return "MipCplex"; }
830

	
831
  void MipCplex::_setColType(int i, MipCplex::ColTypes col_type) {
832

	
833
    // Note If a variable is to be changed to binary, a call to CPXchgbds
834
    // should also be made to change the bounds to 0 and 1.
835

	
836
    switch (col_type){
837
    case INTEGER: {
838
      const char t = 'I';
839
      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
840
    } break;
841
    case REAL: {
842
      const char t = 'C';
843
      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
844
    } break;
845
    default:
846
      break;
847
    }
848
  }
849

	
850
  MipCplex::ColTypes MipCplex::_getColType(int i) const {
851
    char t;
852
    CPXgetctype (cplexEnv(), _prob, &t, i, i);
853
    switch (t) {
854
    case 'I':
855
      return INTEGER;
856
    case 'C':
857
      return REAL;
858
    default:
859
      LEMON_ASSERT(false, "Invalid column type");
860
      return ColTypes();
861
    }
862

	
863
  }
864

	
865
  MipCplex::SolveExitStatus MipCplex::_solve() {
866
    int status;
867
    status = CPXmipopt (cplexEnv(), _prob);
868
    if (status==0)
869
      return SOLVED;
870
    else
871
      return UNSOLVED;
872

	
873
  }
874

	
875

	
876
  MipCplex::ProblemType MipCplex::_getType() const {
877

	
878
    int stat = CPXgetstat(cplexEnv(), _prob);
879

	
880
    //Fortunately, MIP statuses did not change for cplex 8.0
881
    switch (stat) {
882
    case CPXMIP_OPTIMAL:
883
      // Optimal integer solution has been found.
884
    case CPXMIP_OPTIMAL_TOL:
885
      // Optimal soluton with the tolerance defined by epgap or epagap has
886
      // been found.
887
      return OPTIMAL;
888
      //This also exists in later issues
889
      //    case CPXMIP_UNBOUNDED:
890
      //return UNBOUNDED;
891
      case CPXMIP_INFEASIBLE:
892
        return INFEASIBLE;
893
    default:
894
      return UNDEFINED;
895
    }
896
    //Unboundedness not treated well: the following is from cplex 9.0 doc
897
    // About Unboundedness
898

	
899
    // The treatment of models that are unbounded involves a few
900
    // subtleties. Specifically, a declaration of unboundedness means that
901
    // ILOG CPLEX has determined that the model has an unbounded
902
    // ray. Given any feasible solution x with objective z, a multiple of
903
    // the unbounded ray can be added to x to give a feasible solution
904
    // with objective z-1 (or z+1 for maximization models). Thus, if a
905
    // feasible solution exists, then the optimal objective is
906
    // unbounded. Note that ILOG CPLEX has not necessarily concluded that
907
    // a feasible solution exists. Users can call the routine CPXsolninfo
908
    // to determine whether ILOG CPLEX has also concluded that the model
909
    // has a feasible solution.
910
  }
911

	
912
  MipCplex::Value MipCplex::_getSol(int i) const {
913
    Value x;
914
    CPXgetmipx(cplexEnv(), _prob, &x, i, i);
915
    return x;
916
  }
917

	
918
  MipCplex::Value MipCplex::_getSolValue() const {
919
    Value objval;
920
    CPXgetmipobjval(cplexEnv(), _prob, &objval);
921
    return objval;
922
  }
923

	
924
} //namespace lemon
925

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#ifndef LEMON_CPLEX_H
20
#define LEMON_CPLEX_H
21

	
22
///\file
23
///\brief Header of the LEMON-CPLEX lp solver interface.
24

	
25
#include <lemon/lp_base.h>
26

	
27
struct cpxenv;
28
struct cpxlp;
29

	
30
namespace lemon {
31

	
32
  /// \brief Reference counted wrapper around cpxenv pointer
33
  ///
34
  /// The cplex uses environment object which is responsible for
35
  /// checking the proper license usage. This class provides a simple
36
  /// interface for share the environment object between different
37
  /// problems.
38
  class CplexEnv {
39
    friend class CplexBase;
40
  private:
41
    cpxenv* _env;
42
    mutable int* _cnt;
43

	
44
  public:
45

	
46
    /// \brief This exception is thrown when the license check is not
47
    /// sufficient
48
    class LicenseError : public Exception {
49
      friend class CplexEnv;
50
    private:
51

	
52
      LicenseError(int status);
53
      char _message[510];
54

	
55
    public:
56

	
57
      /// The short error message
58
      virtual const char* what() const throw() {
59
        return _message;
60
      }
61
    };
62

	
63
    /// Constructor
64
    CplexEnv();
65
    /// Shallow copy constructor
66
    CplexEnv(const CplexEnv&);
67
    /// Shallow assignement
68
    CplexEnv& operator=(const CplexEnv&);
69
    /// Destructor
70
    virtual ~CplexEnv();
71

	
72
  protected:
73

	
74
    cpxenv* cplexEnv() { return _env; }
75
    const cpxenv* cplexEnv() const { return _env; }
76
  };
77

	
78
  /// \brief Base interface for the CPLEX LP and MIP solver
79
  ///
80
  /// This class implements the common interface of the CPLEX LP and
81
  /// MIP solvers.  
82
  /// \ingroup lp_group
83
  class CplexBase : virtual public LpBase {
84
  protected:
85

	
86
    CplexEnv _env;
87
    cpxlp* _prob;
88

	
89
    CplexBase();
90
    CplexBase(const CplexEnv&);
91
    CplexBase(const CplexBase &);
92
    virtual ~CplexBase();
93

	
94
    virtual int _addCol();
95
    virtual int _addRow();
96

	
97
    virtual void _eraseCol(int i);
98
    virtual void _eraseRow(int i);
99

	
100
    virtual void _eraseColId(int i);
101
    virtual void _eraseRowId(int i);
102

	
103
    virtual void _getColName(int col, std::string& name) const;
104
    virtual void _setColName(int col, const std::string& name);
105
    virtual int _colByName(const std::string& name) const;
106

	
107
    virtual void _getRowName(int row, std::string& name) const;
108
    virtual void _setRowName(int row, const std::string& name);
109
    virtual int _rowByName(const std::string& name) const;
110

	
111
    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
112
    virtual void _getRowCoeffs(int i, InsertIterator b) const;
113

	
114
    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
115
    virtual void _getColCoeffs(int i, InsertIterator b) const;
116

	
117
    virtual void _setCoeff(int row, int col, Value value);
118
    virtual Value _getCoeff(int row, int col) const;
119

	
120
    virtual void _setColLowerBound(int i, Value value);
121
    virtual Value _getColLowerBound(int i) const;
122

	
123
    virtual void _setColUpperBound(int i, Value value);
124
    virtual Value _getColUpperBound(int i) const;
125

	
126
  private:
127
    void _set_row_bounds(int i, Value lb, Value ub);
128
  protected:
129

	
130
    virtual void _setRowLowerBound(int i, Value value);
131
    virtual Value _getRowLowerBound(int i) const;
132

	
133
    virtual void _setRowUpperBound(int i, Value value);
134
    virtual Value _getRowUpperBound(int i) const;
135

	
136
    virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
137
    virtual void _getObjCoeffs(InsertIterator b) const;
138

	
139
    virtual void _setObjCoeff(int i, Value obj_coef);
140
    virtual Value _getObjCoeff(int i) const;
141

	
142
    virtual void _setSense(Sense sense);
143
    virtual Sense _getSense() const;
144

	
145
    virtual void _clear();
146

	
147
  public:
148

	
149
    /// Returns the used \c CplexEnv instance
150
    const CplexEnv& env() const { return _env; }
151
    ///
152
    const cpxenv* cplexEnv() const { return _env.cplexEnv(); }
153

	
154
    cpxlp* cplexLp() { return _prob; }
155
    const cpxlp* cplexLp() const { return _prob; }
156

	
157
  };
158

	
159
  /// \brief Interface for the CPLEX LP solver
160
  ///
161
  /// This class implements an interface for the CPLEX LP solver.
162
  ///\ingroup lp_group
163
  class LpCplex : public CplexBase, public LpSolver {
164
  public:
165
    /// \e
166
    LpCplex();
167
    /// \e
168
    LpCplex(const CplexEnv&);
169
    /// \e
170
    LpCplex(const LpCplex&);
171
    /// \e
172
    virtual ~LpCplex();
173

	
174
  private:
175

	
176
    // these values cannot retrieved element by element
177
    mutable std::vector<int> _col_status;
178
    mutable std::vector<int> _row_status;
179

	
180
    mutable std::vector<Value> _primal_ray;
181
    mutable std::vector<Value> _dual_ray;
182

	
183
    void _clear_temporals();
184

	
185
    SolveExitStatus convertStatus(int status);
186

	
187
  protected:
188

	
189
    virtual LpCplex* _cloneSolver() const;
190
    virtual LpCplex* _newSolver() const;
191

	
192
    virtual const char* _solverName() const;
193

	
194
    virtual SolveExitStatus _solve();
195
    virtual Value _getPrimal(int i) const;
196
    virtual Value _getDual(int i) const;
197
    virtual Value _getPrimalValue() const;
198

	
199
    virtual VarStatus _getColStatus(int i) const;
200
    virtual VarStatus _getRowStatus(int i) const;
201

	
202
    virtual Value _getPrimalRay(int i) const;
203
    virtual Value _getDualRay(int i) const;
204

	
205
    virtual ProblemType _getPrimalType() const;
206
    virtual ProblemType _getDualType() const;
207

	
208
  public:
209

	
210
    /// Solve with primal simplex method
211
    SolveExitStatus solvePrimal();
212

	
213
    /// Solve with dual simplex method
214
    SolveExitStatus solveDual();
215

	
216
    /// Solve with barrier method
217
    SolveExitStatus solveBarrier();
218

	
219
  };
220

	
221
  /// \brief Interface for the CPLEX MIP solver
222
  ///
223
  /// This class implements an interface for the CPLEX MIP solver.
224
  ///\ingroup lp_group
225
  class MipCplex : public CplexBase, public MipSolver {
226
  public:
227
    /// \e
228
    MipCplex();
229
    /// \e
230
    MipCplex(const CplexEnv&);
231
    /// \e
232
    MipCplex(const MipCplex&);
233
    /// \e
234
    virtual ~MipCplex();
235

	
236
  protected:
237

	
238
    virtual MipCplex* _cloneSolver() const;
239
    virtual MipCplex* _newSolver() const;
240

	
241
    virtual const char* _solverName() const;
242

	
243
    virtual ColTypes _getColType(int col) const;
244
    virtual void _setColType(int col, ColTypes col_type);
245

	
246
    virtual SolveExitStatus _solve();
247
    virtual ProblemType _getType() const;
248
    virtual Value _getSol(int i) const;
249
    virtual Value _getSolValue() const;
250

	
251
  };
252

	
253
} //END OF NAMESPACE LEMON
254

	
255
#endif //LEMON_CPLEX_H
256

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
///\file
20
///\brief Implementation of the LEMON GLPK LP and MIP solver interface.
21

	
22
#include <lemon/glpk.h>
23
#include <glpk.h>
24

	
25
#include <lemon/assert.h>
26

	
27
namespace lemon {
28

	
29
  // GlpkBase members
30

	
31
  GlpkBase::GlpkBase() : LpBase() {
32
    lp = glp_create_prob();
33
    glp_create_index(lp);
34
  }
35

	
36
  GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() {
37
    lp = glp_create_prob();
38
    glp_copy_prob(lp, other.lp, GLP_ON);
39
    glp_create_index(lp);
40
    rows = other.rows;
41
    cols = other.cols;
42
  }
43

	
44
  GlpkBase::~GlpkBase() {
45
    glp_delete_prob(lp);
46
  }
47

	
48
  int GlpkBase::_addCol() {
49
    int i = glp_add_cols(lp, 1);
50
    glp_set_col_bnds(lp, i, GLP_FR, 0.0, 0.0);
51
    return i;
52
  }
53

	
54
  int GlpkBase::_addRow() {
55
    int i = glp_add_rows(lp, 1);
56
    glp_set_row_bnds(lp, i, GLP_FR, 0.0, 0.0);
57
    return i;
58
  }
59

	
60
  void GlpkBase::_eraseCol(int i) {
61
    int ca[2];
62
    ca[1] = i;
63
    glp_del_cols(lp, 1, ca);
64
  }
65

	
66
  void GlpkBase::_eraseRow(int i) {
67
    int ra[2];
68
    ra[1] = i;
69
    glp_del_rows(lp, 1, ra);
70
  }
71

	
72
  void GlpkBase::_eraseColId(int i) {
73
    cols.eraseIndex(i);
74
    cols.shiftIndices(i);
75
  }
76

	
77
  void GlpkBase::_eraseRowId(int i) {
78
    rows.eraseIndex(i);
79
    rows.shiftIndices(i);
80
  }
81

	
82
  void GlpkBase::_getColName(int c, std::string& name) const {
83
    const char *str = glp_get_col_name(lp, c);
84
    if (str) name = str;
85
    else name.clear();
86
  }
87

	
88
  void GlpkBase::_setColName(int c, const std::string & name) {
89
    glp_set_col_name(lp, c, const_cast<char*>(name.c_str()));
90

	
91
  }
92

	
93
  int GlpkBase::_colByName(const std::string& name) const {
94
    int k = glp_find_col(lp, const_cast<char*>(name.c_str()));
95
    return k > 0 ? k : -1;
96
  }
97

	
98
  void GlpkBase::_getRowName(int r, std::string& name) const {
99
    const char *str = glp_get_row_name(lp, r);
100
    if (str) name = str;
101
    else name.clear();
102
  }
103

	
104
  void GlpkBase::_setRowName(int r, const std::string & name) {
105
    glp_set_row_name(lp, r, const_cast<char*>(name.c_str()));
106

	
107
  }
108

	
109
  int GlpkBase::_rowByName(const std::string& name) const {
110
    int k = glp_find_row(lp, const_cast<char*>(name.c_str()));
111
    return k > 0 ? k : -1;
112
  }
113

	
114
  void GlpkBase::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
115
    std::vector<int> indexes;
116
    std::vector<Value> values;
117

	
118
    indexes.push_back(0);
119
    values.push_back(0);
120

	
121
    for(ExprIterator it = b; it != e; ++it) {
122
      indexes.push_back(it->first);
123
      values.push_back(it->second);
124
    }
125

	
126
    glp_set_mat_row(lp, i, values.size() - 1,
127
                    &indexes.front(), &values.front());
128
  }
129

	
130
  void GlpkBase::_getRowCoeffs(int ix, InsertIterator b) const {
131
    int length = glp_get_mat_row(lp, ix, 0, 0);
132

	
133
    std::vector<int> indexes(length + 1);
134
    std::vector<Value> values(length + 1);
135

	
136
    glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
137

	
138
    for (int i = 1; i <= length; ++i) {
139
      *b = std::make_pair(indexes[i], values[i]);
140
      ++b;
141
    }
142
  }
143

	
144
  void GlpkBase::_setColCoeffs(int ix, ExprIterator b,
145
                                     ExprIterator e) {
146

	
147
    std::vector<int> indexes;
148
    std::vector<Value> values;
149

	
150
    indexes.push_back(0);
151
    values.push_back(0);
152

	
153
    for(ExprIterator it = b; it != e; ++it) {
154
      indexes.push_back(it->first);
155
      values.push_back(it->second);
156
    }
157

	
158
    glp_set_mat_col(lp, ix, values.size() - 1,
159
                    &indexes.front(), &values.front());
160
  }
161

	
162
  void GlpkBase::_getColCoeffs(int ix, InsertIterator b) const {
163
    int length = glp_get_mat_col(lp, ix, 0, 0);
164

	
165
    std::vector<int> indexes(length + 1);
166
    std::vector<Value> values(length + 1);
167

	
168
    glp_get_mat_col(lp, ix, &indexes.front(), &values.front());
169

	
170
    for (int i = 1; i  <= length; ++i) {
171
      *b = std::make_pair(indexes[i], values[i]);
172
      ++b;
173
    }
174
  }
175

	
176
  void GlpkBase::_setCoeff(int ix, int jx, Value value) {
177

	
178
    if (glp_get_num_cols(lp) < glp_get_num_rows(lp)) {
179

	
180
      int length = glp_get_mat_row(lp, ix, 0, 0);
181

	
182
      std::vector<int> indexes(length + 2);
183
      std::vector<Value> values(length + 2);
184

	
185
      glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
186

	
187
      //The following code does not suppose that the elements of the
188
      //array indexes are sorted
189
      bool found = false;
190
      for (int i = 1; i  <= length; ++i) {
191
        if (indexes[i] == jx) {
192
          found = true;
193
          values[i] = value;
194
          break;
195
        }
196
      }
197
      if (!found) {
198
        ++length;
199
        indexes[length] = jx;
200
        values[length] = value;
201
      }
202

	
203
      glp_set_mat_row(lp, ix, length, &indexes.front(), &values.front());
204

	
205
    } else {
206

	
207
      int length = glp_get_mat_col(lp, jx, 0, 0);
208

	
209
      std::vector<int> indexes(length + 2);
210
      std::vector<Value> values(length + 2);
211

	
212
      glp_get_mat_col(lp, jx, &indexes.front(), &values.front());
213

	
214
      //The following code does not suppose that the elements of the
215
      //array indexes are sorted
216
      bool found = false;
217
      for (int i = 1; i <= length; ++i) {
218
        if (indexes[i] == ix) {
219
          found = true;
220
          values[i] = value;
221
          break;
222
        }
223
      }
224
      if (!found) {
225
        ++length;
226
        indexes[length] = ix;
227
        values[length] = value;
228
      }
229

	
230
      glp_set_mat_col(lp, jx, length, &indexes.front(), &values.front());
231
    }
232

	
233
  }
234

	
235
  GlpkBase::Value GlpkBase::_getCoeff(int ix, int jx) const {
236

	
237
    int length = glp_get_mat_row(lp, ix, 0, 0);
238

	
239
    std::vector<int> indexes(length + 1);
240
    std::vector<Value> values(length + 1);
241

	
242
    glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
243

	
244
    for (int i = 1; i  <= length; ++i) {
245
      if (indexes[i] == jx) {
246
        return values[i];
247
      }
248
    }
249

	
250
    return 0;
251
  }
252

	
253
  void GlpkBase::_setColLowerBound(int i, Value lo) {
254
    LEMON_ASSERT(lo != INF, "Invalid bound");
255

	
256
    int b = glp_get_col_type(lp, i);
257
    double up = glp_get_col_ub(lp, i);
258
    if (lo == -INF) {
259
      switch (b) {
260
      case GLP_FR:
261
      case GLP_LO:
262
        glp_set_col_bnds(lp, i, GLP_FR, lo, up);
263
        break;
264
      case GLP_UP:
265
        break;
266
      case GLP_DB:
267
      case GLP_FX:
268
        glp_set_col_bnds(lp, i, GLP_UP, lo, up);
269
        break;
270
      default:
271
        break;
272
      }
273
    } else {
274
      switch (b) {
275
      case GLP_FR:
276
      case GLP_LO:
277
        glp_set_col_bnds(lp, i, GLP_LO, lo, up);
278
        break;
279
      case GLP_UP:
280
      case GLP_DB:
281
      case GLP_FX:
282
        if (lo == up)
283
          glp_set_col_bnds(lp, i, GLP_FX, lo, up);
284
        else
285
          glp_set_col_bnds(lp, i, GLP_DB, lo, up);
286
        break;
287
      default:
288
        break;
289
      }
290
    }
291
  }
292

	
293
  GlpkBase::Value GlpkBase::_getColLowerBound(int i) const {
294
    int b = glp_get_col_type(lp, i);
295
    switch (b) {
296
    case GLP_LO:
297
    case GLP_DB:
298
    case GLP_FX:
299
      return glp_get_col_lb(lp, i);
300
    default:
301
      return -INF;
302
    }
303
  }
304

	
305
  void GlpkBase::_setColUpperBound(int i, Value up) {
306
    LEMON_ASSERT(up != -INF, "Invalid bound");
307

	
308
    int b = glp_get_col_type(lp, i);
309
    double lo = glp_get_col_lb(lp, i);
310
    if (up == INF) {
311
      switch (b) {
312
      case GLP_FR:
313
      case GLP_LO:
314
        break;
315
      case GLP_UP:
316
        glp_set_col_bnds(lp, i, GLP_FR, lo, up);
317
        break;
318
      case GLP_DB:
319
      case GLP_FX:
320
        glp_set_col_bnds(lp, i, GLP_LO, lo, up);
321
        break;
322
      default:
323
        break;
324
      }
325
    } else {
326
      switch (b) {
327
      case GLP_FR:
328
        glp_set_col_bnds(lp, i, GLP_UP, lo, up);
329
        break;
330
      case GLP_UP:
331
        glp_set_col_bnds(lp, i, GLP_UP, lo, up);
332
        break;
333
      case GLP_LO:
334
      case GLP_DB:
335
      case GLP_FX:
336
        if (lo == up)
337
          glp_set_col_bnds(lp, i, GLP_FX, lo, up);
338
        else
339
          glp_set_col_bnds(lp, i, GLP_DB, lo, up);
340
        break;
341
      default:
342
        break;
343
      }
344
    }
345

	
346
  }
347

	
348
  GlpkBase::Value GlpkBase::_getColUpperBound(int i) const {
349
    int b = glp_get_col_type(lp, i);
350
      switch (b) {
351
      case GLP_UP:
352
      case GLP_DB:
353
      case GLP_FX:
354
        return glp_get_col_ub(lp, i);
355
      default:
356
        return INF;
357
      }
358
  }
359

	
360
  void GlpkBase::_setRowLowerBound(int i, Value lo) {
361
    LEMON_ASSERT(lo != INF, "Invalid bound");
362

	
363
    int b = glp_get_row_type(lp, i);
364
    double up = glp_get_row_ub(lp, i);
365
    if (lo == -INF) {
366
      switch (b) {
367
      case GLP_FR:
368
      case GLP_LO:
369
        glp_set_row_bnds(lp, i, GLP_FR, lo, up);
370
        break;
371
      case GLP_UP:
372
        break;
373
      case GLP_DB:
374
      case GLP_FX:
375
        glp_set_row_bnds(lp, i, GLP_UP, lo, up);
376
        break;
377
      default:
378
        break;
379
      }
380
    } else {
381
      switch (b) {
382
      case GLP_FR:
383
      case GLP_LO:
384
        glp_set_row_bnds(lp, i, GLP_LO, lo, up);
385
        break;
386
      case GLP_UP:
387
      case GLP_DB:
388
      case GLP_FX:
389
        if (lo == up)
390
          glp_set_row_bnds(lp, i, GLP_FX, lo, up);
391
        else
392
          glp_set_row_bnds(lp, i, GLP_DB, lo, up);
393
        break;
394
      default:
395
        break;
396
      }
397
    }
398

	
399
  }
400

	
401
  GlpkBase::Value GlpkBase::_getRowLowerBound(int i) const {
402
    int b = glp_get_row_type(lp, i);
403
    switch (b) {
404
    case GLP_LO:
405
    case GLP_DB:
406
    case GLP_FX:
407
      return glp_get_row_lb(lp, i);
408
    default:
409
      return -INF;
410
    }
411
  }
412

	
413
  void GlpkBase::_setRowUpperBound(int i, Value up) {
414
    LEMON_ASSERT(up != -INF, "Invalid bound");
415

	
416
    int b = glp_get_row_type(lp, i);
417
    double lo = glp_get_row_lb(lp, i);
418
    if (up == INF) {
419
      switch (b) {
420
      case GLP_FR:
421
      case GLP_LO:
422
        break;
423
      case GLP_UP:
424
        glp_set_row_bnds(lp, i, GLP_FR, lo, up);
425
        break;
426
      case GLP_DB:
427
      case GLP_FX:
428
        glp_set_row_bnds(lp, i, GLP_LO, lo, up);
429
        break;
430
      default:
431
        break;
432
      }
433
    } else {
434
      switch (b) {
435
      case GLP_FR:
436
        glp_set_row_bnds(lp, i, GLP_UP, lo, up);
437
        break;
438
      case GLP_UP:
439
        glp_set_row_bnds(lp, i, GLP_UP, lo, up);
440
        break;
441
      case GLP_LO:
442
      case GLP_DB:
443
      case GLP_FX:
444
        if (lo == up)
445
          glp_set_row_bnds(lp, i, GLP_FX, lo, up);
446
        else
447
          glp_set_row_bnds(lp, i, GLP_DB, lo, up);
448
        break;
449
      default:
450
        break;
451
      }
452
    }
453
  }
454

	
455
  GlpkBase::Value GlpkBase::_getRowUpperBound(int i) const {
456
    int b = glp_get_row_type(lp, i);
457
    switch (b) {
458
    case GLP_UP:
459
    case GLP_DB:
460
    case GLP_FX:
461
      return glp_get_row_ub(lp, i);
462
    default:
463
      return INF;
464
    }
465
  }
466

	
467
  void GlpkBase::_setObjCoeffs(ExprIterator b, ExprIterator e) {
468
    for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
469
      glp_set_obj_coef(lp, i, 0.0);
470
    }
471
    for (ExprIterator it = b; it != e; ++it) {
472
      glp_set_obj_coef(lp, it->first, it->second);
473
    }
474
  }
475

	
476
  void GlpkBase::_getObjCoeffs(InsertIterator b) const {
477
    for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
478
      Value val = glp_get_obj_coef(lp, i);
479
      if (val != 0.0) {
480
        *b = std::make_pair(i, val);
481
        ++b;
482
      }
483
    }
484
  }
485

	
486
  void GlpkBase::_setObjCoeff(int i, Value obj_coef) {
487
    //i = 0 means the constant term (shift)
488
    glp_set_obj_coef(lp, i, obj_coef);
489
  }
490

	
491
  GlpkBase::Value GlpkBase::_getObjCoeff(int i) const {
492
    //i = 0 means the constant term (shift)
493
    return glp_get_obj_coef(lp, i);
494
  }
495

	
496
  void GlpkBase::_setSense(GlpkBase::Sense sense) {
497
    switch (sense) {
498
    case MIN:
499
      glp_set_obj_dir(lp, GLP_MIN);
500
      break;
501
    case MAX:
502
      glp_set_obj_dir(lp, GLP_MAX);
503
      break;
504
    }
505
  }
506

	
507
  GlpkBase::Sense GlpkBase::_getSense() const {
508
    switch(glp_get_obj_dir(lp)) {
509
    case GLP_MIN:
510
      return MIN;
511
    case GLP_MAX:
512
      return MAX;
513
    default:
514
      LEMON_ASSERT(false, "Wrong sense");
515
      return GlpkBase::Sense();
516
    }
517
  }
518

	
519
  void GlpkBase::_clear() {
520
    glp_erase_prob(lp);
521
    rows.clear();
522
    cols.clear();
523
  }
524

	
525
  // LpGlpk members
526

	
527
  LpGlpk::LpGlpk()
528
    : LpBase(), GlpkBase(), LpSolver() {
529
    messageLevel(MESSAGE_NO_OUTPUT);
530
  }
531

	
532
  LpGlpk::LpGlpk(const LpGlpk& other)
533
    : LpBase(other), GlpkBase(other), LpSolver(other) {
534
    messageLevel(MESSAGE_NO_OUTPUT);
535
  }
536

	
537
  LpGlpk* LpGlpk::_newSolver() const { return new LpGlpk; }
538
  LpGlpk* LpGlpk::_cloneSolver() const { return new LpGlpk(*this); }
539

	
540
  const char* LpGlpk::_solverName() const { return "LpGlpk"; }
541

	
542
  void LpGlpk::_clear_temporals() {
543
    _primal_ray.clear();
544
    _dual_ray.clear();
545
  }
546

	
547
  LpGlpk::SolveExitStatus LpGlpk::_solve() {
548
    return solvePrimal();
549
  }
550

	
551
  LpGlpk::SolveExitStatus LpGlpk::solvePrimal() {
552
    _clear_temporals();
553

	
554
    glp_smcp smcp;
555
    glp_init_smcp(&smcp);
556

	
557
    switch (_message_level) {
558
    case MESSAGE_NO_OUTPUT:
559
      smcp.msg_lev = GLP_MSG_OFF;
560
      break;
561
    case MESSAGE_ERROR_MESSAGE:
562
      smcp.msg_lev = GLP_MSG_ERR;
563
      break;
564
    case MESSAGE_NORMAL_OUTPUT:
565
      smcp.msg_lev = GLP_MSG_ON;
566
      break;
567
    case MESSAGE_FULL_OUTPUT:
568
      smcp.msg_lev = GLP_MSG_ALL;
569
      break;
570
    }
571

	
572
    if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
573
    return SOLVED;
574
  }
575

	
576
  LpGlpk::SolveExitStatus LpGlpk::solveDual() {
577
    _clear_temporals();
578

	
579
    glp_smcp smcp;
580
    glp_init_smcp(&smcp);
581

	
582
    switch (_message_level) {
583
    case MESSAGE_NO_OUTPUT:
584
      smcp.msg_lev = GLP_MSG_OFF;
585
      break;
586
    case MESSAGE_ERROR_MESSAGE:
587
      smcp.msg_lev = GLP_MSG_ERR;
588
      break;
589
    case MESSAGE_NORMAL_OUTPUT:
590
      smcp.msg_lev = GLP_MSG_ON;
591
      break;
592
    case MESSAGE_FULL_OUTPUT:
593
      smcp.msg_lev = GLP_MSG_ALL;
594
      break;
595
    }
596
    smcp.meth = GLP_DUAL;
597

	
598
    if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
599
    return SOLVED;
600
  }
601

	
602
  LpGlpk::Value LpGlpk::_getPrimal(int i) const {
603
    return glp_get_col_prim(lp, i);
604
  }
605

	
606
  LpGlpk::Value LpGlpk::_getDual(int i) const {
607
    return glp_get_row_dual(lp, i);
608
  }
609

	
610
  LpGlpk::Value LpGlpk::_getPrimalValue() const {
611
    return glp_get_obj_val(lp);
612
  }
613

	
614
  LpGlpk::VarStatus LpGlpk::_getColStatus(int i) const {
615
    switch (glp_get_col_stat(lp, i)) {
616
    case GLP_BS:
617
      return BASIC;
618
    case GLP_UP:
619
      return UPPER;
620
    case GLP_LO:
621
      return LOWER;
622
    case GLP_NF:
623
      return FREE;
624
    case GLP_NS:
625
      return FIXED;
626
    default:
627
      LEMON_ASSERT(false, "Wrong column status");
628
      return LpGlpk::VarStatus();
629
    }
630
  }
631

	
632
  LpGlpk::VarStatus LpGlpk::_getRowStatus(int i) const {
633
    switch (glp_get_row_stat(lp, i)) {
634
    case GLP_BS:
635
      return BASIC;
636
    case GLP_UP:
637
      return UPPER;
638
    case GLP_LO:
639
      return LOWER;
640
    case GLP_NF:
641
      return FREE;
642
    case GLP_NS:
643
      return FIXED;
644
    default:
645
      LEMON_ASSERT(false, "Wrong row status");
646
      return LpGlpk::VarStatus();
647
    }
648
  }
649

	
650
  LpGlpk::Value LpGlpk::_getPrimalRay(int i) const {
651
    if (_primal_ray.empty()) {
652
      int row_num = glp_get_num_rows(lp);
653
      int col_num = glp_get_num_cols(lp);
654

	
655
      _primal_ray.resize(col_num + 1, 0.0);
656

	
657
      int index = glp_get_unbnd_ray(lp);
658
      if (index != 0) {
659
        // The primal ray is found in primal simplex second phase
660
        LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
661
                      glp_get_col_stat(lp, index - row_num)) != GLP_BS,
662
                     "Wrong primal ray");
663

	
664
        bool negate = glp_get_obj_dir(lp) == GLP_MAX;
665

	
666
        if (index > row_num) {
667
          _primal_ray[index - row_num] = 1.0;
668
          if (glp_get_col_dual(lp, index - row_num) > 0) {
669
            negate = !negate;
670
          }
671
        } else {
672
          if (glp_get_row_dual(lp, index) > 0) {
673
            negate = !negate;
674
          }
675
        }
676

	
677
        std::vector<int> ray_indexes(row_num + 1);
678
        std::vector<Value> ray_values(row_num + 1);
679
        int ray_length = glp_eval_tab_col(lp, index, &ray_indexes.front(),
680
                                          &ray_values.front());
681

	
682
        for (int i = 1; i <= ray_length; ++i) {
683
          if (ray_indexes[i] > row_num) {
684
            _primal_ray[ray_indexes[i] - row_num] = ray_values[i];
685
          }
686
        }
687

	
688
        if (negate) {
689
          for (int i = 1; i <= col_num; ++i) {
690
            _primal_ray[i] = - _primal_ray[i];
691
          }
692
        }
693
      } else {
694
        for (int i = 1; i <= col_num; ++i) {
695
          _primal_ray[i] = glp_get_col_prim(lp, i);
696
        }
697
      }
698
    }
699
    return _primal_ray[i];
700
  }
701

	
702
  LpGlpk::Value LpGlpk::_getDualRay(int i) const {
703
    if (_dual_ray.empty()) {
704
      int row_num = glp_get_num_rows(lp);
705

	
706
      _dual_ray.resize(row_num + 1, 0.0);
707

	
708
      int index = glp_get_unbnd_ray(lp);
709
      if (index != 0) {
710
        // The dual ray is found in dual simplex second phase
711
        LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
712
                      glp_get_col_stat(lp, index - row_num)) == GLP_BS,
713

	
714
                     "Wrong dual ray");
715

	
716
        int idx;
717
        bool negate = false;
718

	
719
        if (index > row_num) {
720
          idx = glp_get_col_bind(lp, index - row_num);
721
          if (glp_get_col_prim(lp, index - row_num) >
722
              glp_get_col_ub(lp, index - row_num)) {
723
            negate = true;
724
          }
725
        } else {
726
          idx = glp_get_row_bind(lp, index);
727
          if (glp_get_row_prim(lp, index) > glp_get_row_ub(lp, index)) {
728
            negate = true;
729
          }
730
        }
731

	
732
        _dual_ray[idx] = negate ?  - 1.0 : 1.0;
733

	
734
        glp_btran(lp, &_dual_ray.front());
735
      } else {
736
        double eps = 1e-7;
737
        // The dual ray is found in primal simplex first phase
738
        // We assume that the glpk minimizes the slack to get feasible solution
739
        for (int i = 1; i <= row_num; ++i) {
740
          int index = glp_get_bhead(lp, i);
741
          if (index <= row_num) {
742
            double res = glp_get_row_prim(lp, index);
743
            if (res > glp_get_row_ub(lp, index) + eps) {
744
              _dual_ray[i] = -1;
745
            } else if (res < glp_get_row_lb(lp, index) - eps) {
746
              _dual_ray[i] = 1;
747
            } else {
748
              _dual_ray[i] = 0;
749
            }
750
            _dual_ray[i] *= glp_get_rii(lp, index);
751
          } else {
752
            double res = glp_get_col_prim(lp, index - row_num);
753
            if (res > glp_get_col_ub(lp, index - row_num) + eps) {
754
              _dual_ray[i] = -1;
755
            } else if (res < glp_get_col_lb(lp, index - row_num) - eps) {
756
              _dual_ray[i] = 1;
757
            } else {
758
              _dual_ray[i] = 0;
759
            }
760
            _dual_ray[i] /= glp_get_sjj(lp, index - row_num);
761
          }
762
        }
763

	
764
        glp_btran(lp, &_dual_ray.front());
765

	
766
        for (int i = 1; i <= row_num; ++i) {
767
          _dual_ray[i] /= glp_get_rii(lp, i);
768
        }
769
      }
770
    }
771
    return _dual_ray[i];
772
  }
773

	
774
  LpGlpk::ProblemType LpGlpk::_getPrimalType() const {
775
    if (glp_get_status(lp) == GLP_OPT)
776
      return OPTIMAL;
777
    switch (glp_get_prim_stat(lp)) {
778
    case GLP_UNDEF:
779
      return UNDEFINED;
780
    case GLP_FEAS:
781
    case GLP_INFEAS:
782
      if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
783
        return UNBOUNDED;
784
      } else {
785
        return UNDEFINED;
786
      }
787
    case GLP_NOFEAS:
788
      return INFEASIBLE;
789
    default:
790
      LEMON_ASSERT(false, "Wrong primal type");
791
      return  LpGlpk::ProblemType();
792
    }
793
  }
794

	
795
  LpGlpk::ProblemType LpGlpk::_getDualType() const {
796
    if (glp_get_status(lp) == GLP_OPT)
797
      return OPTIMAL;
798
    switch (glp_get_dual_stat(lp)) {
799
    case GLP_UNDEF:
800
      return UNDEFINED;
801
    case GLP_FEAS:
802
    case GLP_INFEAS:
803
      if (glp_get_prim_stat(lp) == GLP_NOFEAS) {
804
        return UNBOUNDED;
805
      } else {
806
        return UNDEFINED;
807
      }
808
    case GLP_NOFEAS:
809
      return INFEASIBLE;
810
    default:
811
      LEMON_ASSERT(false, "Wrong primal type");
812
      return  LpGlpk::ProblemType();
813
    }
814
  }
815

	
816
  void LpGlpk::presolver(bool b) {
817
    lpx_set_int_parm(lp, LPX_K_PRESOL, b ? 1 : 0);
818
  }
819

	
820
  void LpGlpk::messageLevel(MessageLevel m) {
821
    _message_level = m;
822
  }
823

	
824
  // MipGlpk members
825

	
826
  MipGlpk::MipGlpk()
827
    : LpBase(), GlpkBase(), MipSolver() {
828
    messageLevel(MESSAGE_NO_OUTPUT);
829
  }
830

	
831
  MipGlpk::MipGlpk(const MipGlpk& other)
832
    : LpBase(), GlpkBase(other), MipSolver() {
833
    messageLevel(MESSAGE_NO_OUTPUT);
834
  }
835

	
836
  void MipGlpk::_setColType(int i, MipGlpk::ColTypes col_type) {
837
    switch (col_type) {
838
    case INTEGER:
839
      glp_set_col_kind(lp, i, GLP_IV);
840
      break;
841
    case REAL:
842
      glp_set_col_kind(lp, i, GLP_CV);
843
      break;
844
    }
845
  }
846

	
847
  MipGlpk::ColTypes MipGlpk::_getColType(int i) const {
848
    switch (glp_get_col_kind(lp, i)) {
849
    case GLP_IV:
850
    case GLP_BV:
851
      return INTEGER;
852
    default:
853
      return REAL;
854
    }
855

	
856
  }
857

	
858
  MipGlpk::SolveExitStatus MipGlpk::_solve() {
859
    glp_smcp smcp;
860
    glp_init_smcp(&smcp);
861

	
862
    switch (_message_level) {
863
    case MESSAGE_NO_OUTPUT:
864
      smcp.msg_lev = GLP_MSG_OFF;
865
      break;
866
    case MESSAGE_ERROR_MESSAGE:
867
      smcp.msg_lev = GLP_MSG_ERR;
868
      break;
869
    case MESSAGE_NORMAL_OUTPUT:
870
      smcp.msg_lev = GLP_MSG_ON;
871
      break;
872
    case MESSAGE_FULL_OUTPUT:
873
      smcp.msg_lev = GLP_MSG_ALL;
874
      break;
875
    }
876
    smcp.meth = GLP_DUAL;
877

	
878
    if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
879
    if (glp_get_status(lp) != GLP_OPT) return SOLVED;
880

	
881
    glp_iocp iocp;
882
    glp_init_iocp(&iocp);
883

	
884
    switch (_message_level) {
885
    case MESSAGE_NO_OUTPUT:
886
      iocp.msg_lev = GLP_MSG_OFF;
887
      break;
888
    case MESSAGE_ERROR_MESSAGE:
889
      iocp.msg_lev = GLP_MSG_ERR;
890
      break;
891
    case MESSAGE_NORMAL_OUTPUT:
892
      iocp.msg_lev = GLP_MSG_ON;
893
      break;
894
    case MESSAGE_FULL_OUTPUT:
895
      iocp.msg_lev = GLP_MSG_ALL;
896
      break;
897
    }
898

	
899
    if (glp_intopt(lp, &iocp) != 0) return UNSOLVED;
900
    return SOLVED;
901
  }
902

	
903

	
904
  MipGlpk::ProblemType MipGlpk::_getType() const {
905
    switch (glp_get_status(lp)) {
906
    case GLP_OPT:
907
      switch (glp_mip_status(lp)) {
908
      case GLP_UNDEF:
909
        return UNDEFINED;
910
      case GLP_NOFEAS:
911
        return INFEASIBLE;
912
      case GLP_FEAS:
913
        return FEASIBLE;
914
      case GLP_OPT:
915
        return OPTIMAL;
916
      default:
917
        LEMON_ASSERT(false, "Wrong problem type.");
918
        return MipGlpk::ProblemType();
919
      }
920
    case GLP_NOFEAS:
921
      return INFEASIBLE;
922
    case GLP_INFEAS:
923
    case GLP_FEAS:
924
      if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
925
        return UNBOUNDED;
926
      } else {
927
        return UNDEFINED;
928
      }
929
    default:
930
      LEMON_ASSERT(false, "Wrong problem type.");
931
      return MipGlpk::ProblemType();
932
    }
933
  }
934

	
935
  MipGlpk::Value MipGlpk::_getSol(int i) const {
936
    return glp_mip_col_val(lp, i);
937
  }
938

	
939
  MipGlpk::Value MipGlpk::_getSolValue() const {
940
    return glp_mip_obj_val(lp);
941
  }
942

	
943
  MipGlpk* MipGlpk::_newSolver() const { return new MipGlpk; }
944
  MipGlpk* MipGlpk::_cloneSolver() const {return new MipGlpk(*this); }
945

	
946
  const char* MipGlpk::_solverName() const { return "MipGlpk"; }
947

	
948
  void MipGlpk::messageLevel(MessageLevel m) {
949
    _message_level = m;
950
  }
951

	
952
} //END OF NAMESPACE LEMON
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#ifndef LEMON_GLPK_H
20
#define LEMON_GLPK_H
21

	
22
///\file
23
///\brief Header of the LEMON-GLPK lp solver interface.
24
///\ingroup lp_group
25

	
26
#include <lemon/lp_base.h>
27

	
28
// forward declaration
29
#ifndef _GLP_PROB
30
#define _GLP_PROB
31
typedef struct { double _prob; } glp_prob;
32
/* LP/MIP problem object */
33
#endif
34

	
35
namespace lemon {
36

	
37

	
38
  /// \brief Base interface for the GLPK LP and MIP solver
39
  ///
40
  /// This class implements the common interface of the GLPK LP and MIP solver.
41
  /// \ingroup lp_group
42
  class GlpkBase : virtual public LpBase {
43
  protected:
44

	
45
    typedef glp_prob LPX;
46
    glp_prob* lp;
47

	
48
    GlpkBase();
49
    GlpkBase(const GlpkBase&);
50
    virtual ~GlpkBase();
51

	
52
  protected:
53

	
54
    virtual int _addCol();
55
    virtual int _addRow();
56

	
57
    virtual void _eraseCol(int i);
58
    virtual void _eraseRow(int i);
59

	
60
    virtual void _eraseColId(int i);
61
    virtual void _eraseRowId(int i);
62

	
63
    virtual void _getColName(int col, std::string& name) const;
64
    virtual void _setColName(int col, const std::string& name);
65
    virtual int _colByName(const std::string& name) const;
66

	
67
    virtual void _getRowName(int row, std::string& name) const;
68
    virtual void _setRowName(int row, const std::string& name);
69
    virtual int _rowByName(const std::string& name) const;
70

	
71
    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
72
    virtual void _getRowCoeffs(int i, InsertIterator b) const;
73

	
74
    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
75
    virtual void _getColCoeffs(int i, InsertIterator b) const;
76

	
77
    virtual void _setCoeff(int row, int col, Value value);
78
    virtual Value _getCoeff(int row, int col) const;
79

	
80
    virtual void _setColLowerBound(int i, Value value);
81
    virtual Value _getColLowerBound(int i) const;
82

	
83
    virtual void _setColUpperBound(int i, Value value);
84
    virtual Value _getColUpperBound(int i) const;
85

	
86
    virtual void _setRowLowerBound(int i, Value value);
87
    virtual Value _getRowLowerBound(int i) const;
88

	
89
    virtual void _setRowUpperBound(int i, Value value);
90
    virtual Value _getRowUpperBound(int i) const;
91

	
92
    virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
93
    virtual void _getObjCoeffs(InsertIterator b) const;
94

	
95
    virtual void _setObjCoeff(int i, Value obj_coef);
96
    virtual Value _getObjCoeff(int i) const;
97

	
98
    virtual void _setSense(Sense);
99
    virtual Sense _getSense() const;
100

	
101
    virtual void _clear();
102

	
103
  public:
104

	
105
    ///Pointer to the underlying GLPK data structure.
106
    LPX *lpx() {return lp;}
107
    ///Const pointer to the underlying GLPK data structure.
108
    const LPX *lpx() const {return lp;}
109

	
110
    ///Returns the constraint identifier understood by GLPK.
111
    int lpxRow(Row r) const { return rows(id(r)); }
112

	
113
    ///Returns the variable identifier understood by GLPK.
114
    int lpxCol(Col c) const { return cols(id(c)); }
115

	
116
  };
117

	
118
  /// \brief Interface for the GLPK LP solver
119
  ///
120
  /// This class implements an interface for the GLPK LP solver.
121
  ///\ingroup lp_group
122
  class LpGlpk : public GlpkBase, public LpSolver {
123
  public:
124

	
125
    ///\e
126
    LpGlpk();
127
    ///\e
128
    LpGlpk(const LpGlpk&);
129

	
130
  private:
131

	
132
    mutable std::vector<double> _primal_ray;
133
    mutable std::vector<double> _dual_ray;
134

	
135
    void _clear_temporals();
136

	
137
  protected:
138

	
139
    virtual LpGlpk* _cloneSolver() const;
140
    virtual LpGlpk* _newSolver() const;
141

	
142
    virtual const char* _solverName() const;
143

	
144
    virtual SolveExitStatus _solve();
145
    virtual Value _getPrimal(int i) const;
146
    virtual Value _getDual(int i) const;
147

	
148
    virtual Value _getPrimalValue() const;
149

	
150
    virtual VarStatus _getColStatus(int i) const;
151
    virtual VarStatus _getRowStatus(int i) const;
152

	
153
    virtual Value _getPrimalRay(int i) const;
154
    virtual Value _getDualRay(int i) const;
155

	
156
    ///\todo It should be clarified
157
    ///
158
    virtual ProblemType _getPrimalType() const;
159
    virtual ProblemType _getDualType() const;
160

	
161
  public:
162

	
163
    ///Solve with primal simplex
164
    SolveExitStatus solvePrimal();
165

	
166
    ///Solve with dual simplex
167
    SolveExitStatus solveDual();
168

	
169
    ///Turns on or off the presolver
170

	
171
    ///Turns on (\c b is \c true) or off (\c b is \c false) the presolver
172
    ///
173
    ///The presolver is off by default.
174
    void presolver(bool b);
175

	
176
    ///Enum for \c messageLevel() parameter
177
    enum MessageLevel {
178
      /// no output (default value)
179
      MESSAGE_NO_OUTPUT = 0,
180
      /// error messages only
181
      MESSAGE_ERROR_MESSAGE = 1,
182
      /// normal output
183
      MESSAGE_NORMAL_OUTPUT = 2,
184
      /// full output (includes informational messages)
185
      MESSAGE_FULL_OUTPUT = 3
186
    };
187

	
188
  private:
189

	
190
    MessageLevel _message_level;
191

	
192
  public:
193

	
194
    ///Set the verbosity of the messages
195

	
196
    ///Set the verbosity of the messages
197
    ///
198
    ///\param m is the level of the messages output by the solver routines.
199
    void messageLevel(MessageLevel m);
200
  };
201

	
202
  /// \brief Interface for the GLPK MIP solver
203
  ///
204
  /// This class implements an interface for the GLPK MIP solver.
205
  ///\ingroup lp_group
206
  class MipGlpk : public GlpkBase, public MipSolver {
207
  public:
208

	
209
    ///\e
210
    MipGlpk();
211
    ///\e
212
    MipGlpk(const MipGlpk&);
213

	
214
  protected:
215

	
216
    virtual MipGlpk* _cloneSolver() const;
217
    virtual MipGlpk* _newSolver() const;
218

	
219
    virtual const char* _solverName() const;
220

	
221
    virtual ColTypes _getColType(int col) const;
222
    virtual void _setColType(int col, ColTypes col_type);
223

	
224
    virtual SolveExitStatus _solve();
225
    virtual ProblemType _getType() const;
226
    virtual Value _getSol(int i) const;
227
    virtual Value _getSolValue() const;
228

	
229
    ///Enum for \c messageLevel() parameter
230
    enum MessageLevel {
231
      /// no output (default value)
232
      MESSAGE_NO_OUTPUT = 0,
233
      /// error messages only
234
      MESSAGE_ERROR_MESSAGE = 1,
235
      /// normal output
236
      MESSAGE_NORMAL_OUTPUT = 2,
237
      /// full output (includes informational messages)
238
      MESSAGE_FULL_OUTPUT = 3
239
    };
240

	
241
  private:
242

	
243
    MessageLevel _message_level;
244

	
245
  public:
246

	
247
    ///Set the verbosity of the messages
248

	
249
    ///Set the verbosity of the messages
250
    ///
251
    ///\param m is the level of the messages output by the solver routines.
252
    void messageLevel(MessageLevel m);
253
  };
254

	
255

	
256
} //END OF NAMESPACE LEMON
257

	
258
#endif //LEMON_GLPK_H
259

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#include <iostream>
20
#include <lemon/soplex.h>
21

	
22
#include <soplex/soplex.h>
23

	
24

	
25
///\file
26
///\brief Implementation of the LEMON-SOPLEX lp solver interface.
27
namespace lemon {
28

	
29
  LpSoplex::LpSoplex() {
30
    soplex = new soplex::SoPlex;
31
  }
32

	
33
  LpSoplex::~LpSoplex() {
34
    delete soplex;
35
  }
36

	
37
  LpSoplex::LpSoplex(const LpSoplex& lp) {
38
    rows = lp.rows;
39
    cols = lp.cols;
40

	
41
    soplex = new soplex::SoPlex;
42
    (*static_cast<soplex::SPxLP*>(soplex)) = *(lp.soplex);
43

	
44
    _col_names = lp._col_names;
45
    _col_names_ref = lp._col_names_ref;
46

	
47
    _row_names = lp._row_names;
48
    _row_names_ref = lp._row_names_ref;
49

	
50
  }
51

	
52
  void LpSoplex::_clear_temporals() {
53
    _primal_values.clear();
54
    _dual_values.clear();
55
  }
56

	
57
  LpSoplex* LpSoplex::_newSolver() const {
58
    LpSoplex* newlp = new LpSoplex();
59
    return newlp;
60
  }
61

	
62
  LpSoplex* LpSoplex::_cloneSolver() const {
63
    LpSoplex* newlp = new LpSoplex(*this);
64
    return newlp;
65
  }
66

	
67
  const char* LpSoplex::_solverName() const { return "LpSoplex"; }
68

	
69
  int LpSoplex::_addCol() {
70
    soplex::LPCol c;
71
    c.setLower(-soplex::infinity);
72
    c.setUpper(soplex::infinity);
73
    soplex->addCol(c);
74

	
75
    _col_names.push_back(std::string());
76

	
77
    return soplex->nCols() - 1;
78
  }
79

	
80
  int LpSoplex::_addRow() {
81
    soplex::LPRow r;
82
    r.setLhs(-soplex::infinity);
83
    r.setRhs(soplex::infinity);
84
    soplex->addRow(r);
85

	
86
    _row_names.push_back(std::string());
87

	
88
    return soplex->nRows() - 1;
89
  }
90

	
91

	
92
  void LpSoplex::_eraseCol(int i) {
93
    soplex->removeCol(i);
94
    _col_names_ref.erase(_col_names[i]);
95
    _col_names[i] = _col_names.back();
96
    _col_names_ref[_col_names.back()] = i;
97
    _col_names.pop_back();
98
  }
99

	
100
  void LpSoplex::_eraseRow(int i) {
101
    soplex->removeRow(i);
102
    _row_names_ref.erase(_row_names[i]);
103
    _row_names[i] = _row_names.back();
104
    _row_names_ref[_row_names.back()] = i;
105
    _row_names.pop_back();
106
  }
107

	
108
  void LpSoplex::_eraseColId(int i) {
109
    cols.eraseIndex(i);
110
    cols.relocateIndex(i, cols.maxIndex());
111
  }
112
  void LpSoplex::_eraseRowId(int i) {
113
    rows.eraseIndex(i);
114
    rows.relocateIndex(i, rows.maxIndex());
115
  }
116

	
117
  void LpSoplex::_getColName(int c, std::string &name) const {
118
    name = _col_names[c];
119
  }
120

	
121
  void LpSoplex::_setColName(int c, const std::string &name) {
122
    _col_names_ref.erase(_col_names[c]);
123
    _col_names[c] = name;
124
    if (!name.empty()) {
125
      _col_names_ref.insert(std::make_pair(name, c));
126
    }
127
  }
128

	
129
  int LpSoplex::_colByName(const std::string& name) const {
130
    std::map<std::string, int>::const_iterator it =
131
      _col_names_ref.find(name);
132
    if (it != _col_names_ref.end()) {
133
      return it->second;
134
    } else {
135
      return -1;
136
    }
137
  }
138

	
139
  void LpSoplex::_getRowName(int r, std::string &name) const {
140
    name = _row_names[r];
141
  }
142

	
143
  void LpSoplex::_setRowName(int r, const std::string &name) {
144
    _row_names_ref.erase(_row_names[r]);
145
    _row_names[r] = name;
146
    if (!name.empty()) {
147
      _row_names_ref.insert(std::make_pair(name, r));
148
    }
149
  }
150

	
151
  int LpSoplex::_rowByName(const std::string& name) const {
152
    std::map<std::string, int>::const_iterator it =
153
      _row_names_ref.find(name);
154
    if (it != _row_names_ref.end()) {
155
      return it->second;
156
    } else {
157
      return -1;
158
    }
159
  }
160

	
161

	
162
  void LpSoplex::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
163
    for (int j = 0; j < soplex->nCols(); ++j) {
164
      soplex->changeElement(i, j, 0.0);
165
    }
166
    for(ExprIterator it = b; it != e; ++it) {
167
      soplex->changeElement(i, it->first, it->second);
168
    }
169
  }
170

	
171
  void LpSoplex::_getRowCoeffs(int i, InsertIterator b) const {
172
    const soplex::SVector& vec = soplex->rowVector(i);
173
    for (int k = 0; k < vec.size(); ++k) {
174
      *b = std::make_pair(vec.index(k), vec.value(k));
175
      ++b;
176
    }
177
  }
178

	
179
  void LpSoplex::_setColCoeffs(int j, ExprIterator b, ExprIterator e) {
180
    for (int i = 0; i < soplex->nRows(); ++i) {
181
      soplex->changeElement(i, j, 0.0);
182
    }
183
    for(ExprIterator it = b; it != e; ++it) {
184
      soplex->changeElement(it->first, j, it->second);
185
    }
186
  }
187

	
188
  void LpSoplex::_getColCoeffs(int i, InsertIterator b) const {
189
    const soplex::SVector& vec = soplex->colVector(i);
190
    for (int k = 0; k < vec.size(); ++k) {
191
      *b = std::make_pair(vec.index(k), vec.value(k));
192
      ++b;
193
    }
194
  }
195

	
196
  void LpSoplex::_setCoeff(int i, int j, Value value) {
197
    soplex->changeElement(i, j, value);
198
  }
199

	
200
  LpSoplex::Value LpSoplex::_getCoeff(int i, int j) const {
201
    return soplex->rowVector(i)[j];
202
  }
203

	
204
  void LpSoplex::_setColLowerBound(int i, Value value) {
205
    LEMON_ASSERT(value != INF, "Invalid bound");
206
    soplex->changeLower(i, value != -INF ? value : -soplex::infinity);
207
  }
208

	
209
  LpSoplex::Value LpSoplex::_getColLowerBound(int i) const {
210
    double value = soplex->lower(i);
211
    return value != -soplex::infinity ? value : -INF;
212
  }
213

	
214
  void LpSoplex::_setColUpperBound(int i, Value value) {
215
    LEMON_ASSERT(value != -INF, "Invalid bound");
216
    soplex->changeUpper(i, value != INF ? value : soplex::infinity);
217
  }
218

	
219
  LpSoplex::Value LpSoplex::_getColUpperBound(int i) const {
220
    double value = soplex->upper(i);
221
    return value != soplex::infinity ? value : INF;
222
  }
223

	
224
  void LpSoplex::_setRowLowerBound(int i, Value lb) {
225
    LEMON_ASSERT(lb != INF, "Invalid bound");
226
    soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, soplex->rhs(i));
227
  }
228

	
229
  LpSoplex::Value LpSoplex::_getRowLowerBound(int i) const {
230
    double res = soplex->lhs(i);
231
    return res == -soplex::infinity ? -INF : res;
232
  }
233

	
234
  void LpSoplex::_setRowUpperBound(int i, Value ub) {
235
    LEMON_ASSERT(ub != -INF, "Invalid bound");
236
    soplex->changeRange(i, soplex->lhs(i), ub != INF ? ub : soplex::infinity);
237
  }
238

	
239
  LpSoplex::Value LpSoplex::_getRowUpperBound(int i) const {
240
    double res = soplex->rhs(i);
241
    return res == soplex::infinity ? INF : res;
242
  }
243

	
244
  void LpSoplex::_setObjCoeffs(ExprIterator b, ExprIterator e) {
245
    for (int j = 0; j < soplex->nCols(); ++j) {
246
      soplex->changeObj(j, 0.0);
247
    }
248
    for (ExprIterator it = b; it != e; ++it) {
249
      soplex->changeObj(it->first, it->second);
250
    }
251
  }
252

	
253
  void LpSoplex::_getObjCoeffs(InsertIterator b) const {
254
    for (int j = 0; j < soplex->nCols(); ++j) {
255
      Value coef = soplex->obj(j);
256
      if (coef != 0.0) {
257
        *b = std::make_pair(j, coef);
258
        ++b;
259
      }
260
    }
261
  }
262

	
263
  void LpSoplex::_setObjCoeff(int i, Value obj_coef) {
264
    soplex->changeObj(i, obj_coef);
265
  }
266

	
267
  LpSoplex::Value LpSoplex::_getObjCoeff(int i) const {
268
    return soplex->obj(i);
269
  }
270

	
271
  LpSoplex::SolveExitStatus LpSoplex::_solve() {
272

	
273
    _clear_temporals();
274

	
275
    soplex::SPxSolver::Status status = soplex->solve();
276

	
277
    switch (status) {
278
    case soplex::SPxSolver::OPTIMAL:
279
    case soplex::SPxSolver::INFEASIBLE:
280
    case soplex::SPxSolver::UNBOUNDED:
281
      return SOLVED;
282
    default:
283
      return UNSOLVED;
284
    }
285
  }
286

	
287
  LpSoplex::Value LpSoplex::_getPrimal(int i) const {
288
    if (_primal_values.empty()) {
289
      _primal_values.resize(soplex->nCols());
290
      soplex::Vector pv(_primal_values.size(), &_primal_values.front());
291
      soplex->getPrimal(pv);
292
    }
293
    return _primal_values[i];
294
  }
295

	
296
  LpSoplex::Value LpSoplex::_getDual(int i) const {
297
    if (_dual_values.empty()) {
298
      _dual_values.resize(soplex->nRows());
299
      soplex::Vector dv(_dual_values.size(), &_dual_values.front());
300
      soplex->getDual(dv);
301
    }
302
    return _dual_values[i];
303
  }
304

	
305
  LpSoplex::Value LpSoplex::_getPrimalValue() const {
306
    return soplex->objValue();
307
  }
308

	
309
  LpSoplex::VarStatus LpSoplex::_getColStatus(int i) const {
310
    switch (soplex->getBasisColStatus(i)) {
311
    case soplex::SPxSolver::BASIC:
312
      return BASIC;
313
    case soplex::SPxSolver::ON_UPPER:
314
      return UPPER;
315
    case soplex::SPxSolver::ON_LOWER:
316
      return LOWER;
317
    case soplex::SPxSolver::FIXED:
318
      return FIXED;
319
    case soplex::SPxSolver::ZERO:
320
      return FREE;
321
    default:
322
      LEMON_ASSERT(false, "Wrong column status");
323
      return VarStatus();
324
    }
325
  }
326

	
327
  LpSoplex::VarStatus LpSoplex::_getRowStatus(int i) const {
328
    switch (soplex->getBasisRowStatus(i)) {
329
    case soplex::SPxSolver::BASIC:
330
      return BASIC;
331
    case soplex::SPxSolver::ON_UPPER:
332
      return UPPER;
333
    case soplex::SPxSolver::ON_LOWER:
334
      return LOWER;
335
    case soplex::SPxSolver::FIXED:
336
      return FIXED;
337
    case soplex::SPxSolver::ZERO:
338
      return FREE;
339
    default:
340
      LEMON_ASSERT(false, "Wrong row status");
341
      return VarStatus();
342
    }
343
  }
344

	
345
  LpSoplex::Value LpSoplex::_getPrimalRay(int i) const {
346
    if (_primal_ray.empty()) {
347
      _primal_ray.resize(soplex->nCols());
348
      soplex::Vector pv(_primal_ray.size(), &_primal_ray.front());
349
      soplex->getDualfarkas(pv);
350
    }
351
    return _primal_ray[i];
352
  }
353

	
354
  LpSoplex::Value LpSoplex::_getDualRay(int i) const {
355
    if (_dual_ray.empty()) {
356
      _dual_ray.resize(soplex->nRows());
357
      soplex::Vector dv(_dual_ray.size(), &_dual_ray.front());
358
      soplex->getDualfarkas(dv);
359
    }
360
    return _dual_ray[i];
361
  }
362

	
363
  LpSoplex::ProblemType LpSoplex::_getPrimalType() const {
364
    switch (soplex->status()) {
365
    case soplex::SPxSolver::OPTIMAL:
366
      return OPTIMAL;
367
    case soplex::SPxSolver::UNBOUNDED:
368
      return UNBOUNDED;
369
    case soplex::SPxSolver::INFEASIBLE:
370
      return INFEASIBLE;
371
    default:
372
      return UNDEFINED;
373
    }
374
  }
375

	
376
  LpSoplex::ProblemType LpSoplex::_getDualType() const {
377
    switch (soplex->status()) {
378
    case soplex::SPxSolver::OPTIMAL:
379
      return OPTIMAL;
380
    case soplex::SPxSolver::UNBOUNDED:
381
      return UNBOUNDED;
382
    case soplex::SPxSolver::INFEASIBLE:
383
      return INFEASIBLE;
384
    default:
385
      return UNDEFINED;
386
    }
387
  }
388

	
389
  void LpSoplex::_setSense(Sense sense) {
390
    switch (sense) {
391
    case MIN:
392
      soplex->changeSense(soplex::SPxSolver::MINIMIZE);
393
      break;
394
    case MAX:
395
      soplex->changeSense(soplex::SPxSolver::MAXIMIZE);
396
    }
397
  }
398

	
399
  LpSoplex::Sense LpSoplex::_getSense() const {
400
    switch (soplex->spxSense()) {
401
    case soplex::SPxSolver::MAXIMIZE:
402
      return MAX;
403
    case soplex::SPxSolver::MINIMIZE:
404
      return MIN;
405
    default:
406
      LEMON_ASSERT(false, "Wrong sense.");
407
      return LpSoplex::Sense();
408
    }
409
  }
410

	
411
  void LpSoplex::_clear() {
412
    soplex->clear();
413
    _col_names.clear();
414
    _col_names_ref.clear();
415
    _row_names.clear();
416
    _row_names_ref.clear();
417
    cols.clear();
418
    rows.clear();
419
    _clear_temporals();
420
  }
421

	
422
} //namespace lemon
423

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#ifndef LEMON_SOPLEX_H
20
#define LEMON_SOPLEX_H
21

	
22
///\file
23
///\brief Header of the LEMON-SOPLEX lp solver interface.
24

	
25
#include <vector>
26
#include <string>
27

	
28
#include <lemon/lp_base.h>
29

	
30
// Forward declaration
31
namespace soplex {
32
  class SoPlex;
33
}
34

	
35
namespace lemon {
36

	
37
  /// \ingroup lp_group
38
  ///
39
  /// \brief Interface for the SOPLEX solver
40
  ///
41
  /// This class implements an interface for the SoPlex LP solver.
42
  /// The SoPlex library is an object oriented lp solver library
43
  /// developed at the Konrad-Zuse-Zentrum f�r Informationstechnik
44
  /// Berlin (ZIB). You can find detailed information about it at the
45
  /// <tt>http://soplex.zib.de</tt> address.
46
  class LpSoplex : public LpSolver {
47
  private:
48

	
49
    soplex::SoPlex* soplex;
50

	
51
    std::vector<std::string> _col_names;
52
    std::map<std::string, int> _col_names_ref;
53

	
54
    std::vector<std::string> _row_names;
55
    std::map<std::string, int> _row_names_ref;
56

	
57
  private:
58

	
59
    // these values cannot be retrieved element by element
60
    mutable std::vector<Value> _primal_values;
61
    mutable std::vector<Value> _dual_values;
62

	
63
    mutable std::vector<Value> _primal_ray;
64
    mutable std::vector<Value> _dual_ray;
65

	
66
    void _clear_temporals();
67

	
68
  public:
69

	
70
    /// \e
71
    LpSoplex();
72
    /// \e
73
    LpSoplex(const LpSoplex&);
74
    /// \e
75
    ~LpSoplex();
76

	
77
  protected:
78

	
79
    virtual LpSoplex* _newSolver() const;
80
    virtual LpSoplex* _cloneSolver() const;
81

	
82
    virtual const char* _solverName() const;
83

	
84
    virtual int _addCol();
85
    virtual int _addRow();
86

	
87
    virtual void _eraseCol(int i);
88
    virtual void _eraseRow(int i);
89

	
90
    virtual void _eraseColId(int i);
91
    virtual void _eraseRowId(int i);
92

	
93
    virtual void _getColName(int col, std::string& name) const;
94
    virtual void _setColName(int col, const std::string& name);
95
    virtual int _colByName(const std::string& name) const;
96

	
97
    virtual void _getRowName(int row, std::string& name) const;
98
    virtual void _setRowName(int row, const std::string& name);
99
    virtual int _rowByName(const std::string& name) const;
100

	
101
    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
102
    virtual void _getRowCoeffs(int i, InsertIterator b) const;
103

	
104
    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
105
    virtual void _getColCoeffs(int i, InsertIterator b) const;
106

	
107
    virtual void _setCoeff(int row, int col, Value value);
108
    virtual Value _getCoeff(int row, int col) const;
109

	
110
    virtual void _setColLowerBound(int i, Value value);
111
    virtual Value _getColLowerBound(int i) const;
112
    virtual void _setColUpperBound(int i, Value value);
113
    virtual Value _getColUpperBound(int i) const;
114

	
115
    virtual void _setRowLowerBound(int i, Value value);
116
    virtual Value _getRowLowerBound(int i) const;
117
    virtual void _setRowUpperBound(int i, Value value);
118
    virtual Value _getRowUpperBound(int i) const;
119

	
120
    virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
121
    virtual void _getObjCoeffs(InsertIterator b) const;
122

	
123
    virtual void _setObjCoeff(int i, Value obj_coef);
124
    virtual Value _getObjCoeff(int i) const;
125

	
126
    virtual void _setSense(Sense sense);
127
    virtual Sense _getSense() const;
128

	
129
    virtual SolveExitStatus _solve();
130
    virtual Value _getPrimal(int i) const;
131
    virtual Value _getDual(int i) const;
132

	
133
    virtual Value _getPrimalValue() const;
134

	
135
    virtual Value _getPrimalRay(int i) const;
136
    virtual Value _getDualRay(int i) const;
137

	
138
    virtual VarStatus _getColStatus(int i) const;
139
    virtual VarStatus _getRowStatus(int i) const;
140

	
141
    virtual ProblemType _getPrimalType() const;
142
    virtual ProblemType _getDualType() const;
143

	
144
    virtual void _clear();
145

	
146
  };
147

	
148
} //END OF NAMESPACE LEMON
149

	
150
#endif //LEMON_SOPLEX_H
151

	
Ignore white space 4 line context
... ...
@@ -29,17 +29,17 @@
29 29

	
30 30
if HAVE_GLPK
31
lemon_libemon_la_SOURCES += lemon/lp_glpk.cc
31
lemon_libemon_la_SOURCES += lemon/glpk.cc
32 32
endif
33 33

	
34 34
if HAVE_CPLEX
35
lemon_libemon_la_SOURCES += lemon/lp_cplex.cc
35
lemon_libemon_la_SOURCES += lemon/cplex.cc
36 36
endif
37 37

	
38 38
if HAVE_SOPLEX
39
lemon_libemon_la_SOURCES += lemon/lp_soplex.cc
39
lemon_libemon_la_SOURCES += lemon/soplex.cc
40 40
endif
41 41

	
42 42
if HAVE_CLP
43
lemon_libemon_la_SOURCES += lemon/lp_clp.cc
43
lemon_libemon_la_SOURCES += lemon/clp.cc
44 44
endif
45 45

	
... ...
@@ -51,8 +51,10 @@
51 51
	lemon/bin_heap.h \
52 52
	lemon/circulation.h \
53
	lemon/clp.h \
53 54
	lemon/color.h \
54 55
	lemon/concept_check.h \
55 56
	lemon/counter.h \
56 57
	lemon/core.h \
58
	lemon/cplex.h \
57 59
	lemon/dfs.h \
58 60
	lemon/dijkstra.h \
... ...
@@ -62,4 +64,5 @@
62 64
	lemon/error.h \
63 65
	lemon/full_graph.h \
66
	lemon/glpk.h \
64 67
	lemon/graph_to_eps.h \
65 68
	lemon/grid_graph.h \
... ...
@@ -72,9 +75,5 @@
72 75
	lemon/lp.h \
73 76
	lemon/lp_base.h \
74
	lemon/lp_clp.h \
75
	lemon/lp_cplex.h \
76
	lemon/lp_glpk.h \
77 77
	lemon/lp_skeleton.h \
78
	lemon/lp_soplex.h \
79 78
	lemon/list_graph.h \
80 79
	lemon/maps.h \
... ...
@@ -87,4 +86,5 @@
87 86
	lemon/random.h \
88 87
	lemon/smart_graph.h \
88
	lemon/soplex.h \
89 89
	lemon/suurballe.h \
90 90
	lemon/time_measure.h \
Ignore white space 4 line context
... ...
@@ -24,11 +24,11 @@
24 24

	
25 25
#ifdef HAVE_GLPK
26
#include <lemon/lp_glpk.h>
26
#include <lemon/glpk.h>
27 27
#elif HAVE_CPLEX
28
#include <lemon/lp_cplex.h>
28
#include <lemon/cplex.h>
29 29
#elif HAVE_SOPLEX
30
#include <lemon/lp_soplex.h>
30
#include <lemon/soplex.h>
31 31
#elif HAVE_CLP
32
#include <lemon/lp_clp.h>
32
#include <lemon/clp.h>
33 33
#endif
34 34

	
... ...
@@ -44,6 +44,6 @@
44 44
  ///\ingroup lp_group
45 45
  ///
46
  ///Currently, the possible values are \c LP_GLPK, \c LP_CPLEX, \c
47
  ///LP_SOPLEX or \c LP_CLP
46
  ///Currently, the possible values are \c GLPK, \c CPLEX,
47
  ///\c SOPLEX or \c CLP
48 48
#define LEMON_DEFAULT_LP SOLVER
49 49
  ///The default LP solver
... ...
@@ -60,5 +60,5 @@
60 60
  ///\ingroup lp_group
61 61
  ///
62
  ///Currently, the possible values are \c MIP_GLPK or \c MIP_CPLEX
62
  ///Currently, the possible values are \c GLPK or \c CPLEX
63 63
#define LEMON_DEFAULT_MIP SOLVER
64 64
  ///The default MIP solver.
... ...
@@ -71,18 +71,18 @@
71 71
#else
72 72
#ifdef HAVE_GLPK
73
# define LEMON_DEFAULT_LP LP_GLPK
73
# define LEMON_DEFAULT_LP GLPK
74 74
  typedef LpGlpk Lp;
75
# define LEMON_DEFAULT_MIP MIP_GLPK
75
# define LEMON_DEFAULT_MIP GLPK
76 76
  typedef MipGlpk Mip;
77 77
#elif HAVE_CPLEX
78
# define LEMON_DEFAULT_LP LP_CPLEX
78
# define LEMON_DEFAULT_LP CPLEX
79 79
  typedef LpCplex Lp;
80
# define LEMON_DEFAULT_MIP MIP_CPLEX
80
# define LEMON_DEFAULT_MIP CPLEX
81 81
  typedef MipCplex Mip;
82 82
#elif HAVE_SOPLEX
83
# define DEFAULT_LP LP_SOPLEX
83
# define DEFAULT_LP SOPLEX
84 84
  typedef LpSoplex Lp;
85 85
#elif HAVE_CLP
86
# define DEFAULT_LP LP_CLP
86
# define DEFAULT_LP CLP
87 87
  typedef LpClp Lp;  
88 88
#endif
Ignore white space 4 line context
... ...
@@ -27,17 +27,17 @@
27 27

	
28 28
#ifdef HAVE_GLPK
29
#include <lemon/lp_glpk.h>
29
#include <lemon/glpk.h>
30 30
#endif
31 31

	
32 32
#ifdef HAVE_CPLEX
33
#include <lemon/lp_cplex.h>
33
#include <lemon/cplex.h>
34 34
#endif
35 35

	
36 36
#ifdef HAVE_SOPLEX
37
#include <lemon/lp_soplex.h>
37
#include <lemon/soplex.h>
38 38
#endif
39 39

	
40 40
#ifdef HAVE_CLP
41
#include <lemon/lp_clp.h>
41
#include <lemon/clp.h>
42 42
#endif
43 43

	
Ignore white space 4 line context
... ...
@@ -25,9 +25,9 @@
25 25

	
26 26
#ifdef HAVE_CPLEX
27
#include <lemon/lp_cplex.h>
27
#include <lemon/cplex.h>
28 28
#endif
29 29

	
30 30
#ifdef HAVE_GLPK
31
#include <lemon/lp_glpk.h>
31
#include <lemon/glpk.h>
32 32
#endif
33 33

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#include <lemon/lp_clp.h>
20
#include <coin/ClpSimplex.hpp>
21

	
22
namespace lemon {
23

	
24
  LpClp::LpClp() {
25
    _prob = new ClpSimplex();
26
    _init_temporals();
27
    messageLevel(MESSAGE_NO_OUTPUT);
28
  }
29

	
30
  LpClp::LpClp(const LpClp& other) {
31
    _prob = new ClpSimplex(*other._prob);
32
    rows = other.rows;
33
    cols = other.cols;
34
    _init_temporals();
35
    messageLevel(MESSAGE_NO_OUTPUT);
36
  }
37

	
38
  LpClp::~LpClp() {
39
    delete _prob;
40
    _clear_temporals();
41
  }
42

	
43
  void LpClp::_init_temporals() {
44
    _primal_ray = 0;
45
    _dual_ray = 0;
46
  }
47

	
48
  void LpClp::_clear_temporals() {
49
    if (_primal_ray) {
50
      delete[] _primal_ray;
51
      _primal_ray = 0;
52
    }
53
    if (_dual_ray) {
54
      delete[] _dual_ray;
55
      _dual_ray = 0;
56
    }
57
  }
58

	
59
  LpClp* LpClp::_newSolver() const {
60
    LpClp* newlp = new LpClp;
61
    return newlp;
62
  }
63

	
64
  LpClp* LpClp::_cloneSolver() const {
65
    LpClp* copylp = new LpClp(*this);
66
    return copylp;
67
  }
68

	
69
  const char* LpClp::_solverName() const { return "LpClp"; }
70

	
71
  int LpClp::_addCol() {
72
    _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0);
73
    return _prob->numberColumns() - 1;
74
  }
75

	
76
  int LpClp::_addRow() {
77
    _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX);
78
    return _prob->numberRows() - 1;
79
  }
80

	
81

	
82
  void LpClp::_eraseCol(int c) {
83
    _col_names_ref.erase(_prob->getColumnName(c));
84
    _prob->deleteColumns(1, &c);
85
  }
86

	
87
  void LpClp::_eraseRow(int r) {
88
    _row_names_ref.erase(_prob->getRowName(r));
89
    _prob->deleteRows(1, &r);
90
  }
91

	
92
  void LpClp::_eraseColId(int i) {
93
    cols.eraseIndex(i);
94
    cols.shiftIndices(i);
95
  }
96

	
97
  void LpClp::_eraseRowId(int i) {
98
    rows.eraseIndex(i);
99
    rows.shiftIndices(i);
100
  }
101

	
102
  void LpClp::_getColName(int c, std::string& name) const {
103
    name = _prob->getColumnName(c);
104
  }
105

	
106
  void LpClp::_setColName(int c, const std::string& name) {
107
    _prob->setColumnName(c, const_cast<std::string&>(name));
108
    _col_names_ref[name] = c;
109
  }
110

	
111
  int LpClp::_colByName(const std::string& name) const {
112
    std::map<std::string, int>::const_iterator it = _col_names_ref.find(name);
113
    return it != _col_names_ref.end() ? it->second : -1;
114
  }
115

	
116
  void LpClp::_getRowName(int r, std::string& name) const {
117
    name = _prob->getRowName(r);
118
  }
119

	
120
  void LpClp::_setRowName(int r, const std::string& name) {
121
    _prob->setRowName(r, const_cast<std::string&>(name));
122
    _row_names_ref[name] = r;
123
  }
124

	
125
  int LpClp::_rowByName(const std::string& name) const {
126
    std::map<std::string, int>::const_iterator it = _row_names_ref.find(name);
127
    return it != _row_names_ref.end() ? it->second : -1;
128
  }
129

	
130

	
131
  void LpClp::_setRowCoeffs(int ix, ExprIterator b, ExprIterator e) {
132
    std::map<int, Value> coeffs;
133

	
134
    int n = _prob->clpMatrix()->getNumCols();
135

	
136
    const int* indices = _prob->clpMatrix()->getIndices();
137
    const double* elements = _prob->clpMatrix()->getElements();
138

	
139
    for (int i = 0; i < n; ++i) {
140
      CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i];
141
      CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i];
142

	
143
      const int* it = std::lower_bound(indices + begin, indices + end, ix);
144
      if (it != indices + end && *it == ix && elements[it - indices] != 0.0) {
145
        coeffs[i] = 0.0;
146
      }
147
    }
148

	
149
    for (ExprIterator it = b; it != e; ++it) {
150
      coeffs[it->first] = it->second;
151
    }
152

	
153
    for (std::map<int, Value>::iterator it = coeffs.begin();
154
         it != coeffs.end(); ++it) {
155
      _prob->modifyCoefficient(ix, it->first, it->second);
156
    }
157
  }
158

	
159
  void LpClp::_getRowCoeffs(int ix, InsertIterator b) const {
160
    int n = _prob->clpMatrix()->getNumCols();
161

	
162
    const int* indices = _prob->clpMatrix()->getIndices();
163
    const double* elements = _prob->clpMatrix()->getElements();
164

	
165
    for (int i = 0; i < n; ++i) {
166
      CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i];
167
      CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i];
168

	
169
      const int* it = std::lower_bound(indices + begin, indices + end, ix);
170
      if (it != indices + end && *it == ix) {
171
        *b = std::make_pair(i, elements[it - indices]);
172
      }
173
    }
174
  }
175

	
176
  void LpClp::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) {
177
    std::map<int, Value> coeffs;
178

	
179
    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
180
    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
181

	
182
    const int* indices = _prob->clpMatrix()->getIndices();
183
    const double* elements = _prob->clpMatrix()->getElements();
184

	
185
    for (CoinBigIndex i = begin; i != end; ++i) {
186
      if (elements[i] != 0.0) {
187
        coeffs[indices[i]] = 0.0;
188
      }
189
    }
190
    for (ExprIterator it = b; it != e; ++it) {
191
      coeffs[it->first] = it->second;
192
    }
193
    for (std::map<int, Value>::iterator it = coeffs.begin();
194
         it != coeffs.end(); ++it) {
195
      _prob->modifyCoefficient(it->first, ix, it->second);
196
    }
197
  }
198

	
199
  void LpClp::_getColCoeffs(int ix, InsertIterator b) const {
200
    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
201
    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
202

	
203
    const int* indices = _prob->clpMatrix()->getIndices();
204
    const double* elements = _prob->clpMatrix()->getElements();
205

	
206
    for (CoinBigIndex i = begin; i != end; ++i) {
207
      *b = std::make_pair(indices[i], elements[i]);
208
      ++b;
209
    }
210
  }
211

	
212
  void LpClp::_setCoeff(int ix, int jx, Value value) {
213
    _prob->modifyCoefficient(ix, jx, value);
214
  }
215

	
216
  LpClp::Value LpClp::_getCoeff(int ix, int jx) const {
217
    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
218
    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
219

	
220
    const int* indices = _prob->clpMatrix()->getIndices();
221
    const double* elements = _prob->clpMatrix()->getElements();
222

	
223
    const int* it = std::lower_bound(indices + begin, indices + end, jx);
224
    if (it != indices + end && *it == jx) {
225
      return elements[it - indices];
226
    } else {
227
      return 0.0;
228
    }
229
  }
230

	
231
  void LpClp::_setColLowerBound(int i, Value lo) {
232
    _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
233
  }
234

	
235
  LpClp::Value LpClp::_getColLowerBound(int i) const {
236
    double val = _prob->getColLower()[i];
237
    return val == - COIN_DBL_MAX ? - INF : val;
238
  }
239

	
240
  void LpClp::_setColUpperBound(int i, Value up) {
241
    _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up);
242
  }
243

	
244
  LpClp::Value LpClp::_getColUpperBound(int i) const {
245
    double val = _prob->getColUpper()[i];
246
    return val == COIN_DBL_MAX ? INF : val;
247
  }
248

	
249
  void LpClp::_setRowLowerBound(int i, Value lo) {
250
    _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
251
  }
252

	
253
  LpClp::Value LpClp::_getRowLowerBound(int i) const {
254
    double val = _prob->getRowLower()[i];
255
    return val == - COIN_DBL_MAX ? - INF : val;
256
  }
257

	
258
  void LpClp::_setRowUpperBound(int i, Value up) {
259
    _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up);
260
  }
261

	
262
  LpClp::Value LpClp::_getRowUpperBound(int i) const {
263
    double val = _prob->getRowUpper()[i];
264
    return val == COIN_DBL_MAX ? INF : val;
265
  }
266

	
267
  void LpClp::_setObjCoeffs(ExprIterator b, ExprIterator e) {
268
    int num = _prob->clpMatrix()->getNumCols();
269
    for (int i = 0; i < num; ++i) {
270
      _prob->setObjectiveCoefficient(i, 0.0);
271
    }
272
    for (ExprIterator it = b; it != e; ++it) {
273
      _prob->setObjectiveCoefficient(it->first, it->second);
274
    }
275
  }
276

	
277
  void LpClp::_getObjCoeffs(InsertIterator b) const {
278
    int num = _prob->clpMatrix()->getNumCols();
279
    for (int i = 0; i < num; ++i) {
280
      Value coef = _prob->getObjCoefficients()[i];
281
      if (coef != 0.0) {
282
        *b = std::make_pair(i, coef);
283
        ++b;
284
      }
285
    }
286
  }
287

	
288
  void LpClp::_setObjCoeff(int i, Value obj_coef) {
289
    _prob->setObjectiveCoefficient(i, obj_coef);
290
  }
291

	
292
  LpClp::Value LpClp::_getObjCoeff(int i) const {
293
    return _prob->getObjCoefficients()[i];
294
  }
295

	
296
  LpClp::SolveExitStatus LpClp::_solve() {
297
    return _prob->primal() >= 0 ? SOLVED : UNSOLVED;
298
  }
299

	
300
  LpClp::SolveExitStatus LpClp::solvePrimal() {
301
    return _prob->primal() >= 0 ? SOLVED : UNSOLVED;
302
  }
303

	
304
  LpClp::SolveExitStatus LpClp::solveDual() {
305
    return _prob->dual() >= 0 ? SOLVED : UNSOLVED;
306
  }
307

	
308
  LpClp::SolveExitStatus LpClp::solveBarrier() {
309
    return _prob->barrier() >= 0 ? SOLVED : UNSOLVED;
310
  }
311

	
312
  LpClp::Value LpClp::_getPrimal(int i) const {
313
    return _prob->primalColumnSolution()[i];
314
  }
315
  LpClp::Value LpClp::_getPrimalValue() const {
316
    return _prob->objectiveValue();
317
  }
318

	
319
  LpClp::Value LpClp::_getDual(int i) const {
320
    return _prob->dualRowSolution()[i];
321
  }
322

	
323
  LpClp::Value LpClp::_getPrimalRay(int i) const {
324
    if (!_primal_ray) {
325
      _primal_ray = _prob->unboundedRay();
326
      LEMON_ASSERT(_primal_ray != 0, "Primal ray is not provided");
327
    }
328
    return _primal_ray[i];
329
  }
330

	
331
  LpClp::Value LpClp::_getDualRay(int i) const {
332
    if (!_dual_ray) {
333
      _dual_ray = _prob->infeasibilityRay();
334
      LEMON_ASSERT(_dual_ray != 0, "Dual ray is not provided");
335
    }
336
    return _dual_ray[i];
337
  }
338

	
339
  LpClp::VarStatus LpClp::_getColStatus(int i) const {
340
    switch (_prob->getColumnStatus(i)) {
341
    case ClpSimplex::basic:
342
      return BASIC;
343
    case ClpSimplex::isFree:
344
      return FREE;
345
    case ClpSimplex::atUpperBound:
346
      return UPPER;
347
    case ClpSimplex::atLowerBound:
348
      return LOWER;
349
    case ClpSimplex::isFixed:
350
      return FIXED;
351
    case ClpSimplex::superBasic:
352
      return FREE;
353
    default:
354
      LEMON_ASSERT(false, "Wrong column status");
355
      return VarStatus();
356
    }
357
  }
358

	
359
  LpClp::VarStatus LpClp::_getRowStatus(int i) const {
360
    switch (_prob->getColumnStatus(i)) {
361
    case ClpSimplex::basic:
362
      return BASIC;
363
    case ClpSimplex::isFree:
364
      return FREE;
365
    case ClpSimplex::atUpperBound:
366
      return UPPER;
367
    case ClpSimplex::atLowerBound:
368
      return LOWER;
369
    case ClpSimplex::isFixed:
370
      return FIXED;
371
    case ClpSimplex::superBasic:
372
      return FREE;
373
    default:
374
      LEMON_ASSERT(false, "Wrong row status");
375
      return VarStatus();
376
    }
377
  }
378

	
379

	
380
  LpClp::ProblemType LpClp::_getPrimalType() const {
381
    if (_prob->isProvenOptimal()) {
382
      return OPTIMAL;
383
    } else if (_prob->isProvenPrimalInfeasible()) {
384
      return INFEASIBLE;
385
    } else if (_prob->isProvenDualInfeasible()) {
386
      return UNBOUNDED;
387
    } else {
388
      return UNDEFINED;
389
    }
390
  }
391

	
392
  LpClp::ProblemType LpClp::_getDualType() const {
393
    if (_prob->isProvenOptimal()) {
394
      return OPTIMAL;
395
    } else if (_prob->isProvenDualInfeasible()) {
396
      return INFEASIBLE;
397
    } else if (_prob->isProvenPrimalInfeasible()) {
398
      return INFEASIBLE;
399
    } else {
400
      return UNDEFINED;
401
    }
402
  }
403

	
404
  void LpClp::_setSense(LpClp::Sense sense) {
405
    switch (sense) {
406
    case MIN:
407
      _prob->setOptimizationDirection(1);
408
      break;
409
    case MAX:
410
      _prob->setOptimizationDirection(-1);
411
      break;
412
    }
413
  }
414

	
415
  LpClp::Sense LpClp::_getSense() const {
416
    double dir = _prob->optimizationDirection();
417
    if (dir > 0.0) {
418
      return MIN;
419
    } else {
420
      return MAX;
421
    }
422
  }
423

	
424
  void LpClp::_clear() {
425
    delete _prob;
426
    _prob = new ClpSimplex();
427
    rows.clear();
428
    cols.clear();
429
    _col_names_ref.clear();
430
    _clear_temporals();
431
  }
432

	
433
  void LpClp::messageLevel(MessageLevel m) {
434
    _prob->setLogLevel(static_cast<int>(m));
435
  }
436

	
437
} //END OF NAMESPACE LEMON
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#ifndef LEMON_LP_CLP_H
20
#define LEMON_LP_CLP_H
21

	
22
///\file
23
///\brief Header of the LEMON-CLP lp solver interface.
24

	
25
#include <vector>
26
#include <string>
27

	
28
#include <lemon/lp_base.h>
29

	
30
class ClpSimplex;
31

	
32
namespace lemon {
33

	
34
  /// \ingroup lp_group
35
  ///
36
  /// \brief Interface for the CLP solver
37
  ///
38
  /// This class implements an interface for the Clp LP solver.  The
39
  /// Clp library is an object oriented lp solver library developed at
40
  /// the IBM. The CLP is part of the COIN-OR package and it can be
41
  /// used with Common Public License.
42
  class LpClp : public LpSolver {
43
  protected:
44

	
45
    ClpSimplex* _prob;
46

	
47
    std::map<std::string, int> _col_names_ref;
48
    std::map<std::string, int> _row_names_ref;
49

	
50
  public:
51

	
52
    /// \e
53
    LpClp();
54
    /// \e
55
    LpClp(const LpClp&);
56
    /// \e
57
    ~LpClp();
58

	
59
  protected:
60

	
61
    mutable double* _primal_ray;
62
    mutable double* _dual_ray;
63

	
64
    void _init_temporals();
65
    void _clear_temporals();
66

	
67
  protected:
68

	
69
    virtual LpClp* _newSolver() const;
70
    virtual LpClp* _cloneSolver() const;
71

	
72
    virtual const char* _solverName() const;
73

	
74
    virtual int _addCol();
75
    virtual int _addRow();
76

	
77
    virtual void _eraseCol(int i);
78
    virtual void _eraseRow(int i);
79

	
80
    virtual void _eraseColId(int i);
81
    virtual void _eraseRowId(int i);
82

	
83
    virtual void _getColName(int col, std::string& name) const;
84
    virtual void _setColName(int col, const std::string& name);
85
    virtual int _colByName(const std::string& name) const;
86

	
87
    virtual void _getRowName(int row, std::string& name) const;
88
    virtual void _setRowName(int row, const std::string& name);
89
    virtual int _rowByName(const std::string& name) const;
90

	
91
    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
92
    virtual void _getRowCoeffs(int i, InsertIterator b) const;
93

	
94
    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
95
    virtual void _getColCoeffs(int i, InsertIterator b) const;
96

	
97
    virtual void _setCoeff(int row, int col, Value value);
98
    virtual Value _getCoeff(int row, int col) const;
99

	
100
    virtual void _setColLowerBound(int i, Value value);
101
    virtual Value _getColLowerBound(int i) const;
102
    virtual void _setColUpperBound(int i, Value value);
103
    virtual Value _getColUpperBound(int i) const;
104

	
105
    virtual void _setRowLowerBound(int i, Value value);
106
    virtual Value _getRowLowerBound(int i) const;
107
    virtual void _setRowUpperBound(int i, Value value);
108
    virtual Value _getRowUpperBound(int i) const;
109

	
110
    virtual void _setObjCoeffs(ExprIterator, ExprIterator);
111
    virtual void _getObjCoeffs(InsertIterator) const;
112

	
113
    virtual void _setObjCoeff(int i, Value obj_coef);
114
    virtual Value _getObjCoeff(int i) const;
115

	
116
    virtual void _setSense(Sense sense);
117
    virtual Sense _getSense() const;
118

	
119
    virtual SolveExitStatus _solve();
120

	
121
    virtual Value _getPrimal(int i) const;
122
    virtual Value _getDual(int i) const;
123

	
124
    virtual Value _getPrimalValue() const;
125

	
126
    virtual Value _getPrimalRay(int i) const;
127
    virtual Value _getDualRay(int i) const;
128

	
129
    virtual VarStatus _getColStatus(int i) const;
130
    virtual VarStatus _getRowStatus(int i) const;
131

	
132
    virtual ProblemType _getPrimalType() const;
133
    virtual ProblemType _getDualType() const;
134

	
135
    virtual void _clear();
136

	
137
  public:
138

	
139
    ///Solves LP with primal simplex method.
140
    SolveExitStatus solvePrimal();
141

	
142
    ///Solves LP with dual simplex method.
143
    SolveExitStatus solveDual();
144

	
145
    ///Solves LP with barrier method.
146
    SolveExitStatus solveBarrier();
147

	
148
    ///Returns the constraint identifier understood by CLP.
149
    int clpRow(Row r) const { return rows(id(r)); }
150

	
151
    ///Returns the variable identifier understood by CLP.
152
    int clpCol(Col c) const { return cols(id(c)); }
153

	
154
    ///Enum for \c messageLevel() parameter
155
    enum MessageLevel {
156
      /// no output (default value)
157
      MESSAGE_NO_OUTPUT = 0,
158
      /// print final solution
159
      MESSAGE_FINAL_SOLUTION = 1,
160
      /// print factorization
161
      MESSAGE_FACTORIZATION = 2,
162
      /// normal output
163
      MESSAGE_NORMAL_OUTPUT = 3,
164
      /// verbose output
165
      MESSAGE_VERBOSE_OUTPUT = 4
166
    };
167
    ///Set the verbosity of the messages
168

	
169
    ///Set the verbosity of the messages
170
    ///
171
    ///\param m is the level of the messages output by the solver routines.
172
    void messageLevel(MessageLevel m);
173

	
174
  };
175

	
176
} //END OF NAMESPACE LEMON
177

	
178
#endif //LEMON_LP_CLP_H
179

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#include <iostream>
20
#include <vector>
21
#include <cstring>
22

	
23
#include <lemon/lp_cplex.h>
24

	
25
extern "C" {
26
#include <ilcplex/cplex.h>
27
}
28

	
29

	
30
///\file
31
///\brief Implementation of the LEMON-CPLEX lp solver interface.
32
namespace lemon {
33

	
34
  CplexEnv::LicenseError::LicenseError(int status) {
35
    if (!CPXgeterrorstring(0, status, _message)) {
36
      std::strcpy(_message, "Cplex unknown error");
37
    }
38
  }
39

	
40
  CplexEnv::CplexEnv() {
41
    int status;
42
    _cnt = new int;
43
    _env = CPXopenCPLEX(&status);
44
    if (_env == 0) {
45
      delete _cnt;
46
      _cnt = 0;
47
      throw LicenseError(status);
48
    }
49
  }
50

	
51
  CplexEnv::CplexEnv(const CplexEnv& other) {
52
    _env = other._env;
53
    _cnt = other._cnt;
54
    ++(*_cnt);
55
  }
56

	
57
  CplexEnv& CplexEnv::operator=(const CplexEnv& other) {
58
    _env = other._env;
59
    _cnt = other._cnt;
60
    ++(*_cnt);
61
    return *this;
62
  }
63

	
64
  CplexEnv::~CplexEnv() {
65
    --(*_cnt);
66
    if (*_cnt == 0) {
67
      delete _cnt;
68
      CPXcloseCPLEX(&_env);
69
    }
70
  }
71

	
72
  CplexBase::CplexBase() : LpBase() {
73
    int status;
74
    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
75
  }
76

	
77
  CplexBase::CplexBase(const CplexEnv& env)
78
    : LpBase(), _env(env) {
79
    int status;
80
    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
81
  }
82

	
83
  CplexBase::CplexBase(const CplexBase& cplex)
84
    : LpBase() {
85
    int status;
86
    _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status);
87
    rows = cplex.rows;
88
    cols = cplex.cols;
89
  }
90

	
91
  CplexBase::~CplexBase() {
92
    CPXfreeprob(cplexEnv(),&_prob);
93
  }
94

	
95
  int CplexBase::_addCol() {
96
    int i = CPXgetnumcols(cplexEnv(), _prob);
97
    double lb = -INF, ub = INF;
98
    CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0);
99
    return i;
100
  }
101

	
102

	
103
  int CplexBase::_addRow() {
104
    int i = CPXgetnumrows(cplexEnv(), _prob);
105
    const double ub = INF;
106
    const char s = 'L';
107
    CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
108
    return i;
109
  }
110

	
111

	
112
  void CplexBase::_eraseCol(int i) {
113
    CPXdelcols(cplexEnv(), _prob, i, i);
114
  }
115

	
116
  void CplexBase::_eraseRow(int i) {
117
    CPXdelrows(cplexEnv(), _prob, i, i);
118
  }
119

	
120
  void CplexBase::_eraseColId(int i) {
121
    cols.eraseIndex(i);
122
    cols.shiftIndices(i);
123
  }
124
  void CplexBase::_eraseRowId(int i) {
125
    rows.eraseIndex(i);
126
    rows.shiftIndices(i);
127
  }
128

	
129
  void CplexBase::_getColName(int col, std::string &name) const {
130
    int size;
131
    CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col);
132
    if (size == 0) {
133
      name.clear();
134
      return;
135
    }
136

	
137
    size *= -1;
138
    std::vector<char> buf(size);
139
    char *cname;
140
    int tmp;
141
    CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size,
142
                  &tmp, col, col);
143
    name = cname;
144
  }
145

	
146
  void CplexBase::_setColName(int col, const std::string &name) {
147
    char *cname;
148
    cname = const_cast<char*>(name.c_str());
149
    CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname);
150
  }
151

	
152
  int CplexBase::_colByName(const std::string& name) const {
153
    int index;
154
    if (CPXgetcolindex(cplexEnv(), _prob,
155
                       const_cast<char*>(name.c_str()), &index) == 0) {
156
      return index;
157
    }
158
    return -1;
159
  }
160

	
161
  void CplexBase::_getRowName(int row, std::string &name) const {
162
    int size;
163
    CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row);
164
    if (size == 0) {
165
      name.clear();
166
      return;
167
    }
168

	
169
    size *= -1;
170
    std::vector<char> buf(size);
171
    char *cname;
172
    int tmp;
173
    CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size,
174
                  &tmp, row, row);
175
    name = cname;
176
  }
177

	
178
  void CplexBase::_setRowName(int row, const std::string &name) {
179
    char *cname;
180
    cname = const_cast<char*>(name.c_str());
181
    CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname);
182
  }
183

	
184
  int CplexBase::_rowByName(const std::string& name) const {
185
    int index;
186
    if (CPXgetrowindex(cplexEnv(), _prob,
187
                       const_cast<char*>(name.c_str()), &index) == 0) {
188
      return index;
189
    }
190
    return -1;
191
  }
192

	
193
  void CplexBase::_setRowCoeffs(int i, ExprIterator b,
194
                                      ExprIterator e)
195
  {
196
    std::vector<int> indices;
197
    std::vector<int> rowlist;
198
    std::vector<Value> values;
199

	
200
    for(ExprIterator it=b; it!=e; ++it) {
201
      indices.push_back(it->first);
202
      values.push_back(it->second);
203
      rowlist.push_back(i);
204
    }
205

	
206
    CPXchgcoeflist(cplexEnv(), _prob, values.size(),
207
                   &rowlist.front(), &indices.front(), &values.front());
208
  }
209

	
210
  void CplexBase::_getRowCoeffs(int i, InsertIterator b) const {
211
    int tmp1, tmp2, tmp3, length;
212
    CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
213

	
214
    length = -length;
215
    std::vector<int> indices(length);
216
    std::vector<double> values(length);
217

	
218
    CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2,
219
               &indices.front(), &values.front(),
220
               length, &tmp3, i, i);
221

	
222
    for (int i = 0; i < length; ++i) {
223
      *b = std::make_pair(indices[i], values[i]);
224
      ++b;
225
    }
226
  }
227

	
228
  void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) {
229
    std::vector<int> indices;
230
    std::vector<int> collist;
231
    std::vector<Value> values;
232

	
233
    for(ExprIterator it=b; it!=e; ++it) {
234
      indices.push_back(it->first);
235
      values.push_back(it->second);
236
      collist.push_back(i);
237
    }
238

	
239
    CPXchgcoeflist(cplexEnv(), _prob, values.size(),
240
                   &indices.front(), &collist.front(), &values.front());
241
  }
242

	
243
  void CplexBase::_getColCoeffs(int i, InsertIterator b) const {
244

	
245
    int tmp1, tmp2, tmp3, length;
246
    CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
247

	
248
    length = -length;
249
    std::vector<int> indices(length);
250
    std::vector<double> values(length);
251

	
252
    CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2,
253
               &indices.front(), &values.front(),
254
               length, &tmp3, i, i);
255

	
256
    for (int i = 0; i < length; ++i) {
257
      *b = std::make_pair(indices[i], values[i]);
258
      ++b;
259
    }
260

	
261
  }
262

	
263
  void CplexBase::_setCoeff(int row, int col, Value value) {
264
    CPXchgcoef(cplexEnv(), _prob, row, col, value);
265
  }
266

	
267
  CplexBase::Value CplexBase::_getCoeff(int row, int col) const {
268
    CplexBase::Value value;
269
    CPXgetcoef(cplexEnv(), _prob, row, col, &value);
270
    return value;
271
  }
272

	
273
  void CplexBase::_setColLowerBound(int i, Value value) {
274
    const char s = 'L';
275
    CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
276
  }
277

	
278
  CplexBase::Value CplexBase::_getColLowerBound(int i) const {
279
    CplexBase::Value res;
280
    CPXgetlb(cplexEnv(), _prob, &res, i, i);
281
    return res <= -CPX_INFBOUND ? -INF : res;
282
  }
283

	
284
  void CplexBase::_setColUpperBound(int i, Value value)
285
  {
286
    const char s = 'U';
287
    CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
288
  }
289

	
290
  CplexBase::Value CplexBase::_getColUpperBound(int i) const {
291
    CplexBase::Value res;
292
    CPXgetub(cplexEnv(), _prob, &res, i, i);
293
    return res >= CPX_INFBOUND ? INF : res;
294
  }
295

	
296
  CplexBase::Value CplexBase::_getRowLowerBound(int i) const {
297
    char s;
298
    CPXgetsense(cplexEnv(), _prob, &s, i, i);
299
    CplexBase::Value res;
300

	
301
    switch (s) {
302
    case 'G':
303
    case 'R':
304
    case 'E':
305
      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
306
      return res <= -CPX_INFBOUND ? -INF : res;
307
    default:
308
      return -INF;
309
    }
310
  }
311

	
312
  CplexBase::Value CplexBase::_getRowUpperBound(int i) const {
313
    char s;
314
    CPXgetsense(cplexEnv(), _prob, &s, i, i);
315
    CplexBase::Value res;
316

	
317
    switch (s) {
318
    case 'L':
319
    case 'E':
320
      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
321
      return res >= CPX_INFBOUND ? INF : res;
322
    case 'R':
323
      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
324
      {
325
        double rng;
326
        CPXgetrngval(cplexEnv(), _prob, &rng, i, i);
327
        res += rng;
328
      }
329
      return res >= CPX_INFBOUND ? INF : res;
330
    default:
331
      return INF;
332
    }
333
  }
334

	
335
  //This is easier to implement
336
  void CplexBase::_set_row_bounds(int i, Value lb, Value ub) {
337
    if (lb == -INF) {
338
      const char s = 'L';
339
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
340
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub);
341
    } else if (ub == INF) {
342
      const char s = 'G';
343
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
344
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
345
    } else if (lb == ub){
346
      const char s = 'E';
347
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
348
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
349
    } else {
350
      const char s = 'R';
351
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
352
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
353
      double len = ub - lb;
354
      CPXchgrngval(cplexEnv(), _prob, 1, &i, &len);
355
    }
356
  }
357

	
358
  void CplexBase::_setRowLowerBound(int i, Value lb)
359
  {
360
    LEMON_ASSERT(lb != INF, "Invalid bound");
361
    _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i));
362
  }
363

	
364
  void CplexBase::_setRowUpperBound(int i, Value ub)
365
  {
366

	
367
    LEMON_ASSERT(ub != -INF, "Invalid bound");
368
    _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub);
369
  }
370

	
371
  void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e)
372
  {
373
    std::vector<int> indices;
374
    std::vector<Value> values;
375
    for(ExprIterator it=b; it!=e; ++it) {
376
      indices.push_back(it->first);
377
      values.push_back(it->second);
378
    }
379
    CPXchgobj(cplexEnv(), _prob, values.size(),
380
              &indices.front(), &values.front());
381

	
382
  }
383

	
384
  void CplexBase::_getObjCoeffs(InsertIterator b) const
385
  {
386
    int num = CPXgetnumcols(cplexEnv(), _prob);
387
    std::vector<Value> x(num);
388

	
389
    CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1);
390
    for (int i = 0; i < num; ++i) {
391
      if (x[i] != 0.0) {
392
        *b = std::make_pair(i, x[i]);
393
        ++b;
394
      }
395
    }
396
  }
397

	
398
  void CplexBase::_setObjCoeff(int i, Value obj_coef)
399
  {
400
    CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef);
401
  }
402

	
403
  CplexBase::Value CplexBase::_getObjCoeff(int i) const
404
  {
405
    Value x;
406
    CPXgetobj(cplexEnv(), _prob, &x, i, i);
407
    return x;
408
  }
409

	
410
  void CplexBase::_setSense(CplexBase::Sense sense) {
411
    switch (sense) {
412
    case MIN:
413
      CPXchgobjsen(cplexEnv(), _prob, CPX_MIN);
414
      break;
415
    case MAX:
416
      CPXchgobjsen(cplexEnv(), _prob, CPX_MAX);
417
      break;
418
    }
419
  }
420

	
421
  CplexBase::Sense CplexBase::_getSense() const {
422
    switch (CPXgetobjsen(cplexEnv(), _prob)) {
423
    case CPX_MIN:
424
      return MIN;
425
    case CPX_MAX:
426
      return MAX;
427
    default:
428
      LEMON_ASSERT(false, "Invalid sense");
429
      return CplexBase::Sense();
430
    }
431
  }
432

	
433
  void CplexBase::_clear() {
434
    CPXfreeprob(cplexEnv(),&_prob);
435
    int status;
436
    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
437
    rows.clear();
438
    cols.clear();
439
  }
440

	
441
  // LpCplex members
442

	
443
  LpCplex::LpCplex()
444
    : LpBase(), CplexBase(), LpSolver() {}
445

	
446
  LpCplex::LpCplex(const CplexEnv& env)
447
    : LpBase(), CplexBase(env), LpSolver() {}
448

	
449
  LpCplex::LpCplex(const LpCplex& other)
450
    : LpBase(), CplexBase(other), LpSolver() {}
451

	
452
  LpCplex::~LpCplex() {}
453

	
454
  LpCplex* LpCplex::_newSolver() const { return new LpCplex; }
455
  LpCplex* LpCplex::_cloneSolver() const {return new LpCplex(*this); }
456

	
457
  const char* LpCplex::_solverName() const { return "LpCplex"; }
458

	
459
  void LpCplex::_clear_temporals() {
460
    _col_status.clear();
461
    _row_status.clear();
462
    _primal_ray.clear();
463
    _dual_ray.clear();
464
  }
465

	
466
  // The routine returns zero unless an error occurred during the
467
  // optimization. Examples of errors include exhausting available
468
  // memory (CPXERR_NO_MEMORY) or encountering invalid data in the
469
  // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a
470
  // user-specified CPLEX limit, or proving the model infeasible or
471
  // unbounded, are not considered errors. Note that a zero return
472
  // value does not necessarily mean that a solution exists. Use query
473
  // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain
474
  // further information about the status of the optimization.
475
  LpCplex::SolveExitStatus LpCplex::convertStatus(int status) {
476
#if CPX_VERSION >= 800
477
    if (status == 0) {
478
      switch (CPXgetstat(cplexEnv(), _prob)) {
479
      case CPX_STAT_OPTIMAL:
480
      case CPX_STAT_INFEASIBLE:
481
      case CPX_STAT_UNBOUNDED:
482
        return SOLVED;
483
      default:
484
        return UNSOLVED;
485
      }
486
    } else {
487
      return UNSOLVED;
488
    }
489
#else
490
    if (status == 0) {
491
      //We want to exclude some cases
492
      switch (CPXgetstat(cplexEnv(), _prob)) {
493
      case CPX_OBJ_LIM:
494
      case CPX_IT_LIM_FEAS:
495
      case CPX_IT_LIM_INFEAS:
496
      case CPX_TIME_LIM_FEAS:
497
      case CPX_TIME_LIM_INFEAS:
498
        return UNSOLVED;
499
      default:
500
        return SOLVED;
501
      }
502
    } else {
503
      return UNSOLVED;
504
    }
505
#endif
506
  }
507

	
508
  LpCplex::SolveExitStatus LpCplex::_solve() {
509
    _clear_temporals();
510
    return convertStatus(CPXlpopt(cplexEnv(), _prob));
511
  }
512

	
513
  LpCplex::SolveExitStatus LpCplex::solvePrimal() {
514
    _clear_temporals();
515
    return convertStatus(CPXprimopt(cplexEnv(), _prob));
516
  }
517

	
518
  LpCplex::SolveExitStatus LpCplex::solveDual() {
519
    _clear_temporals();
520
    return convertStatus(CPXdualopt(cplexEnv(), _prob));
521
  }
522

	
523
  LpCplex::SolveExitStatus LpCplex::solveBarrier() {
524
    _clear_temporals();
525
    return convertStatus(CPXbaropt(cplexEnv(), _prob));
526
  }
527

	
528
  LpCplex::Value LpCplex::_getPrimal(int i) const {
529
    Value x;
530
    CPXgetx(cplexEnv(), _prob, &x, i, i);
531
    return x;
532
  }
533

	
534
  LpCplex::Value LpCplex::_getDual(int i) const {
535
    Value y;
536
    CPXgetpi(cplexEnv(), _prob, &y, i, i);
537
    return y;
538
  }
539

	
540
  LpCplex::Value LpCplex::_getPrimalValue() const {
541
    Value objval;
542
    CPXgetobjval(cplexEnv(), _prob, &objval);
543
    return objval;
544
  }
545

	
546
  LpCplex::VarStatus LpCplex::_getColStatus(int i) const {
547
    if (_col_status.empty()) {
548
      _col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
549
      CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
550
    }
551
    switch (_col_status[i]) {
552
    case CPX_BASIC:
553
      return BASIC;
554
    case CPX_FREE_SUPER:
555
      return FREE;
556
    case CPX_AT_LOWER:
557
      return LOWER;
558
    case CPX_AT_UPPER:
559
      return UPPER;
560
    default:
561
      LEMON_ASSERT(false, "Wrong column status");
562
      return LpCplex::VarStatus();
563
    }
564
  }
565

	
566
  LpCplex::VarStatus LpCplex::_getRowStatus(int i) const {
567
    if (_row_status.empty()) {
568
      _row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
569
      CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
570
    }
571
    switch (_row_status[i]) {
572
    case CPX_BASIC:
573
      return BASIC;
574
    case CPX_AT_LOWER:
575
      {
576
        char s;
577
        CPXgetsense(cplexEnv(), _prob, &s, i, i);
578
        return s != 'L' ? LOWER : UPPER;
579
      }
580
    case CPX_AT_UPPER:
581
      return UPPER;
582
    default:
583
      LEMON_ASSERT(false, "Wrong row status");
584
      return LpCplex::VarStatus();
585
    }
586
  }
587

	
588
  LpCplex::Value LpCplex::_getPrimalRay(int i) const {
589
    if (_primal_ray.empty()) {
590
      _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
591
      CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
592
    }
593
    return _primal_ray[i];
594
  }
595

	
596
  LpCplex::Value LpCplex::_getDualRay(int i) const {
597
    if (_dual_ray.empty()) {
598

	
599
    }
600
    return _dual_ray[i];
601
  }
602

	
603
  //7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!)
604
  // This table lists the statuses, returned by the CPXgetstat()
605
  // routine, for solutions to LP problems or mixed integer problems. If
606
  // no solution exists, the return value is zero.
607

	
608
  // For Simplex, Barrier
609
  // 1          CPX_OPTIMAL
610
  //          Optimal solution found
611
  // 2          CPX_INFEASIBLE
612
  //          Problem infeasible
613
  // 3    CPX_UNBOUNDED
614
  //          Problem unbounded
615
  // 4          CPX_OBJ_LIM
616
  //          Objective limit exceeded in Phase II
617
  // 5          CPX_IT_LIM_FEAS
618
  //          Iteration limit exceeded in Phase II
619
  // 6          CPX_IT_LIM_INFEAS
620
  //          Iteration limit exceeded in Phase I
621
  // 7          CPX_TIME_LIM_FEAS
622
  //          Time limit exceeded in Phase II
623
  // 8          CPX_TIME_LIM_INFEAS
624
  //          Time limit exceeded in Phase I
625
  // 9          CPX_NUM_BEST_FEAS
626
  //          Problem non-optimal, singularities in Phase II
627
  // 10         CPX_NUM_BEST_INFEAS
628
  //          Problem non-optimal, singularities in Phase I
629
  // 11         CPX_OPTIMAL_INFEAS
630
  //          Optimal solution found, unscaled infeasibilities
631
  // 12         CPX_ABORT_FEAS
632
  //          Aborted in Phase II
633
  // 13         CPX_ABORT_INFEAS
634
  //          Aborted in Phase I
635
  // 14          CPX_ABORT_DUAL_INFEAS
636
  //          Aborted in barrier, dual infeasible
637
  // 15          CPX_ABORT_PRIM_INFEAS
638
  //          Aborted in barrier, primal infeasible
639
  // 16          CPX_ABORT_PRIM_DUAL_INFEAS
640
  //          Aborted in barrier, primal and dual infeasible
641
  // 17          CPX_ABORT_PRIM_DUAL_FEAS
642
  //          Aborted in barrier, primal and dual feasible
643
  // 18          CPX_ABORT_CROSSOVER
644
  //          Aborted in crossover
645
  // 19          CPX_INForUNBD
646
  //          Infeasible or unbounded
647
  // 20   CPX_PIVOT
648
  //       User pivot used
649
  //
650
  //     Ezeket hova tegyem:
651
  // ??case CPX_ABORT_DUAL_INFEAS
652
  // ??case CPX_ABORT_CROSSOVER
653
  // ??case CPX_INForUNBD
654
  // ??case CPX_PIVOT
655

	
656
  //Some more interesting stuff:
657

	
658
  // CPX_PARAM_PROBMETHOD  1062  int  LPMETHOD
659
  // 0 Automatic
660
  // 1 Primal Simplex
661
  // 2 Dual Simplex
662
  // 3 Network Simplex
663
  // 4 Standard Barrier
664
  // Default: 0
665
  // Description: Method for linear optimization.
666
  // Determines which algorithm is used when CPXlpopt() (or "optimize"
667
  // in the Interactive Optimizer) is called. Currently the behavior of
668
  // the "Automatic" setting is that CPLEX simply invokes the dual
669
  // simplex method, but this capability may be expanded in the future
670
  // so that CPLEX chooses the method based on problem characteristics
671
#if CPX_VERSION < 900
672
  void statusSwitch(CPXENVptr cplexEnv(),int& stat){
673
    int lpmethod;
674
    CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod);
675
    if (lpmethod==2){
676
      if (stat==CPX_UNBOUNDED){
677
        stat=CPX_INFEASIBLE;
678
      }
679
      else{
680
        if (stat==CPX_INFEASIBLE)
681
          stat=CPX_UNBOUNDED;
682
      }
683
    }
684
  }
685
#else
686
  void statusSwitch(CPXENVptr,int&){}
687
#endif
688

	
689
  LpCplex::ProblemType LpCplex::_getPrimalType() const {
690
    // Unboundedness not treated well: the following is from cplex 9.0 doc
691
    // About Unboundedness
692

	
693
    // The treatment of models that are unbounded involves a few
694
    // subtleties. Specifically, a declaration of unboundedness means that
695
    // ILOG CPLEX has determined that the model has an unbounded
696
    // ray. Given any feasible solution x with objective z, a multiple of
697
    // the unbounded ray can be added to x to give a feasible solution
698
    // with objective z-1 (or z+1 for maximization models). Thus, if a
699
    // feasible solution exists, then the optimal objective is
700
    // unbounded. Note that ILOG CPLEX has not necessarily concluded that
701
    // a feasible solution exists. Users can call the routine CPXsolninfo
702
    // to determine whether ILOG CPLEX has also concluded that the model
703
    // has a feasible solution.
704

	
705
    int stat = CPXgetstat(cplexEnv(), _prob);
706
#if CPX_VERSION >= 800
707
    switch (stat)
708
      {
709
      case CPX_STAT_OPTIMAL:
710
        return OPTIMAL;
711
      case CPX_STAT_UNBOUNDED:
712
        return UNBOUNDED;
713
      case CPX_STAT_INFEASIBLE:
714
        return INFEASIBLE;
715
      default:
716
        return UNDEFINED;
717
      }
718
#else
719
    statusSwitch(cplexEnv(),stat);
720
    //CPXgetstat(cplexEnv(), _prob);
721
    //printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL);
722
    switch (stat) {
723
    case 0:
724
      return UNDEFINED; //Undefined
725
    case CPX_OPTIMAL://Optimal
726
      return OPTIMAL;
727
    case CPX_UNBOUNDED://Unbounded
728
      return INFEASIBLE;//In case of dual simplex
729
      //return UNBOUNDED;
730
    case CPX_INFEASIBLE://Infeasible
731
      //    case CPX_IT_LIM_INFEAS:
732
      //     case CPX_TIME_LIM_INFEAS:
733
      //     case CPX_NUM_BEST_INFEAS:
734
      //     case CPX_OPTIMAL_INFEAS:
735
      //     case CPX_ABORT_INFEAS:
736
      //     case CPX_ABORT_PRIM_INFEAS:
737
      //     case CPX_ABORT_PRIM_DUAL_INFEAS:
738
      return UNBOUNDED;//In case of dual simplex
739
      //return INFEASIBLE;
740
      //     case CPX_OBJ_LIM:
741
      //     case CPX_IT_LIM_FEAS:
742
      //     case CPX_TIME_LIM_FEAS:
743
      //     case CPX_NUM_BEST_FEAS:
744
      //     case CPX_ABORT_FEAS:
745
      //     case CPX_ABORT_PRIM_DUAL_FEAS:
746
      //       return FEASIBLE;
747
    default:
748
      return UNDEFINED; //Everything else comes here
749
      //FIXME error
750
    }
751
#endif
752
  }
753

	
754
  //9.0-as cplex verzio statusai
755
  // CPX_STAT_ABORT_DUAL_OBJ_LIM
756
  // CPX_STAT_ABORT_IT_LIM
757
  // CPX_STAT_ABORT_OBJ_LIM
758
  // CPX_STAT_ABORT_PRIM_OBJ_LIM
759
  // CPX_STAT_ABORT_TIME_LIM
760
  // CPX_STAT_ABORT_USER
761
  // CPX_STAT_FEASIBLE_RELAXED
762
  // CPX_STAT_INFEASIBLE
763
  // CPX_STAT_INForUNBD
764
  // CPX_STAT_NUM_BEST
765
  // CPX_STAT_OPTIMAL
766
  // CPX_STAT_OPTIMAL_FACE_UNBOUNDED
767
  // CPX_STAT_OPTIMAL_INFEAS
768
  // CPX_STAT_OPTIMAL_RELAXED
769
  // CPX_STAT_UNBOUNDED
770

	
771
  LpCplex::ProblemType LpCplex::_getDualType() const {
772
    int stat = CPXgetstat(cplexEnv(), _prob);
773
#if CPX_VERSION >= 800
774
    switch (stat) {
775
    case CPX_STAT_OPTIMAL:
776
      return OPTIMAL;
777
    case CPX_STAT_UNBOUNDED:
778
      return INFEASIBLE;
779
    default:
780
      return UNDEFINED;
781
    }
782
#else
783
    statusSwitch(cplexEnv(),stat);
784
    switch (stat) {
785
    case 0:
786
      return UNDEFINED; //Undefined
787
    case CPX_OPTIMAL://Optimal
788
      return OPTIMAL;
789
    case CPX_UNBOUNDED:
790
      return INFEASIBLE;
791
    default:
792
      return UNDEFINED; //Everything else comes here
793
      //FIXME error
794
    }
795
#endif
796
  }
797

	
798
  // MipCplex members
799

	
800
  MipCplex::MipCplex()
801
    : LpBase(), CplexBase(), MipSolver() {
802

	
803
#if CPX_VERSION < 800
804
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
805
#else
806
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
807
#endif
808
  }
809

	
810
  MipCplex::MipCplex(const CplexEnv& env)
811
    : LpBase(), CplexBase(env), MipSolver() {
812

	
813
#if CPX_VERSION < 800
814
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
815
#else
816
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
817
#endif
818

	
819
  }
820

	
821
  MipCplex::MipCplex(const MipCplex& other)
822
    : LpBase(), CplexBase(other), MipSolver() {}
823

	
824
  MipCplex::~MipCplex() {}
825

	
826
  MipCplex* MipCplex::_newSolver() const { return new MipCplex; }
827
  MipCplex* MipCplex::_cloneSolver() const {return new MipCplex(*this); }
828

	
829
  const char* MipCplex::_solverName() const { return "MipCplex"; }
830

	
831
  void MipCplex::_setColType(int i, MipCplex::ColTypes col_type) {
832

	
833
    // Note If a variable is to be changed to binary, a call to CPXchgbds
834
    // should also be made to change the bounds to 0 and 1.
835

	
836
    switch (col_type){
837
    case INTEGER: {
838
      const char t = 'I';
839
      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
840
    } break;
841
    case REAL: {
842
      const char t = 'C';
843
      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
844
    } break;
845
    default:
846
      break;
847
    }
848
  }
849

	
850
  MipCplex::ColTypes MipCplex::_getColType(int i) const {
851
    char t;
852
    CPXgetctype (cplexEnv(), _prob, &t, i, i);
853
    switch (t) {
854
    case 'I':
855
      return INTEGER;
856
    case 'C':
857
      return REAL;
858
    default:
859
      LEMON_ASSERT(false, "Invalid column type");
860
      return ColTypes();
861
    }
862

	
863
  }
864

	
865
  MipCplex::SolveExitStatus MipCplex::_solve() {
866
    int status;
867
    status = CPXmipopt (cplexEnv(), _prob);
868
    if (status==0)
869
      return SOLVED;
870
    else
871
      return UNSOLVED;
872

	
873
  }
874

	
875

	
876
  MipCplex::ProblemType MipCplex::_getType() const {
877

	
878
    int stat = CPXgetstat(cplexEnv(), _prob);
879

	
880
    //Fortunately, MIP statuses did not change for cplex 8.0
881
    switch (stat) {
882
    case CPXMIP_OPTIMAL:
883
      // Optimal integer solution has been found.
884
    case CPXMIP_OPTIMAL_TOL:
885
      // Optimal soluton with the tolerance defined by epgap or epagap has
886
      // been found.
887
      return OPTIMAL;
888
      //This also exists in later issues
889
      //    case CPXMIP_UNBOUNDED:
890
      //return UNBOUNDED;
891
      case CPXMIP_INFEASIBLE:
892
        return INFEASIBLE;
893
    default:
894
      return UNDEFINED;
895
    }
896
    //Unboundedness not treated well: the following is from cplex 9.0 doc
897
    // About Unboundedness
898

	
899
    // The treatment of models that are unbounded involves a few
900
    // subtleties. Specifically, a declaration of unboundedness means that
901
    // ILOG CPLEX has determined that the model has an unbounded
902
    // ray. Given any feasible solution x with objective z, a multiple of
903
    // the unbounded ray can be added to x to give a feasible solution
904
    // with objective z-1 (or z+1 for maximization models). Thus, if a
905
    // feasible solution exists, then the optimal objective is
906
    // unbounded. Note that ILOG CPLEX has not necessarily concluded that
907
    // a feasible solution exists. Users can call the routine CPXsolninfo
908
    // to determine whether ILOG CPLEX has also concluded that the model
909
    // has a feasible solution.
910
  }
911

	
912
  MipCplex::Value MipCplex::_getSol(int i) const {
913
    Value x;
914
    CPXgetmipx(cplexEnv(), _prob, &x, i, i);
915
    return x;
916
  }
917

	
918
  MipCplex::Value MipCplex::_getSolValue() const {
919
    Value objval;
920
    CPXgetmipobjval(cplexEnv(), _prob, &objval);
921
    return objval;
922
  }
923

	
924
} //namespace lemon
925

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#ifndef LEMON_LP_CPLEX_H
20
#define LEMON_LP_CPLEX_H
21

	
22
///\file
23
///\brief Header of the LEMON-CPLEX lp solver interface.
24

	
25
#include <lemon/lp_base.h>
26

	
27
struct cpxenv;
28
struct cpxlp;
29

	
30
namespace lemon {
31

	
32
  /// \brief Reference counted wrapper around cpxenv pointer
33
  ///
34
  /// The cplex uses environment object which is responsible for
35
  /// checking the proper license usage. This class provides a simple
36
  /// interface for share the environment object between different
37
  /// problems.
38
  class CplexEnv {
39
    friend class CplexBase;
40
  private:
41
    cpxenv* _env;
42
    mutable int* _cnt;
43

	
44
  public:
45

	
46
    /// \brief This exception is thrown when the license check is not
47
    /// sufficient
48
    class LicenseError : public Exception {
49
      friend class CplexEnv;
50
    private:
51

	
52
      LicenseError(int status);
53
      char _message[510];
54

	
55
    public:
56

	
57
      /// The short error message
58
      virtual const char* what() const throw() {
59
        return _message;
60
      }
61
    };
62

	
63
    /// Constructor
64
    CplexEnv();
65
    /// Shallow copy constructor
66
    CplexEnv(const CplexEnv&);
67
    /// Shallow assignement
68
    CplexEnv& operator=(const CplexEnv&);
69
    /// Destructor
70
    virtual ~CplexEnv();
71

	
72
  protected:
73

	
74
    cpxenv* cplexEnv() { return _env; }
75
    const cpxenv* cplexEnv() const { return _env; }
76
  };
77

	
78
  /// \brief Base interface for the CPLEX LP and MIP solver
79
  ///
80
  /// This class implements the common interface of the CPLEX LP and
81
  /// MIP solvers.  
82
  /// \ingroup lp_group
83
  class CplexBase : virtual public LpBase {
84
  protected:
85

	
86
    CplexEnv _env;
87
    cpxlp* _prob;
88

	
89
    CplexBase();
90
    CplexBase(const CplexEnv&);
91
    CplexBase(const CplexBase &);
92
    virtual ~CplexBase();
93

	
94
    virtual int _addCol();
95
    virtual int _addRow();
96

	
97
    virtual void _eraseCol(int i);
98
    virtual void _eraseRow(int i);
99

	
100
    virtual void _eraseColId(int i);
101
    virtual void _eraseRowId(int i);
102

	
103
    virtual void _getColName(int col, std::string& name) const;
104
    virtual void _setColName(int col, const std::string& name);
105
    virtual int _colByName(const std::string& name) const;
106

	
107
    virtual void _getRowName(int row, std::string& name) const;
108
    virtual void _setRowName(int row, const std::string& name);
109
    virtual int _rowByName(const std::string& name) const;
110

	
111
    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
112
    virtual void _getRowCoeffs(int i, InsertIterator b) const;
113

	
114
    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
115
    virtual void _getColCoeffs(int i, InsertIterator b) const;
116

	
117
    virtual void _setCoeff(int row, int col, Value value);
118
    virtual Value _getCoeff(int row, int col) const;
119

	
120
    virtual void _setColLowerBound(int i, Value value);
121
    virtual Value _getColLowerBound(int i) const;
122

	
123
    virtual void _setColUpperBound(int i, Value value);
124
    virtual Value _getColUpperBound(int i) const;
125

	
126
  private:
127
    void _set_row_bounds(int i, Value lb, Value ub);
128
  protected:
129

	
130
    virtual void _setRowLowerBound(int i, Value value);
131
    virtual Value _getRowLowerBound(int i) const;
132

	
133
    virtual void _setRowUpperBound(int i, Value value);
134
    virtual Value _getRowUpperBound(int i) const;
135

	
136
    virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
137
    virtual void _getObjCoeffs(InsertIterator b) const;
138

	
139
    virtual void _setObjCoeff(int i, Value obj_coef);
140
    virtual Value _getObjCoeff(int i) const;
141

	
142
    virtual void _setSense(Sense sense);
143
    virtual Sense _getSense() const;
144

	
145
    virtual void _clear();
146

	
147
  public:
148

	
149
    /// Returns the used \c CplexEnv instance
150
    const CplexEnv& env() const { return _env; }
151
    ///
152
    const cpxenv* cplexEnv() const { return _env.cplexEnv(); }
153

	
154
    cpxlp* cplexLp() { return _prob; }
155
    const cpxlp* cplexLp() const { return _prob; }
156

	
157
  };
158

	
159
  /// \brief Interface for the CPLEX LP solver
160
  ///
161
  /// This class implements an interface for the CPLEX LP solver.
162
  ///\ingroup lp_group
163
  class LpCplex : public CplexBase, public LpSolver {
164
  public:
165
    /// \e
166
    LpCplex();
167
    /// \e
168
    LpCplex(const CplexEnv&);
169
    /// \e
170
    LpCplex(const LpCplex&);
171
    /// \e
172
    virtual ~LpCplex();
173

	
174
  private:
175

	
176
    // these values cannot retrieved element by element
177
    mutable std::vector<int> _col_status;
178
    mutable std::vector<int> _row_status;
179

	
180
    mutable std::vector<Value> _primal_ray;
181
    mutable std::vector<Value> _dual_ray;
182

	
183
    void _clear_temporals();
184

	
185
    SolveExitStatus convertStatus(int status);
186

	
187
  protected:
188

	
189
    virtual LpCplex* _cloneSolver() const;
190
    virtual LpCplex* _newSolver() const;
191

	
192
    virtual const char* _solverName() const;
193

	
194
    virtual SolveExitStatus _solve();
195
    virtual Value _getPrimal(int i) const;
196
    virtual Value _getDual(int i) const;
197
    virtual Value _getPrimalValue() const;
198

	
199
    virtual VarStatus _getColStatus(int i) const;
200
    virtual VarStatus _getRowStatus(int i) const;
201

	
202
    virtual Value _getPrimalRay(int i) const;
203
    virtual Value _getDualRay(int i) const;
204

	
205
    virtual ProblemType _getPrimalType() const;
206
    virtual ProblemType _getDualType() const;
207

	
208
  public:
209

	
210
    /// Solve with primal simplex method
211
    SolveExitStatus solvePrimal();
212

	
213
    /// Solve with dual simplex method
214
    SolveExitStatus solveDual();
215

	
216
    /// Solve with barrier method
217
    SolveExitStatus solveBarrier();
218

	
219
  };
220

	
221
  /// \brief Interface for the CPLEX MIP solver
222
  ///
223
  /// This class implements an interface for the CPLEX MIP solver.
224
  ///\ingroup lp_group
225
  class MipCplex : public CplexBase, public MipSolver {
226
  public:
227
    /// \e
228
    MipCplex();
229
    /// \e
230
    MipCplex(const CplexEnv&);
231
    /// \e
232
    MipCplex(const MipCplex&);
233
    /// \e
234
    virtual ~MipCplex();
235

	
236
  protected:
237

	
238
    virtual MipCplex* _cloneSolver() const;
239
    virtual MipCplex* _newSolver() const;
240

	
241
    virtual const char* _solverName() const;
242

	
243
    virtual ColTypes _getColType(int col) const;
244
    virtual void _setColType(int col, ColTypes col_type);
245

	
246
    virtual SolveExitStatus _solve();
247
    virtual ProblemType _getType() const;
248
    virtual Value _getSol(int i) const;
249
    virtual Value _getSolValue() const;
250

	
251
  };
252

	
253
} //END OF NAMESPACE LEMON
254

	
255
#endif //LEMON_LP_CPLEX_H
256

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
///\file
20
///\brief Implementation of the LEMON GLPK LP and MIP solver interface.
21

	
22
#include <lemon/lp_glpk.h>
23
#include <glpk.h>
24

	
25
#include <lemon/assert.h>
26

	
27
namespace lemon {
28

	
29
  // GlpkBase members
30

	
31
  GlpkBase::GlpkBase() : LpBase() {
32
    lp = glp_create_prob();
33
    glp_create_index(lp);
34
  }
35

	
36
  GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() {
37
    lp = glp_create_prob();
38
    glp_copy_prob(lp, other.lp, GLP_ON);
39
    glp_create_index(lp);
40
    rows = other.rows;
41
    cols = other.cols;
42
  }
43

	
44
  GlpkBase::~GlpkBase() {
45
    glp_delete_prob(lp);
46
  }
47

	
48
  int GlpkBase::_addCol() {
49
    int i = glp_add_cols(lp, 1);
50
    glp_set_col_bnds(lp, i, GLP_FR, 0.0, 0.0);
51
    return i;
52
  }
53

	
54
  int GlpkBase::_addRow() {
55
    int i = glp_add_rows(lp, 1);
56
    glp_set_row_bnds(lp, i, GLP_FR, 0.0, 0.0);
57
    return i;
58
  }
59

	
60
  void GlpkBase::_eraseCol(int i) {
61
    int ca[2];
62
    ca[1] = i;
63
    glp_del_cols(lp, 1, ca);
64
  }
65

	
66
  void GlpkBase::_eraseRow(int i) {
67
    int ra[2];
68
    ra[1] = i;
69
    glp_del_rows(lp, 1, ra);
70
  }
71

	
72
  void GlpkBase::_eraseColId(int i) {
73
    cols.eraseIndex(i);
74
    cols.shiftIndices(i);
75
  }
76

	
77
  void GlpkBase::_eraseRowId(int i) {
78
    rows.eraseIndex(i);
79
    rows.shiftIndices(i);
80
  }
81

	
82
  void GlpkBase::_getColName(int c, std::string& name) const {
83
    const char *str = glp_get_col_name(lp, c);
84
    if (str) name = str;
85
    else name.clear();
86
  }
87

	
88
  void GlpkBase::_setColName(int c, const std::string & name) {
89
    glp_set_col_name(lp, c, const_cast<char*>(name.c_str()));
90

	
91
  }
92

	
93
  int GlpkBase::_colByName(const std::string& name) const {
94
    int k = glp_find_col(lp, const_cast<char*>(name.c_str()));
95
    return k > 0 ? k : -1;
96
  }
97

	
98
  void GlpkBase::_getRowName(int r, std::string& name) const {
99
    const char *str = glp_get_row_name(lp, r);
100
    if (str) name = str;
101
    else name.clear();
102
  }
103

	
104
  void GlpkBase::_setRowName(int r, const std::string & name) {
105
    glp_set_row_name(lp, r, const_cast<char*>(name.c_str()));
106

	
107
  }
108

	
109
  int GlpkBase::_rowByName(const std::string& name) const {
110
    int k = glp_find_row(lp, const_cast<char*>(name.c_str()));
111
    return k > 0 ? k : -1;
112
  }
113

	
114
  void GlpkBase::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
115
    std::vector<int> indexes;
116
    std::vector<Value> values;
117

	
118
    indexes.push_back(0);
119
    values.push_back(0);
120

	
121
    for(ExprIterator it = b; it != e; ++it) {
122
      indexes.push_back(it->first);
123
      values.push_back(it->second);
124
    }
125

	
126
    glp_set_mat_row(lp, i, values.size() - 1,
127
                    &indexes.front(), &values.front());
128
  }
129

	
130
  void GlpkBase::_getRowCoeffs(int ix, InsertIterator b) const {
131
    int length = glp_get_mat_row(lp, ix, 0, 0);
132

	
133
    std::vector<int> indexes(length + 1);
134
    std::vector<Value> values(length + 1);
135

	
136
    glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
137

	
138
    for (int i = 1; i <= length; ++i) {
139
      *b = std::make_pair(indexes[i], values[i]);
140
      ++b;
141
    }
142
  }
143

	
144
  void GlpkBase::_setColCoeffs(int ix, ExprIterator b,
145
                                     ExprIterator e) {
146

	
147
    std::vector<int> indexes;
148
    std::vector<Value> values;
149

	
150
    indexes.push_back(0);
151
    values.push_back(0);
152

	
153
    for(ExprIterator it = b; it != e; ++it) {
154
      indexes.push_back(it->first);
155
      values.push_back(it->second);
156
    }
157

	
158
    glp_set_mat_col(lp, ix, values.size() - 1,
159
                    &indexes.front(), &values.front());
160
  }
161

	
162
  void GlpkBase::_getColCoeffs(int ix, InsertIterator b) const {
163
    int length = glp_get_mat_col(lp, ix, 0, 0);
164

	
165
    std::vector<int> indexes(length + 1);
166
    std::vector<Value> values(length + 1);
167

	
168
    glp_get_mat_col(lp, ix, &indexes.front(), &values.front());
169

	
170
    for (int i = 1; i  <= length; ++i) {
171
      *b = std::make_pair(indexes[i], values[i]);
172
      ++b;
173
    }
174
  }
175

	
176
  void GlpkBase::_setCoeff(int ix, int jx, Value value) {
177

	
178
    if (glp_get_num_cols(lp) < glp_get_num_rows(lp)) {
179

	
180
      int length = glp_get_mat_row(lp, ix, 0, 0);
181

	
182
      std::vector<int> indexes(length + 2);
183
      std::vector<Value> values(length + 2);
184

	
185
      glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
186

	
187
      //The following code does not suppose that the elements of the
188
      //array indexes are sorted
189
      bool found = false;
190
      for (int i = 1; i  <= length; ++i) {
191
        if (indexes[i] == jx) {
192
          found = true;
193
          values[i] = value;
194
          break;
195
        }
196
      }
197
      if (!found) {
198
        ++length;
199
        indexes[length] = jx;
200
        values[length] = value;
201
      }
202

	
203
      glp_set_mat_row(lp, ix, length, &indexes.front(), &values.front());
204

	
205
    } else {
206

	
207
      int length = glp_get_mat_col(lp, jx, 0, 0);
208

	
209
      std::vector<int> indexes(length + 2);
210
      std::vector<Value> values(length + 2);
211

	
212
      glp_get_mat_col(lp, jx, &indexes.front(), &values.front());
213

	
214
      //The following code does not suppose that the elements of the
215
      //array indexes are sorted
216
      bool found = false;
217
      for (int i = 1; i <= length; ++i) {
218
        if (indexes[i] == ix) {
219
          found = true;
220
          values[i] = value;
221
          break;
222
        }
223
      }
224
      if (!found) {
225
        ++length;
226
        indexes[length] = ix;
227
        values[length] = value;
228
      }
229

	
230
      glp_set_mat_col(lp, jx, length, &indexes.front(), &values.front());
231
    }
232

	
233
  }
234

	
235
  GlpkBase::Value GlpkBase::_getCoeff(int ix, int jx) const {
236

	
237
    int length = glp_get_mat_row(lp, ix, 0, 0);
238

	
239
    std::vector<int> indexes(length + 1);
240
    std::vector<Value> values(length + 1);
241

	
242
    glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
243

	
244
    for (int i = 1; i  <= length; ++i) {
245
      if (indexes[i] == jx) {
246
        return values[i];
247
      }
248
    }
249

	
250
    return 0;
251
  }
252

	
253
  void GlpkBase::_setColLowerBound(int i, Value lo) {
254
    LEMON_ASSERT(lo != INF, "Invalid bound");
255

	
256
    int b = glp_get_col_type(lp, i);
257
    double up = glp_get_col_ub(lp, i);
258
    if (lo == -INF) {
259
      switch (b) {
260
      case GLP_FR:
261
      case GLP_LO:
262
        glp_set_col_bnds(lp, i, GLP_FR, lo, up);
263
        break;
264
      case GLP_UP:
265
        break;
266
      case GLP_DB:
267
      case GLP_FX:
268
        glp_set_col_bnds(lp, i, GLP_UP, lo, up);
269
        break;
270
      default:
271
        break;
272
      }
273
    } else {
274
      switch (b) {
275
      case GLP_FR:
276
      case GLP_LO:
277
        glp_set_col_bnds(lp, i, GLP_LO, lo, up);
278
        break;
279
      case GLP_UP:
280
      case GLP_DB:
281
      case GLP_FX:
282
        if (lo == up)
283
          glp_set_col_bnds(lp, i, GLP_FX, lo, up);
284
        else
285
          glp_set_col_bnds(lp, i, GLP_DB, lo, up);
286
        break;
287
      default:
288
        break;
289
      }
290
    }
291
  }
292

	
293
  GlpkBase::Value GlpkBase::_getColLowerBound(int i) const {
294
    int b = glp_get_col_type(lp, i);
295
    switch (b) {
296
    case GLP_LO:
297
    case GLP_DB:
298
    case GLP_FX:
299
      return glp_get_col_lb(lp, i);
300
    default:
301
      return -INF;
302
    }
303
  }
304

	
305
  void GlpkBase::_setColUpperBound(int i, Value up) {
306
    LEMON_ASSERT(up != -INF, "Invalid bound");
307

	
308
    int b = glp_get_col_type(lp, i);
309
    double lo = glp_get_col_lb(lp, i);
310
    if (up == INF) {
311
      switch (b) {
312
      case GLP_FR:
313
      case GLP_LO:
314
        break;
315
      case GLP_UP:
316
        glp_set_col_bnds(lp, i, GLP_FR, lo, up);
317
        break;
318
      case GLP_DB:
319
      case GLP_FX:
320
        glp_set_col_bnds(lp, i, GLP_LO, lo, up);
321
        break;
322
      default:
323
        break;
324
      }
325
    } else {
326
      switch (b) {
327
      case GLP_FR:
328
        glp_set_col_bnds(lp, i, GLP_UP, lo, up);
329
        break;
330
      case GLP_UP:
331
        glp_set_col_bnds(lp, i, GLP_UP, lo, up);
332
        break;
333
      case GLP_LO:
334
      case GLP_DB:
335
      case GLP_FX:
336
        if (lo == up)
337
          glp_set_col_bnds(lp, i, GLP_FX, lo, up);
338
        else
339
          glp_set_col_bnds(lp, i, GLP_DB, lo, up);
340
        break;
341
      default:
342
        break;
343
      }
344
    }
345

	
346
  }
347

	
348
  GlpkBase::Value GlpkBase::_getColUpperBound(int i) const {
349
    int b = glp_get_col_type(lp, i);
350
      switch (b) {
351
      case GLP_UP:
352
      case GLP_DB:
353
      case GLP_FX:
354
        return glp_get_col_ub(lp, i);
355
      default:
356
        return INF;
357
      }
358
  }
359

	
360
  void GlpkBase::_setRowLowerBound(int i, Value lo) {
361
    LEMON_ASSERT(lo != INF, "Invalid bound");
362

	
363
    int b = glp_get_row_type(lp, i);
364
    double up = glp_get_row_ub(lp, i);
365
    if (lo == -INF) {
366
      switch (b) {
367
      case GLP_FR:
368
      case GLP_LO:
369
        glp_set_row_bnds(lp, i, GLP_FR, lo, up);
370
        break;
371
      case GLP_UP:
372
        break;
373
      case GLP_DB:
374
      case GLP_FX:
375
        glp_set_row_bnds(lp, i, GLP_UP, lo, up);
376
        break;
377
      default:
378
        break;
379
      }
380
    } else {
381
      switch (b) {
382
      case GLP_FR:
383
      case GLP_LO:
384
        glp_set_row_bnds(lp, i, GLP_LO, lo, up);
385
        break;
386
      case GLP_UP:
387
      case GLP_DB:
388
      case GLP_FX:
389
        if (lo == up)
390
          glp_set_row_bnds(lp, i, GLP_FX, lo, up);
391
        else
392
          glp_set_row_bnds(lp, i, GLP_DB, lo, up);
393
        break;
394
      default:
395
        break;
396
      }
397
    }
398

	
399
  }
400

	
401
  GlpkBase::Value GlpkBase::_getRowLowerBound(int i) const {
402
    int b = glp_get_row_type(lp, i);
403
    switch (b) {
404
    case GLP_LO:
405
    case GLP_DB:
406
    case GLP_FX:
407
      return glp_get_row_lb(lp, i);
408
    default:
409
      return -INF;
410
    }
411
  }
412

	
413
  void GlpkBase::_setRowUpperBound(int i, Value up) {
414
    LEMON_ASSERT(up != -INF, "Invalid bound");
415

	
416
    int b = glp_get_row_type(lp, i);
417
    double lo = glp_get_row_lb(lp, i);
418
    if (up == INF) {
419
      switch (b) {
420
      case GLP_FR:
421
      case GLP_LO:
422
        break;
423
      case GLP_UP:
424
        glp_set_row_bnds(lp, i, GLP_FR, lo, up);
425
        break;
426
      case GLP_DB:
427
      case GLP_FX:
428
        glp_set_row_bnds(lp, i, GLP_LO, lo, up);
429
        break;
430
      default:
431
        break;
432
      }
433
    } else {
434
      switch (b) {
435
      case GLP_FR:
436
        glp_set_row_bnds(lp, i, GLP_UP, lo, up);
437
        break;
438
      case GLP_UP:
439
        glp_set_row_bnds(lp, i, GLP_UP, lo, up);
440
        break;
441
      case GLP_LO:
442
      case GLP_DB:
443
      case GLP_FX:
444
        if (lo == up)
445
          glp_set_row_bnds(lp, i, GLP_FX, lo, up);
446
        else
447
          glp_set_row_bnds(lp, i, GLP_DB, lo, up);
448
        break;
449
      default:
450
        break;
451
      }
452
    }
453
  }
454

	
455
  GlpkBase::Value GlpkBase::_getRowUpperBound(int i) const {
456
    int b = glp_get_row_type(lp, i);
457
    switch (b) {
458
    case GLP_UP:
459
    case GLP_DB:
460
    case GLP_FX:
461
      return glp_get_row_ub(lp, i);
462
    default:
463
      return INF;
464
    }
465
  }
466

	
467
  void GlpkBase::_setObjCoeffs(ExprIterator b, ExprIterator e) {
468
    for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
469
      glp_set_obj_coef(lp, i, 0.0);
470
    }
471
    for (ExprIterator it = b; it != e; ++it) {
472
      glp_set_obj_coef(lp, it->first, it->second);
473
    }
474
  }
475

	
476
  void GlpkBase::_getObjCoeffs(InsertIterator b) const {
477
    for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
478
      Value val = glp_get_obj_coef(lp, i);
479
      if (val != 0.0) {
480
        *b = std::make_pair(i, val);
481
        ++b;
482
      }
483
    }
484
  }
485

	
486
  void GlpkBase::_setObjCoeff(int i, Value obj_coef) {
487
    //i = 0 means the constant term (shift)
488
    glp_set_obj_coef(lp, i, obj_coef);
489
  }
490

	
491
  GlpkBase::Value GlpkBase::_getObjCoeff(int i) const {
492
    //i = 0 means the constant term (shift)
493
    return glp_get_obj_coef(lp, i);
494
  }
495

	
496
  void GlpkBase::_setSense(GlpkBase::Sense sense) {
497
    switch (sense) {
498
    case MIN:
499
      glp_set_obj_dir(lp, GLP_MIN);
500
      break;
501
    case MAX:
502
      glp_set_obj_dir(lp, GLP_MAX);
503
      break;
504
    }
505
  }
506

	
507
  GlpkBase::Sense GlpkBase::_getSense() const {
508
    switch(glp_get_obj_dir(lp)) {
509
    case GLP_MIN:
510
      return MIN;
511
    case GLP_MAX:
512
      return MAX;
513
    default:
514
      LEMON_ASSERT(false, "Wrong sense");
515
      return GlpkBase::Sense();
516
    }
517
  }
518

	
519
  void GlpkBase::_clear() {
520
    glp_erase_prob(lp);
521
    rows.clear();
522
    cols.clear();
523
  }
524

	
525
  // LpGlpk members
526

	
527
  LpGlpk::LpGlpk()
528
    : LpBase(), GlpkBase(), LpSolver() {
529
    messageLevel(MESSAGE_NO_OUTPUT);
530
  }
531

	
532
  LpGlpk::LpGlpk(const LpGlpk& other)
533
    : LpBase(other), GlpkBase(other), LpSolver(other) {
534
    messageLevel(MESSAGE_NO_OUTPUT);
535
  }
536

	
537
  LpGlpk* LpGlpk::_newSolver() const { return new LpGlpk; }
538
  LpGlpk* LpGlpk::_cloneSolver() const { return new LpGlpk(*this); }
539

	
540
  const char* LpGlpk::_solverName() const { return "LpGlpk"; }
541

	
542
  void LpGlpk::_clear_temporals() {
543
    _primal_ray.clear();
544
    _dual_ray.clear();
545
  }
546

	
547
  LpGlpk::SolveExitStatus LpGlpk::_solve() {
548
    return solvePrimal();
549
  }
550

	
551
  LpGlpk::SolveExitStatus LpGlpk::solvePrimal() {
552
    _clear_temporals();
553

	
554
    glp_smcp smcp;
555
    glp_init_smcp(&smcp);
556

	
557
    switch (_message_level) {
558
    case MESSAGE_NO_OUTPUT:
559
      smcp.msg_lev = GLP_MSG_OFF;
560
      break;
561
    case MESSAGE_ERROR_MESSAGE:
562
      smcp.msg_lev = GLP_MSG_ERR;
563
      break;
564
    case MESSAGE_NORMAL_OUTPUT:
565
      smcp.msg_lev = GLP_MSG_ON;
566
      break;
567
    case MESSAGE_FULL_OUTPUT:
568
      smcp.msg_lev = GLP_MSG_ALL;
569
      break;
570
    }
571

	
572
    if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
573
    return SOLVED;
574
  }
575

	
576
  LpGlpk::SolveExitStatus LpGlpk::solveDual() {
577
    _clear_temporals();
578

	
579
    glp_smcp smcp;
580
    glp_init_smcp(&smcp);
581

	
582
    switch (_message_level) {
583
    case MESSAGE_NO_OUTPUT:
584
      smcp.msg_lev = GLP_MSG_OFF;
585
      break;
586
    case MESSAGE_ERROR_MESSAGE:
587
      smcp.msg_lev = GLP_MSG_ERR;
588
      break;
589
    case MESSAGE_NORMAL_OUTPUT:
590
      smcp.msg_lev = GLP_MSG_ON;
591
      break;
592
    case MESSAGE_FULL_OUTPUT:
593
      smcp.msg_lev = GLP_MSG_ALL;
594
      break;
595
    }
596
    smcp.meth = GLP_DUAL;
597

	
598
    if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
599
    return SOLVED;
600
  }
601

	
602
  LpGlpk::Value LpGlpk::_getPrimal(int i) const {
603
    return glp_get_col_prim(lp, i);
604
  }
605

	
606
  LpGlpk::Value LpGlpk::_getDual(int i) const {
607
    return glp_get_row_dual(lp, i);
608
  }
609

	
610
  LpGlpk::Value LpGlpk::_getPrimalValue() const {
611
    return glp_get_obj_val(lp);
612
  }
613

	
614
  LpGlpk::VarStatus LpGlpk::_getColStatus(int i) const {
615
    switch (glp_get_col_stat(lp, i)) {
616
    case GLP_BS:
617
      return BASIC;
618
    case GLP_UP:
619
      return UPPER;
620
    case GLP_LO:
621
      return LOWER;
622
    case GLP_NF:
623
      return FREE;
624
    case GLP_NS:
625
      return FIXED;
626
    default:
627
      LEMON_ASSERT(false, "Wrong column status");
628
      return LpGlpk::VarStatus();
629
    }
630
  }
631

	
632
  LpGlpk::VarStatus LpGlpk::_getRowStatus(int i) const {
633
    switch (glp_get_row_stat(lp, i)) {
634
    case GLP_BS:
635
      return BASIC;
636
    case GLP_UP:
637
      return UPPER;
638
    case GLP_LO:
639
      return LOWER;
640
    case GLP_NF:
641
      return FREE;
642
    case GLP_NS:
643
      return FIXED;
644
    default:
645
      LEMON_ASSERT(false, "Wrong row status");
646
      return LpGlpk::VarStatus();
647
    }
648
  }
649

	
650
  LpGlpk::Value LpGlpk::_getPrimalRay(int i) const {
651
    if (_primal_ray.empty()) {
652
      int row_num = glp_get_num_rows(lp);
653
      int col_num = glp_get_num_cols(lp);
654

	
655
      _primal_ray.resize(col_num + 1, 0.0);
656

	
657
      int index = glp_get_unbnd_ray(lp);
658
      if (index != 0) {
659
        // The primal ray is found in primal simplex second phase
660
        LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
661
                      glp_get_col_stat(lp, index - row_num)) != GLP_BS,
662
                     "Wrong primal ray");
663

	
664
        bool negate = glp_get_obj_dir(lp) == GLP_MAX;
665

	
666
        if (index > row_num) {
667
          _primal_ray[index - row_num] = 1.0;
668
          if (glp_get_col_dual(lp, index - row_num) > 0) {
669
            negate = !negate;
670
          }
671
        } else {
672
          if (glp_get_row_dual(lp, index) > 0) {
673
            negate = !negate;
674
          }
675
        }
676

	
677
        std::vector<int> ray_indexes(row_num + 1);
678
        std::vector<Value> ray_values(row_num + 1);
679
        int ray_length = glp_eval_tab_col(lp, index, &ray_indexes.front(),
680
                                          &ray_values.front());
681

	
682
        for (int i = 1; i <= ray_length; ++i) {
683
          if (ray_indexes[i] > row_num) {
684
            _primal_ray[ray_indexes[i] - row_num] = ray_values[i];
685
          }
686
        }
687

	
688
        if (negate) {
689
          for (int i = 1; i <= col_num; ++i) {
690
            _primal_ray[i] = - _primal_ray[i];
691
          }
692
        }
693
      } else {
694
        for (int i = 1; i <= col_num; ++i) {
695
          _primal_ray[i] = glp_get_col_prim(lp, i);
696
        }
697
      }
698
    }
699
    return _primal_ray[i];
700
  }
701

	
702
  LpGlpk::Value LpGlpk::_getDualRay(int i) const {
703
    if (_dual_ray.empty()) {
704
      int row_num = glp_get_num_rows(lp);
705

	
706
      _dual_ray.resize(row_num + 1, 0.0);
707

	
708
      int index = glp_get_unbnd_ray(lp);
709
      if (index != 0) {
710
        // The dual ray is found in dual simplex second phase
711
        LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
712
                      glp_get_col_stat(lp, index - row_num)) == GLP_BS,
713

	
714
                     "Wrong dual ray");
715

	
716
        int idx;
717
        bool negate = false;
718

	
719
        if (index > row_num) {
720
          idx = glp_get_col_bind(lp, index - row_num);
721
          if (glp_get_col_prim(lp, index - row_num) >
722
              glp_get_col_ub(lp, index - row_num)) {
723
            negate = true;
724
          }
725
        } else {
726
          idx = glp_get_row_bind(lp, index);
727
          if (glp_get_row_prim(lp, index) > glp_get_row_ub(lp, index)) {
728
            negate = true;
729
          }
730
        }
731

	
732
        _dual_ray[idx] = negate ?  - 1.0 : 1.0;
733

	
734
        glp_btran(lp, &_dual_ray.front());
735
      } else {
736
        double eps = 1e-7;
737
        // The dual ray is found in primal simplex first phase
738
        // We assume that the glpk minimizes the slack to get feasible solution
739
        for (int i = 1; i <= row_num; ++i) {
740
          int index = glp_get_bhead(lp, i);
741
          if (index <= row_num) {
742
            double res = glp_get_row_prim(lp, index);
743
            if (res > glp_get_row_ub(lp, index) + eps) {
744
              _dual_ray[i] = -1;
745
            } else if (res < glp_get_row_lb(lp, index) - eps) {
746
              _dual_ray[i] = 1;
747
            } else {
748
              _dual_ray[i] = 0;
749
            }
750
            _dual_ray[i] *= glp_get_rii(lp, index);
751
          } else {
752
            double res = glp_get_col_prim(lp, index - row_num);
753
            if (res > glp_get_col_ub(lp, index - row_num) + eps) {
754
              _dual_ray[i] = -1;
755
            } else if (res < glp_get_col_lb(lp, index - row_num) - eps) {
756
              _dual_ray[i] = 1;
757
            } else {
758
              _dual_ray[i] = 0;
759
            }
760
            _dual_ray[i] /= glp_get_sjj(lp, index - row_num);
761
          }
762
        }
763

	
764
        glp_btran(lp, &_dual_ray.front());
765

	
766
        for (int i = 1; i <= row_num; ++i) {
767
          _dual_ray[i] /= glp_get_rii(lp, i);
768
        }
769
      }
770
    }
771
    return _dual_ray[i];
772
  }
773

	
774
  LpGlpk::ProblemType LpGlpk::_getPrimalType() const {
775
    if (glp_get_status(lp) == GLP_OPT)
776
      return OPTIMAL;
777
    switch (glp_get_prim_stat(lp)) {
778
    case GLP_UNDEF:
779
      return UNDEFINED;
780
    case GLP_FEAS:
781
    case GLP_INFEAS:
782
      if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
783
        return UNBOUNDED;
784
      } else {
785
        return UNDEFINED;
786
      }
787
    case GLP_NOFEAS:
788
      return INFEASIBLE;
789
    default:
790
      LEMON_ASSERT(false, "Wrong primal type");
791
      return  LpGlpk::ProblemType();
792
    }
793
  }
794

	
795
  LpGlpk::ProblemType LpGlpk::_getDualType() const {
796
    if (glp_get_status(lp) == GLP_OPT)
797
      return OPTIMAL;
798
    switch (glp_get_dual_stat(lp)) {
799
    case GLP_UNDEF:
800
      return UNDEFINED;
801
    case GLP_FEAS:
802
    case GLP_INFEAS:
803
      if (glp_get_prim_stat(lp) == GLP_NOFEAS) {
804
        return UNBOUNDED;
805
      } else {
806
        return UNDEFINED;
807
      }
808
    case GLP_NOFEAS:
809
      return INFEASIBLE;
810
    default:
811
      LEMON_ASSERT(false, "Wrong primal type");
812
      return  LpGlpk::ProblemType();
813
    }
814
  }
815

	
816
  void LpGlpk::presolver(bool b) {
817
    lpx_set_int_parm(lp, LPX_K_PRESOL, b ? 1 : 0);
818
  }
819

	
820
  void LpGlpk::messageLevel(MessageLevel m) {
821
    _message_level = m;
822
  }
823

	
824
  // MipGlpk members
825

	
826
  MipGlpk::MipGlpk()
827
    : LpBase(), GlpkBase(), MipSolver() {
828
    messageLevel(MESSAGE_NO_OUTPUT);
829
  }
830

	
831
  MipGlpk::MipGlpk(const MipGlpk& other)
832
    : LpBase(), GlpkBase(other), MipSolver() {
833
    messageLevel(MESSAGE_NO_OUTPUT);
834
  }
835

	
836
  void MipGlpk::_setColType(int i, MipGlpk::ColTypes col_type) {
837
    switch (col_type) {
838
    case INTEGER:
839
      glp_set_col_kind(lp, i, GLP_IV);
840
      break;
841
    case REAL:
842
      glp_set_col_kind(lp, i, GLP_CV);
843
      break;
844
    }
845
  }
846

	
847
  MipGlpk::ColTypes MipGlpk::_getColType(int i) const {
848
    switch (glp_get_col_kind(lp, i)) {
849
    case GLP_IV:
850
    case GLP_BV:
851
      return INTEGER;
852
    default:
853
      return REAL;
854
    }
855

	
856
  }
857

	
858
  MipGlpk::SolveExitStatus MipGlpk::_solve() {
859
    glp_smcp smcp;
860
    glp_init_smcp(&smcp);
861

	
862
    switch (_message_level) {
863
    case MESSAGE_NO_OUTPUT:
864
      smcp.msg_lev = GLP_MSG_OFF;
865
      break;
866
    case MESSAGE_ERROR_MESSAGE:
867
      smcp.msg_lev = GLP_MSG_ERR;
868
      break;
869
    case MESSAGE_NORMAL_OUTPUT:
870
      smcp.msg_lev = GLP_MSG_ON;
871
      break;
872
    case MESSAGE_FULL_OUTPUT:
873
      smcp.msg_lev = GLP_MSG_ALL;
874
      break;
875
    }
876
    smcp.meth = GLP_DUAL;
877

	
878
    if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
879
    if (glp_get_status(lp) != GLP_OPT) return SOLVED;
880

	
881
    glp_iocp iocp;
882
    glp_init_iocp(&iocp);
883

	
884
    switch (_message_level) {
885
    case MESSAGE_NO_OUTPUT:
886
      iocp.msg_lev = GLP_MSG_OFF;
887
      break;
888
    case MESSAGE_ERROR_MESSAGE:
889
      iocp.msg_lev = GLP_MSG_ERR;
890
      break;
891
    case MESSAGE_NORMAL_OUTPUT:
892
      iocp.msg_lev = GLP_MSG_ON;
893
      break;
894
    case MESSAGE_FULL_OUTPUT:
895
      iocp.msg_lev = GLP_MSG_ALL;
896
      break;
897
    }
898

	
899
    if (glp_intopt(lp, &iocp) != 0) return UNSOLVED;
900
    return SOLVED;
901
  }
902

	
903

	
904
  MipGlpk::ProblemType MipGlpk::_getType() const {
905
    switch (glp_get_status(lp)) {
906
    case GLP_OPT:
907
      switch (glp_mip_status(lp)) {
908
      case GLP_UNDEF:
909
        return UNDEFINED;
910
      case GLP_NOFEAS:
911
        return INFEASIBLE;
912
      case GLP_FEAS:
913
        return FEASIBLE;
914
      case GLP_OPT:
915
        return OPTIMAL;
916
      default:
917
        LEMON_ASSERT(false, "Wrong problem type.");
918
        return MipGlpk::ProblemType();
919
      }
920
    case GLP_NOFEAS:
921
      return INFEASIBLE;
922
    case GLP_INFEAS:
923
    case GLP_FEAS:
924
      if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
925
        return UNBOUNDED;
926
      } else {
927
        return UNDEFINED;
928
      }
929
    default:
930
      LEMON_ASSERT(false, "Wrong problem type.");
931
      return MipGlpk::ProblemType();
932
    }
933
  }
934

	
935
  MipGlpk::Value MipGlpk::_getSol(int i) const {
936
    return glp_mip_col_val(lp, i);
937
  }
938

	
939
  MipGlpk::Value MipGlpk::_getSolValue() const {
940
    return glp_mip_obj_val(lp);
941
  }
942

	
943
  MipGlpk* MipGlpk::_newSolver() const { return new MipGlpk; }
944
  MipGlpk* MipGlpk::_cloneSolver() const {return new MipGlpk(*this); }
945

	
946
  const char* MipGlpk::_solverName() const { return "MipGlpk"; }
947

	
948
  void MipGlpk::messageLevel(MessageLevel m) {
949
    _message_level = m;
950
  }
951

	
952
} //END OF NAMESPACE LEMON
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#ifndef LEMON_LP_GLPK_H
20
#define LEMON_LP_GLPK_H
21

	
22
///\file
23
///\brief Header of the LEMON-GLPK lp solver interface.
24
///\ingroup lp_group
25

	
26
#include <lemon/lp_base.h>
27

	
28
// forward declaration
29
#ifndef _GLP_PROB
30
#define _GLP_PROB
31
typedef struct { double _prob; } glp_prob;
32
/* LP/MIP problem object */
33
#endif
34

	
35
namespace lemon {
36

	
37

	
38
  /// \brief Base interface for the GLPK LP and MIP solver
39
  ///
40
  /// This class implements the common interface of the GLPK LP and MIP solver.
41
  /// \ingroup lp_group
42
  class GlpkBase : virtual public LpBase {
43
  protected:
44

	
45
    typedef glp_prob LPX;
46
    glp_prob* lp;
47

	
48
    GlpkBase();
49
    GlpkBase(const GlpkBase&);
50
    virtual ~GlpkBase();
51

	
52
  protected:
53

	
54
    virtual int _addCol();
55
    virtual int _addRow();
56

	
57
    virtual void _eraseCol(int i);
58
    virtual void _eraseRow(int i);
59

	
60
    virtual void _eraseColId(int i);
61
    virtual void _eraseRowId(int i);
62

	
63
    virtual void _getColName(int col, std::string& name) const;
64
    virtual void _setColName(int col, const std::string& name);
65
    virtual int _colByName(const std::string& name) const;
66

	
67
    virtual void _getRowName(int row, std::string& name) const;
68
    virtual void _setRowName(int row, const std::string& name);
69
    virtual int _rowByName(const std::string& name) const;
70

	
71
    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
72
    virtual void _getRowCoeffs(int i, InsertIterator b) const;
73

	
74
    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
75
    virtual void _getColCoeffs(int i, InsertIterator b) const;
76

	
77
    virtual void _setCoeff(int row, int col, Value value);
78
    virtual Value _getCoeff(int row, int col) const;
79

	
80
    virtual void _setColLowerBound(int i, Value value);
81
    virtual Value _getColLowerBound(int i) const;
82

	
83
    virtual void _setColUpperBound(int i, Value value);
84
    virtual Value _getColUpperBound(int i) const;
85

	
86
    virtual void _setRowLowerBound(int i, Value value);
87
    virtual Value _getRowLowerBound(int i) const;
88

	
89
    virtual void _setRowUpperBound(int i, Value value);
90
    virtual Value _getRowUpperBound(int i) const;
91

	
92
    virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
93
    virtual void _getObjCoeffs(InsertIterator b) const;
94

	
95
    virtual void _setObjCoeff(int i, Value obj_coef);
96
    virtual Value _getObjCoeff(int i) const;
97

	
98
    virtual void _setSense(Sense);
99
    virtual Sense _getSense() const;
100

	
101
    virtual void _clear();
102

	
103
  public:
104

	
105
    ///Pointer to the underlying GLPK data structure.
106
    LPX *lpx() {return lp;}
107
    ///Const pointer to the underlying GLPK data structure.
108
    const LPX *lpx() const {return lp;}
109

	
110
    ///Returns the constraint identifier understood by GLPK.
111
    int lpxRow(Row r) const { return rows(id(r)); }
112

	
113
    ///Returns the variable identifier understood by GLPK.
114
    int lpxCol(Col c) const { return cols(id(c)); }
115

	
116
  };
117

	
118
  /// \brief Interface for the GLPK LP solver
119
  ///
120
  /// This class implements an interface for the GLPK LP solver.
121
  ///\ingroup lp_group
122
  class LpGlpk : public GlpkBase, public LpSolver {
123
  public:
124

	
125
    ///\e
126
    LpGlpk();
127
    ///\e
128
    LpGlpk(const LpGlpk&);
129

	
130
  private:
131

	
132
    mutable std::vector<double> _primal_ray;
133
    mutable std::vector<double> _dual_ray;
134

	
135
    void _clear_temporals();
136

	
137
  protected:
138

	
139
    virtual LpGlpk* _cloneSolver() const;
140
    virtual LpGlpk* _newSolver() const;
141

	
142
    virtual const char* _solverName() const;
143

	
144
    virtual SolveExitStatus _solve();
145
    virtual Value _getPrimal(int i) const;
146
    virtual Value _getDual(int i) const;
147

	
148
    virtual Value _getPrimalValue() const;
149

	
150
    virtual VarStatus _getColStatus(int i) const;
151
    virtual VarStatus _getRowStatus(int i) const;
152

	
153
    virtual Value _getPrimalRay(int i) const;
154
    virtual Value _getDualRay(int i) const;
155

	
156
    ///\todo It should be clarified
157
    ///
158
    virtual ProblemType _getPrimalType() const;
159
    virtual ProblemType _getDualType() const;
160

	
161
  public:
162

	
163
    ///Solve with primal simplex
164
    SolveExitStatus solvePrimal();
165

	
166
    ///Solve with dual simplex
167
    SolveExitStatus solveDual();
168

	
169
    ///Turns on or off the presolver
170

	
171
    ///Turns on (\c b is \c true) or off (\c b is \c false) the presolver
172
    ///
173
    ///The presolver is off by default.
174
    void presolver(bool b);
175

	
176
    ///Enum for \c messageLevel() parameter
177
    enum MessageLevel {
178
      /// no output (default value)
179
      MESSAGE_NO_OUTPUT = 0,
180
      /// error messages only
181
      MESSAGE_ERROR_MESSAGE = 1,
182
      /// normal output
183
      MESSAGE_NORMAL_OUTPUT = 2,
184
      /// full output (includes informational messages)
185
      MESSAGE_FULL_OUTPUT = 3
186
    };
187

	
188
  private:
189

	
190
    MessageLevel _message_level;
191

	
192
  public:
193

	
194
    ///Set the verbosity of the messages
195

	
196
    ///Set the verbosity of the messages
197
    ///
198
    ///\param m is the level of the messages output by the solver routines.
199
    void messageLevel(MessageLevel m);
200
  };
201

	
202
  /// \brief Interface for the GLPK MIP solver
203
  ///
204
  /// This class implements an interface for the GLPK MIP solver.
205
  ///\ingroup lp_group
206
  class MipGlpk : public GlpkBase, public MipSolver {
207
  public:
208

	
209
    ///\e
210
    MipGlpk();
211
    ///\e
212
    MipGlpk(const MipGlpk&);
213

	
214
  protected:
215

	
216
    virtual MipGlpk* _cloneSolver() const;
217
    virtual MipGlpk* _newSolver() const;
218

	
219
    virtual const char* _solverName() const;
220

	
221
    virtual ColTypes _getColType(int col) const;
222
    virtual void _setColType(int col, ColTypes col_type);
223

	
224
    virtual SolveExitStatus _solve();
225
    virtual ProblemType _getType() const;
226
    virtual Value _getSol(int i) const;
227
    virtual Value _getSolValue() const;
228

	
229
    ///Enum for \c messageLevel() parameter
230
    enum MessageLevel {
231
      /// no output (default value)
232
      MESSAGE_NO_OUTPUT = 0,
233
      /// error messages only
234
      MESSAGE_ERROR_MESSAGE = 1,
235
      /// normal output
236
      MESSAGE_NORMAL_OUTPUT = 2,
237
      /// full output (includes informational messages)
238
      MESSAGE_FULL_OUTPUT = 3
239
    };
240

	
241
  private:
242

	
243
    MessageLevel _message_level;
244

	
245
  public:
246

	
247
    ///Set the verbosity of the messages
248

	
249
    ///Set the verbosity of the messages
250
    ///
251
    ///\param m is the level of the messages output by the solver routines.
252
    void messageLevel(MessageLevel m);
253
  };
254

	
255

	
256
} //END OF NAMESPACE LEMON
257

	
258
#endif //LEMON_LP_GLPK_H
259

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#include <iostream>
20
#include <lemon/lp_soplex.h>
21

	
22
#include <soplex/soplex.h>
23

	
24

	
25
///\file
26
///\brief Implementation of the LEMON-SOPLEX lp solver interface.
27
namespace lemon {
28

	
29
  LpSoplex::LpSoplex() {
30
    soplex = new soplex::SoPlex;
31
  }
32

	
33
  LpSoplex::~LpSoplex() {
34
    delete soplex;
35
  }
36

	
37
  LpSoplex::LpSoplex(const LpSoplex& lp) {
38
    rows = lp.rows;
39
    cols = lp.cols;
40

	
41
    soplex = new soplex::SoPlex;
42
    (*static_cast<soplex::SPxLP*>(soplex)) = *(lp.soplex);
43

	
44
    _col_names = lp._col_names;
45
    _col_names_ref = lp._col_names_ref;
46

	
47
    _row_names = lp._row_names;
48
    _row_names_ref = lp._row_names_ref;
49

	
50
  }
51

	
52
  void LpSoplex::_clear_temporals() {
53
    _primal_values.clear();
54
    _dual_values.clear();
55
  }
56

	
57
  LpSoplex* LpSoplex::_newSolver() const {
58
    LpSoplex* newlp = new LpSoplex();
59
    return newlp;
60
  }
61

	
62
  LpSoplex* LpSoplex::_cloneSolver() const {
63
    LpSoplex* newlp = new LpSoplex(*this);
64
    return newlp;
65
  }
66

	
67
  const char* LpSoplex::_solverName() const { return "LpSoplex"; }
68

	
69
  int LpSoplex::_addCol() {
70
    soplex::LPCol c;
71
    c.setLower(-soplex::infinity);
72
    c.setUpper(soplex::infinity);
73
    soplex->addCol(c);
74

	
75
    _col_names.push_back(std::string());
76

	
77
    return soplex->nCols() - 1;
78
  }
79

	
80
  int LpSoplex::_addRow() {
81
    soplex::LPRow r;
82
    r.setLhs(-soplex::infinity);
83
    r.setRhs(soplex::infinity);
84
    soplex->addRow(r);
85

	
86
    _row_names.push_back(std::string());
87

	
88
    return soplex->nRows() - 1;
89
  }
90

	
91

	
92
  void LpSoplex::_eraseCol(int i) {
93
    soplex->removeCol(i);
94
    _col_names_ref.erase(_col_names[i]);
95
    _col_names[i] = _col_names.back();
96
    _col_names_ref[_col_names.back()] = i;
97
    _col_names.pop_back();
98
  }
99

	
100
  void LpSoplex::_eraseRow(int i) {
101
    soplex->removeRow(i);
102
    _row_names_ref.erase(_row_names[i]);
103
    _row_names[i] = _row_names.back();
104
    _row_names_ref[_row_names.back()] = i;
105
    _row_names.pop_back();
106
  }
107

	
108
  void LpSoplex::_eraseColId(int i) {
109
    cols.eraseIndex(i);
110
    cols.relocateIndex(i, cols.maxIndex());
111
  }
112
  void LpSoplex::_eraseRowId(int i) {
113
    rows.eraseIndex(i);
114
    rows.relocateIndex(i, rows.maxIndex());
115
  }
116

	
117
  void LpSoplex::_getColName(int c, std::string &name) const {
118
    name = _col_names[c];
119
  }
120

	
121
  void LpSoplex::_setColName(int c, const std::string &name) {
122
    _col_names_ref.erase(_col_names[c]);
123
    _col_names[c] = name;
124
    if (!name.empty()) {
125
      _col_names_ref.insert(std::make_pair(name, c));
126
    }
127
  }
128

	
129
  int LpSoplex::_colByName(const std::string& name) const {
130
    std::map<std::string, int>::const_iterator it =
131
      _col_names_ref.find(name);
132
    if (it != _col_names_ref.end()) {
133
      return it->second;
134
    } else {
135
      return -1;
136
    }
137
  }
138

	
139
  void LpSoplex::_getRowName(int r, std::string &name) const {
140
    name = _row_names[r];
141
  }
142

	
143
  void LpSoplex::_setRowName(int r, const std::string &name) {
144
    _row_names_ref.erase(_row_names[r]);
145
    _row_names[r] = name;
146
    if (!name.empty()) {
147
      _row_names_ref.insert(std::make_pair(name, r));
148
    }
149
  }
150

	
151
  int LpSoplex::_rowByName(const std::string& name) const {
152
    std::map<std::string, int>::const_iterator it =
153
      _row_names_ref.find(name);
154
    if (it != _row_names_ref.end()) {
155
      return it->second;
156
    } else {
157
      return -1;
158
    }
159
  }
160

	
161

	
162
  void LpSoplex::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
163
    for (int j = 0; j < soplex->nCols(); ++j) {
164
      soplex->changeElement(i, j, 0.0);
165
    }
166
    for(ExprIterator it = b; it != e; ++it) {
167
      soplex->changeElement(i, it->first, it->second);
168
    }
169
  }
170

	
171
  void LpSoplex::_getRowCoeffs(int i, InsertIterator b) const {
172
    const soplex::SVector& vec = soplex->rowVector(i);
173
    for (int k = 0; k < vec.size(); ++k) {
174
      *b = std::make_pair(vec.index(k), vec.value(k));
175
      ++b;
176
    }
177
  }
178

	
179
  void LpSoplex::_setColCoeffs(int j, ExprIterator b, ExprIterator e) {
180
    for (int i = 0; i < soplex->nRows(); ++i) {
181
      soplex->changeElement(i, j, 0.0);
182
    }
183
    for(ExprIterator it = b; it != e; ++it) {
184
      soplex->changeElement(it->first, j, it->second);
185
    }
186
  }
187

	
188
  void LpSoplex::_getColCoeffs(int i, InsertIterator b) const {
189
    const soplex::SVector& vec = soplex->colVector(i);
190
    for (int k = 0; k < vec.size(); ++k) {
191
      *b = std::make_pair(vec.index(k), vec.value(k));
192
      ++b;
193
    }
194
  }
195

	
196
  void LpSoplex::_setCoeff(int i, int j, Value value) {
197
    soplex->changeElement(i, j, value);
198
  }
199

	
200
  LpSoplex::Value LpSoplex::_getCoeff(int i, int j) const {
201
    return soplex->rowVector(i)[j];
202
  }
203

	
204
  void LpSoplex::_setColLowerBound(int i, Value value) {
205
    LEMON_ASSERT(value != INF, "Invalid bound");
206
    soplex->changeLower(i, value != -INF ? value : -soplex::infinity);
207
  }
208

	
209
  LpSoplex::Value LpSoplex::_getColLowerBound(int i) const {
210
    double value = soplex->lower(i);
211
    return value != -soplex::infinity ? value : -INF;
212
  }
213

	
214
  void LpSoplex::_setColUpperBound(int i, Value value) {
215
    LEMON_ASSERT(value != -INF, "Invalid bound");
216
    soplex->changeUpper(i, value != INF ? value : soplex::infinity);
217
  }
218

	
219
  LpSoplex::Value LpSoplex::_getColUpperBound(int i) const {
220
    double value = soplex->upper(i);
221
    return value != soplex::infinity ? value : INF;
222
  }
223

	
224
  void LpSoplex::_setRowLowerBound(int i, Value lb) {
225
    LEMON_ASSERT(lb != INF, "Invalid bound");
226
    soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, soplex->rhs(i));
227
  }
228

	
229
  LpSoplex::Value LpSoplex::_getRowLowerBound(int i) const {
230
    double res = soplex->lhs(i);
231
    return res == -soplex::infinity ? -INF : res;
232
  }
233

	
234
  void LpSoplex::_setRowUpperBound(int i, Value ub) {
235
    LEMON_ASSERT(ub != -INF, "Invalid bound");
236
    soplex->changeRange(i, soplex->lhs(i), ub != INF ? ub : soplex::infinity);
237
  }
238

	
239
  LpSoplex::Value LpSoplex::_getRowUpperBound(int i) const {
240
    double res = soplex->rhs(i);
241
    return res == soplex::infinity ? INF : res;
242
  }
243

	
244
  void LpSoplex::_setObjCoeffs(ExprIterator b, ExprIterator e) {
245
    for (int j = 0; j < soplex->nCols(); ++j) {
246
      soplex->changeObj(j, 0.0);
247
    }
248
    for (ExprIterator it = b; it != e; ++it) {
249
      soplex->changeObj(it->first, it->second);
250
    }
251
  }
252

	
253
  void LpSoplex::_getObjCoeffs(InsertIterator b) const {
254
    for (int j = 0; j < soplex->nCols(); ++j) {
255
      Value coef = soplex->obj(j);
256
      if (coef != 0.0) {
257
        *b = std::make_pair(j, coef);
258
        ++b;
259
      }
260
    }
261
  }
262

	
263
  void LpSoplex::_setObjCoeff(int i, Value obj_coef) {
264
    soplex->changeObj(i, obj_coef);
265
  }
266

	
267
  LpSoplex::Value LpSoplex::_getObjCoeff(int i) const {
268
    return soplex->obj(i);
269
  }
270

	
271
  LpSoplex::SolveExitStatus LpSoplex::_solve() {
272

	
273
    _clear_temporals();
274

	
275
    soplex::SPxSolver::Status status = soplex->solve();
276

	
277
    switch (status) {
278
    case soplex::SPxSolver::OPTIMAL:
279
    case soplex::SPxSolver::INFEASIBLE:
280
    case soplex::SPxSolver::UNBOUNDED:
281
      return SOLVED;
282
    default:
283
      return UNSOLVED;
284
    }
285
  }
286

	
287
  LpSoplex::Value LpSoplex::_getPrimal(int i) const {
288
    if (_primal_values.empty()) {
289
      _primal_values.resize(soplex->nCols());
290
      soplex::Vector pv(_primal_values.size(), &_primal_values.front());
291
      soplex->getPrimal(pv);
292
    }
293
    return _primal_values[i];
294
  }
295

	
296
  LpSoplex::Value LpSoplex::_getDual(int i) const {
297
    if (_dual_values.empty()) {
298
      _dual_values.resize(soplex->nRows());
299
      soplex::Vector dv(_dual_values.size(), &_dual_values.front());
300
      soplex->getDual(dv);
301
    }
302
    return _dual_values[i];
303
  }
304

	
305
  LpSoplex::Value LpSoplex::_getPrimalValue() const {
306
    return soplex->objValue();
307
  }
308

	
309
  LpSoplex::VarStatus LpSoplex::_getColStatus(int i) const {
310
    switch (soplex->getBasisColStatus(i)) {
311
    case soplex::SPxSolver::BASIC:
312
      return BASIC;
313
    case soplex::SPxSolver::ON_UPPER:
314
      return UPPER;
315
    case soplex::SPxSolver::ON_LOWER:
316
      return LOWER;
317
    case soplex::SPxSolver::FIXED:
318
      return FIXED;
319
    case soplex::SPxSolver::ZERO:
320
      return FREE;
321
    default:
322
      LEMON_ASSERT(false, "Wrong column status");
323
      return VarStatus();
324
    }
325
  }
326

	
327
  LpSoplex::VarStatus LpSoplex::_getRowStatus(int i) const {
328
    switch (soplex->getBasisRowStatus(i)) {
329
    case soplex::SPxSolver::BASIC:
330
      return BASIC;
331
    case soplex::SPxSolver::ON_UPPER:
332
      return UPPER;
333
    case soplex::SPxSolver::ON_LOWER:
334
      return LOWER;
335
    case soplex::SPxSolver::FIXED:
336
      return FIXED;
337
    case soplex::SPxSolver::ZERO:
338
      return FREE;
339
    default:
340
      LEMON_ASSERT(false, "Wrong row status");
341
      return VarStatus();
342
    }
343
  }
344

	
345
  LpSoplex::Value LpSoplex::_getPrimalRay(int i) const {
346
    if (_primal_ray.empty()) {
347
      _primal_ray.resize(soplex->nCols());
348
      soplex::Vector pv(_primal_ray.size(), &_primal_ray.front());
349
      soplex->getDualfarkas(pv);
350
    }
351
    return _primal_ray[i];
352
  }
353

	
354
  LpSoplex::Value LpSoplex::_getDualRay(int i) const {
355
    if (_dual_ray.empty()) {
356
      _dual_ray.resize(soplex->nRows());
357
      soplex::Vector dv(_dual_ray.size(), &_dual_ray.front());
358
      soplex->getDualfarkas(dv);
359
    }
360
    return _dual_ray[i];
361
  }
362

	
363
  LpSoplex::ProblemType LpSoplex::_getPrimalType() const {
364
    switch (soplex->status()) {
365
    case soplex::SPxSolver::OPTIMAL:
366
      return OPTIMAL;
367
    case soplex::SPxSolver::UNBOUNDED:
368
      return UNBOUNDED;
369
    case soplex::SPxSolver::INFEASIBLE:
370
      return INFEASIBLE;
371
    default:
372
      return UNDEFINED;
373
    }
374
  }
375

	
376
  LpSoplex::ProblemType LpSoplex::_getDualType() const {
377
    switch (soplex->status()) {
378
    case soplex::SPxSolver::OPTIMAL:
379
      return OPTIMAL;
380
    case soplex::SPxSolver::UNBOUNDED:
381
      return UNBOUNDED;
382
    case soplex::SPxSolver::INFEASIBLE:
383
      return INFEASIBLE;
384
    default:
385
      return UNDEFINED;
386
    }
387
  }
388

	
389
  void LpSoplex::_setSense(Sense sense) {
390
    switch (sense) {
391
    case MIN:
392
      soplex->changeSense(soplex::SPxSolver::MINIMIZE);
393
      break;
394
    case MAX:
395
      soplex->changeSense(soplex::SPxSolver::MAXIMIZE);
396
    }
397
  }
398

	
399
  LpSoplex::Sense LpSoplex::_getSense() const {
400
    switch (soplex->spxSense()) {
401
    case soplex::SPxSolver::MAXIMIZE:
402
      return MAX;
403
    case soplex::SPxSolver::MINIMIZE:
404
      return MIN;
405
    default:
406
      LEMON_ASSERT(false, "Wrong sense.");
407
      return LpSoplex::Sense();
408
    }
409
  }
410

	
411
  void LpSoplex::_clear() {
412
    soplex->clear();
413
    _col_names.clear();
414
    _col_names_ref.clear();
415
    _row_names.clear();
416
    _row_names_ref.clear();
417
    cols.clear();
418
    rows.clear();
419
    _clear_temporals();
420
  }
421

	
422
} //namespace lemon
423

	
Ignore white space 4 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2008
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#ifndef LEMON_LP_SOPLEX_H
20
#define LEMON_LP_SOPLEX_H
21

	
22
///\file
23
///\brief Header of the LEMON-SOPLEX lp solver interface.
24

	
25
#include <vector>
26
#include <string>
27

	
28
#include <lemon/lp_base.h>
29

	
30
// Forward declaration
31
namespace soplex {
32
  class SoPlex;
33
}
34

	
35
namespace lemon {
36

	
37
  /// \ingroup lp_group
38
  ///
39
  /// \brief Interface for the SOPLEX solver
40
  ///
41
  /// This class implements an interface for the SoPlex LP solver.
42
  /// The SoPlex library is an object oriented lp solver library
43
  /// developed at the Konrad-Zuse-Zentrum f�r Informationstechnik
44
  /// Berlin (ZIB). You can find detailed information about it at the
45
  /// <tt>http://soplex.zib.de</tt> address.
46
  class LpSoplex : public LpSolver {
47
  private:
48

	
49
    soplex::SoPlex* soplex;
50

	
51
    std::vector<std::string> _col_names;
52
    std::map<std::string, int> _col_names_ref;
53

	
54
    std::vector<std::string> _row_names;
55
    std::map<std::string, int> _row_names_ref;
56

	
57
  private:
58

	
59
    // these values cannot be retrieved element by element
60
    mutable std::vector<Value> _primal_values;
61
    mutable std::vector<Value> _dual_values;
62

	
63
    mutable std::vector<Value> _primal_ray;
64
    mutable std::vector<Value> _dual_ray;
65

	
66
    void _clear_temporals();
67

	
68
  public:
69

	
70
    /// \e
71
    LpSoplex();
72
    /// \e
73
    LpSoplex(const LpSoplex&);
74
    /// \e
75
    ~LpSoplex();
76

	
77
  protected:
78

	
79
    virtual LpSoplex* _newSolver() const;
80
    virtual LpSoplex* _cloneSolver() const;
81

	
82
    virtual const char* _solverName() const;
83

	
84
    virtual int _addCol();
85
    virtual int _addRow();
86

	
87
    virtual void _eraseCol(int i);
88
    virtual void _eraseRow(int i);
89

	
90
    virtual void _eraseColId(int i);
91
    virtual void _eraseRowId(int i);
92

	
93
    virtual void _getColName(int col, std::string& name) const;
94
    virtual void _setColName(int col, const std::string& name);
95
    virtual int _colByName(const std::string& name) const;
96

	
97
    virtual void _getRowName(int row, std::string& name) const;
98
    virtual void _setRowName(int row, const std::string& name);
99
    virtual int _rowByName(const std::string& name) const;
100

	
101
    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
102
    virtual void _getRowCoeffs(int i, InsertIterator b) const;
103

	
104
    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
105
    virtual void _getColCoeffs(int i, InsertIterator b) const;
106

	
107
    virtual void _setCoeff(int row, int col, Value value);
108
    virtual Value _getCoeff(int row, int col) const;
109

	
110
    virtual void _setColLowerBound(int i, Value value);
111
    virtual Value _getColLowerBound(int i) const;
112
    virtual void _setColUpperBound(int i, Value value);
113
    virtual Value _getColUpperBound(int i) const;
114

	
115
    virtual void _setRowLowerBound(int i, Value value);
116
    virtual Value _getRowLowerBound(int i) const;
117
    virtual void _setRowUpperBound(int i, Value value);
118
    virtual Value _getRowUpperBound(int i) const;
119

	
120
    virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
121
    virtual void _getObjCoeffs(InsertIterator b) const;
122

	
123
    virtual void _setObjCoeff(int i, Value obj_coef);
124
    virtual Value _getObjCoeff(int i) const;
125

	
126
    virtual void _setSense(Sense sense);
127
    virtual Sense _getSense() const;
128

	
129
    virtual SolveExitStatus _solve();
130
    virtual Value _getPrimal(int i) const;
131
    virtual Value _getDual(int i) const;
132

	
133
    virtual Value _getPrimalValue() const;
134

	
135
    virtual Value _getPrimalRay(int i) const;
136
    virtual Value _getDualRay(int i) const;
137

	
138
    virtual VarStatus _getColStatus(int i) const;
139
    virtual VarStatus _getRowStatus(int i) const;
140

	
141
    virtual ProblemType _getPrimalType() const;
142
    virtual ProblemType _getDualType() const;
143

	
144
    virtual void _clear();
145

	
146
  };
147

	
148
} //END OF NAMESPACE LEMON
149

	
150
#endif //LEMON_LP_SOPLEX_H
151

	
0 comments (0 inline)