gravatar
deba@inf.elte.hu
deba@inf.elte.hu
Unified message handling for LP and MIP solvers (#9)
0 13 0
default
13 files changed with 183 insertions and 188 deletions:
↑ Collapse diff ↑
Show white space 128 line context
1 1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5 5
 * Copyright (C) 2003-2009
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
10 10
 * provided that this copyright notice appears in all copies. For
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
///\file
20 20
///\brief Implementation of the CBC MIP solver interface.
21 21

	
22 22
#include "cbc.h"
23 23

	
24 24
#include <coin/CoinModel.hpp>
25 25
#include <coin/CbcModel.hpp>
26 26
#include <coin/OsiSolverInterface.hpp>
27 27

	
28 28
#ifdef COIN_HAS_CLP
29 29
#include "coin/OsiClpSolverInterface.hpp"
30 30
#endif
31 31
#ifdef COIN_HAS_OSL
32 32
#include "coin/OsiOslSolverInterface.hpp"
33 33
#endif
34 34

	
35 35
#include "coin/CbcCutGenerator.hpp"
36 36
#include "coin/CbcHeuristicLocal.hpp"
37 37
#include "coin/CbcHeuristicGreedy.hpp"
38 38
#include "coin/CbcHeuristicFPump.hpp"
39 39
#include "coin/CbcHeuristicRINS.hpp"
40 40

	
41 41
#include "coin/CglGomory.hpp"
42 42
#include "coin/CglProbing.hpp"
43 43
#include "coin/CglKnapsackCover.hpp"
44 44
#include "coin/CglOddHole.hpp"
45 45
#include "coin/CglClique.hpp"
46 46
#include "coin/CglFlowCover.hpp"
47 47
#include "coin/CglMixedIntegerRounding.hpp"
48 48

	
49 49
#include "coin/CbcHeuristic.hpp"
50 50

	
51 51
namespace lemon {
52 52

	
53 53
  CbcMip::CbcMip() {
54 54
    _prob = new CoinModel();
55 55
    _prob->setProblemName("LEMON");
56 56
    _osi_solver = 0;
57 57
    _cbc_model = 0;
58
    messageLevel(MESSAGE_NOTHING);
58 59
  }
59 60

	
60 61
  CbcMip::CbcMip(const CbcMip& other) {
61 62
    _prob = new CoinModel(*other._prob);
63
    _prob->setProblemName("LEMON");
62 64
    _osi_solver = 0;
63 65
    _cbc_model = 0;
66
    messageLevel(MESSAGE_NOTHING);
64 67
  }
65 68

	
66 69
  CbcMip::~CbcMip() {
67 70
    delete _prob;
68 71
    if (_osi_solver) delete _osi_solver;
69 72
    if (_cbc_model) delete _cbc_model;
70 73
  }
71 74

	
72 75
  const char* CbcMip::_solverName() const { return "CbcMip"; }
73 76

	
74 77
  int CbcMip::_addCol() {
75 78
    _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0, 0, false);
76 79
    return _prob->numberColumns() - 1;
77 80
  }
78 81

	
79 82
  CbcMip* CbcMip::newSolver() const {
80 83
    CbcMip* newlp = new CbcMip;
81 84
    return newlp;
82 85
  }
83 86

	
84 87
  CbcMip* CbcMip::cloneSolver() const {
85 88
    CbcMip* copylp = new CbcMip(*this);
86 89
    return copylp;
87 90
  }
88 91

	
89 92
  int CbcMip::_addRow() {
90 93
    _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX);
91 94
    return _prob->numberRows() - 1;
92 95
  }
93 96

	
94 97

	
95 98
  void CbcMip::_eraseCol(int i) {
96 99
    _prob->deleteColumn(i);
97 100
  }
98 101

	
99 102
  void CbcMip::_eraseRow(int i) {
100 103
    _prob->deleteRow(i);
101 104
  }
102 105

	
103 106
  void CbcMip::_eraseColId(int i) {
104 107
    cols.eraseIndex(i);
105 108
  }
106 109

	
107 110
  void CbcMip::_eraseRowId(int i) {
108 111
    rows.eraseIndex(i);
109 112
  }
110 113

	
111 114
  void CbcMip::_getColName(int c, std::string& name) const {
112 115
    name = _prob->getColumnName(c);
113 116
  }
114 117

	
115 118
  void CbcMip::_setColName(int c, const std::string& name) {
116 119
    _prob->setColumnName(c, name.c_str());
117 120
  }
118 121

	
119 122
  int CbcMip::_colByName(const std::string& name) const {
120 123
    return _prob->column(name.c_str());
121 124
  }
122 125

	
123 126
  void CbcMip::_getRowName(int r, std::string& name) const {
124 127
    name = _prob->getRowName(r);
125 128
  }
126 129

	
127 130
  void CbcMip::_setRowName(int r, const std::string& name) {
... ...
@@ -209,146 +212,130 @@
209 212
  CbcMip::Value CbcMip::_getRowLowerBound(int i) const {
210 213
    double val = _prob->getRowLower(i);
211 214
    return val == - COIN_DBL_MAX ? - INF : val;
212 215
  }
213 216

	
214 217
  void CbcMip::_setRowUpperBound(int i, Value up) {
215 218
    LEMON_ASSERT(up != -INF, "Invalid bound");
216 219
    _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up);
217 220
  }
218 221

	
219 222
  CbcMip::Value CbcMip::_getRowUpperBound(int i) const {
220 223
    double val = _prob->getRowUpper(i);
221 224
    return val == COIN_DBL_MAX ? INF : val;
222 225
  }
223 226

	
224 227
  void CbcMip::_setObjCoeffs(ExprIterator b, ExprIterator e) {
225 228
    int num = _prob->numberColumns();
226 229
    for (int i = 0; i < num; ++i) {
227 230
      _prob->setColumnObjective(i, 0.0);
228 231
    }
229 232
    for (ExprIterator it = b; it != e; ++it) {
230 233
      _prob->setColumnObjective(it->first, it->second);
231 234
    }
232 235
  }
233 236

	
234 237
  void CbcMip::_getObjCoeffs(InsertIterator b) const {
235 238
    int num = _prob->numberColumns();
236 239
    for (int i = 0; i < num; ++i) {
237 240
      Value coef = _prob->getColumnObjective(i);
238 241
      if (coef != 0.0) {
239 242
        *b = std::make_pair(i, coef);
240 243
        ++b;
241 244
      }
242 245
    }
243 246
  }
244 247

	
245 248
  void CbcMip::_setObjCoeff(int i, Value obj_coef) {
246 249
    _prob->setColumnObjective(i, obj_coef);
247 250
  }
248 251

	
249 252
  CbcMip::Value CbcMip::_getObjCoeff(int i) const {
250 253
    return _prob->getColumnObjective(i);
251 254
  }
252 255

	
253 256
  CbcMip::SolveExitStatus CbcMip::_solve() {
254 257

	
255 258
    if (_osi_solver) {
256 259
      delete _osi_solver;
257 260
    }
258 261
#ifdef COIN_HAS_CLP
259 262
    _osi_solver = new OsiClpSolverInterface();
260 263
#elif COIN_HAS_OSL
261 264
    _osi_solver = new OsiOslSolverInterface();
262 265
#else
263 266
#error Cannot instantiate Osi solver
264 267
#endif
265 268

	
266 269
    _osi_solver->loadFromCoinModel(*_prob);
267 270

	
268 271
    if (_cbc_model) {
269 272
      delete _cbc_model;
270 273
    }
271 274
    _cbc_model= new CbcModel(*_osi_solver);
272 275

	
273
    switch (_message_level) {
274
    case MESSAGE_NO_OUTPUT:
275
      _osi_solver->messageHandler()->setLogLevel(0);
276
      _cbc_model->setLogLevel(0);
277
      break;
278
    case MESSAGE_ERROR_MESSAGE:
279
      _osi_solver->messageHandler()->setLogLevel(1);
280
      _cbc_model->setLogLevel(1);
281
      break;
282
    case MESSAGE_NORMAL_OUTPUT:
283
      _osi_solver->messageHandler()->setLogLevel(2);
284
      _cbc_model->setLogLevel(2);
285
      break;
286
    case MESSAGE_FULL_OUTPUT:
287
      _osi_solver->messageHandler()->setLogLevel(3);
288
      _cbc_model->setLogLevel(3);
289
      break;
290
    }
276
    _osi_solver->messageHandler()->setLogLevel(_message_level);
277
    _cbc_model->setLogLevel(_message_level);
291 278

	
292 279
    _cbc_model->initialSolve();
293 280
    _cbc_model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
294 281

	
295 282
    if (!_cbc_model->isInitialSolveAbandoned() &&
296 283
        _cbc_model->isInitialSolveProvenOptimal() &&
297 284
        !_cbc_model->isInitialSolveProvenPrimalInfeasible() &&
298 285
        !_cbc_model->isInitialSolveProvenDualInfeasible()) {
299 286

	
300 287
      CglProbing generator1;
301 288
      generator1.setUsingObjective(true);
302 289
      generator1.setMaxPass(3);
303 290
      generator1.setMaxProbe(100);
304 291
      generator1.setMaxLook(50);
305 292
      generator1.setRowCuts(3);
306 293
      _cbc_model->addCutGenerator(&generator1, -1, "Probing");
307 294

	
308 295
      CglGomory generator2;
309 296
      generator2.setLimit(300);
310 297
      _cbc_model->addCutGenerator(&generator2, -1, "Gomory");
311 298

	
312 299
      CglKnapsackCover generator3;
313 300
      _cbc_model->addCutGenerator(&generator3, -1, "Knapsack");
314 301

	
315 302
      CglOddHole generator4;
316 303
      generator4.setMinimumViolation(0.005);
317 304
      generator4.setMinimumViolationPer(0.00002);
318 305
      generator4.setMaximumEntries(200);
319 306
      _cbc_model->addCutGenerator(&generator4, -1, "OddHole");
320 307

	
321 308
      CglClique generator5;
322 309
      generator5.setStarCliqueReport(false);
323 310
      generator5.setRowCliqueReport(false);
324 311
      _cbc_model->addCutGenerator(&generator5, -1, "Clique");
325 312

	
326 313
      CglMixedIntegerRounding mixedGen;
327 314
      _cbc_model->addCutGenerator(&mixedGen, -1, "MixedIntegerRounding");
328 315

	
329 316
      CglFlowCover flowGen;
330 317
      _cbc_model->addCutGenerator(&flowGen, -1, "FlowCover");
331 318

	
332 319
#ifdef COIN_HAS_CLP
333 320
      OsiClpSolverInterface* osiclp =
334 321
        dynamic_cast<OsiClpSolverInterface*>(_cbc_model->solver());
335 322
      if (osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500) {
336 323
        osiclp->setupForRepeatedUse(2, 0);
337 324
      }
338 325
#endif
339 326

	
340 327
      CbcRounding heuristic1(*_cbc_model);
341 328
      heuristic1.setWhen(3);
342 329
      _cbc_model->addHeuristic(&heuristic1);
343 330

	
344 331
      CbcHeuristicLocal heuristic2(*_cbc_model);
345 332
      heuristic2.setWhen(3);
346 333
      _cbc_model->addHeuristic(&heuristic2);
347 334

	
348 335
      CbcHeuristicGreedyCover heuristic3(*_cbc_model);
349 336
      heuristic3.setAlgorithm(11);
350 337
      heuristic3.setWhen(3);
351 338
      _cbc_model->addHeuristic(&heuristic3);
352 339

	
353 340
      CbcHeuristicFPump heuristic4(*_cbc_model);
354 341
      heuristic4.setWhen(3);
... ...
@@ -392,69 +379,85 @@
392 379
  CbcMip::ProblemType CbcMip::_getType() const {
393 380
    if (_cbc_model->isProvenOptimal()) {
394 381
      return OPTIMAL;
395 382
    } else if (_cbc_model->isContinuousUnbounded()) {
396 383
      return UNBOUNDED;
397 384
    }
398 385
    return FEASIBLE;
399 386
  }
400 387

	
401 388
  void CbcMip::_setSense(Sense sense) {
402 389
    switch (sense) {
403 390
    case MIN:
404 391
      _prob->setOptimizationDirection(1.0);
405 392
      break;
406 393
    case MAX:
407 394
      _prob->setOptimizationDirection(- 1.0);
408 395
      break;
409 396
    }
410 397
  }
411 398

	
412 399
  CbcMip::Sense CbcMip::_getSense() const {
413 400
    if (_prob->optimizationDirection() > 0.0) {
414 401
      return MIN;
415 402
    } else if (_prob->optimizationDirection() < 0.0) {
416 403
      return MAX;
417 404
    } else {
418 405
      LEMON_ASSERT(false, "Wrong sense");
419 406
      return CbcMip::Sense();
420 407
    }
421 408
  }
422 409

	
423 410
  void CbcMip::_setColType(int i, CbcMip::ColTypes col_type) {
424 411
    switch (col_type){
425 412
    case INTEGER:
426 413
      _prob->setInteger(i);
427 414
      break;
428 415
    case REAL:
429 416
      _prob->setContinuous(i);
430 417
      break;
431 418
    default:;
432 419
      LEMON_ASSERT(false, "Wrong sense");
433 420
    }
434 421
  }
435 422

	
436 423
  CbcMip::ColTypes CbcMip::_getColType(int i) const {
437 424
    return _prob->getColumnIsInteger(i) ? INTEGER : REAL;
438 425
  }
439 426

	
440 427
  void CbcMip::_clear() {
441 428
    delete _prob;
442 429
    if (_osi_solver) {
443 430
      delete _osi_solver;
444 431
      _osi_solver = 0;
445 432
    }
446 433
    if (_cbc_model) {
447 434
      delete _cbc_model;
448 435
      _cbc_model = 0;
449 436
    }
450 437

	
451 438
    _prob = new CoinModel();
452 439
    rows.clear();
453 440
    cols.clear();
454 441
  }
455 442

	
456
  void CbcMip::messageLevel(MessageLevel m) {
457
    _message_level = m;
443
  void CbcMip::_messageLevel(MessageLevel level) {
444
    switch (level) {
445
    case MESSAGE_NOTHING:
446
      _message_level = 0;
447
      break;
448
    case MESSAGE_ERROR:
449
      _message_level = 1;
450
      break;
451
    case MESSAGE_WARNING:
452
      _message_level = 1;
453
      break;
454
    case MESSAGE_NORMAL:
455
      _message_level = 2;
456
      break;
457
    case MESSAGE_VERBOSE:
458
      _message_level = 3;
459
      break;
460
    }
458 461
  }
459 462

	
460 463
} //END OF NAMESPACE LEMON
Show white space 128 line context
... ...
@@ -54,97 +54,76 @@
54 54
    /// \e
55 55
    virtual CbcMip* newSolver() const;
56 56
    /// \e
57 57
    virtual CbcMip* cloneSolver() const;
58 58

	
59 59
  protected:
60 60

	
61 61
    virtual const char* _solverName() const;
62 62

	
63 63
    virtual int _addCol();
64 64
    virtual int _addRow();
65 65

	
66 66
    virtual void _eraseCol(int i);
67 67
    virtual void _eraseRow(int i);
68 68

	
69 69
    virtual void _eraseColId(int i);
70 70
    virtual void _eraseRowId(int i);
71 71

	
72 72
    virtual void _getColName(int col, std::string& name) const;
73 73
    virtual void _setColName(int col, const std::string& name);
74 74
    virtual int _colByName(const std::string& name) const;
75 75

	
76 76
    virtual void _getRowName(int row, std::string& name) const;
77 77
    virtual void _setRowName(int row, const std::string& name);
78 78
    virtual int _rowByName(const std::string& name) const;
79 79

	
80 80
    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
81 81
    virtual void _getRowCoeffs(int i, InsertIterator b) const;
82 82

	
83 83
    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
84 84
    virtual void _getColCoeffs(int i, InsertIterator b) const;
85 85

	
86 86
    virtual void _setCoeff(int row, int col, Value value);
87 87
    virtual Value _getCoeff(int row, int col) const;
88 88

	
89 89
    virtual void _setColLowerBound(int i, Value value);
90 90
    virtual Value _getColLowerBound(int i) const;
91 91
    virtual void _setColUpperBound(int i, Value value);
92 92
    virtual Value _getColUpperBound(int i) const;
93 93

	
94 94
    virtual void _setRowLowerBound(int i, Value value);
95 95
    virtual Value _getRowLowerBound(int i) const;
96 96
    virtual void _setRowUpperBound(int i, Value value);
97 97
    virtual Value _getRowUpperBound(int i) const;
98 98

	
99 99
    virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
100 100
    virtual void _getObjCoeffs(InsertIterator b) const;
101 101

	
102 102
    virtual void _setObjCoeff(int i, Value obj_coef);
103 103
    virtual Value _getObjCoeff(int i) const;
104 104

	
105 105
    virtual void _setSense(Sense sense);
106 106
    virtual Sense _getSense() const;
107 107

	
108 108
    virtual ColTypes _getColType(int col) const;
109 109
    virtual void _setColType(int col, ColTypes col_type);
110 110

	
111 111
    virtual SolveExitStatus _solve();
112 112
    virtual ProblemType _getType() const;
113 113
    virtual Value _getSol(int i) const;
114 114
    virtual Value _getSolValue() const;
115 115

	
116 116
    virtual void _clear();
117 117

	
118
  public:
118
    virtual void _messageLevel(MessageLevel level);
119
    void _applyMessageLevel();
119 120

	
120
    ///Enum for \c messageLevel() parameter
121
    enum MessageLevel {
122
      /// no output (default value)
123
      MESSAGE_NO_OUTPUT = 0,
124
      /// error messages only
125
      MESSAGE_ERROR_MESSAGE = 1,
126
      /// normal output
127
      MESSAGE_NORMAL_OUTPUT = 2,
128
      /// full output (includes informational messages)
129
      MESSAGE_FULL_OUTPUT = 3
130
    };
121
    int _message_level;
131 122

	
132
  private:
133

	
134
    MessageLevel _message_level;
135

	
136
  public:
137

	
138
    ///Set the verbosity of the messages
139

	
140
    ///Set the verbosity of the messages
141
    ///
142
    ///\param m is the level of the messages output by the solver routines.
143
    void messageLevel(MessageLevel m);
144 123

	
145 124

	
146 125
  };
147 126

	
148 127
}
149 128

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

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

	
22 22
namespace lemon {
23 23

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

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

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

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

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

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

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

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

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

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

	
81 81

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

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

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

	
97 97
  void ClpLp::_eraseRowId(int i) {
98 98
    rows.eraseIndex(i);
99 99
    rows.shiftIndices(i);
... ...
@@ -369,69 +369,85 @@
369 369
    case ClpSimplex::isFixed:
370 370
      return FIXED;
371 371
    case ClpSimplex::superBasic:
372 372
      return FREE;
373 373
    default:
374 374
      LEMON_ASSERT(false, "Wrong row status");
375 375
      return VarStatus();
376 376
    }
377 377
  }
378 378

	
379 379

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

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

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

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

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

	
433
  void ClpLp::messageLevel(MessageLevel m) {
434
    _prob->setLogLevel(static_cast<int>(m));
433
  void ClpLp::_messageLevel(MessageLevel level) {
434
    switch (level) {
435
    case MESSAGE_NOTHING:
436
      _prob->setLogLevel(0);
437
      break;
438
    case MESSAGE_ERROR:
439
      _prob->setLogLevel(1);
440
      break;
441
    case MESSAGE_WARNING:
442
      _prob->setLogLevel(2);
443
      break;
444
    case MESSAGE_NORMAL:
445
      _prob->setLogLevel(3);
446
      break;
447
    case MESSAGE_VERBOSE:
448
      _prob->setLogLevel(4);
449
      break;
450
    }
435 451
  }
436 452

	
437 453
} //END OF NAMESPACE LEMON
Show white space 128 line context
... ...
@@ -75,107 +75,89 @@
75 75

	
76 76
    virtual int _addCol();
77 77
    virtual int _addRow();
78 78

	
79 79
    virtual void _eraseCol(int i);
80 80
    virtual void _eraseRow(int i);
81 81

	
82 82
    virtual void _eraseColId(int i);
83 83
    virtual void _eraseRowId(int i);
84 84

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

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

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

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

	
99 99
    virtual void _setCoeff(int row, int col, Value value);
100 100
    virtual Value _getCoeff(int row, int col) const;
101 101

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

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

	
112 112
    virtual void _setObjCoeffs(ExprIterator, ExprIterator);
113 113
    virtual void _getObjCoeffs(InsertIterator) const;
114 114

	
115 115
    virtual void _setObjCoeff(int i, Value obj_coef);
116 116
    virtual Value _getObjCoeff(int i) const;
117 117

	
118 118
    virtual void _setSense(Sense sense);
119 119
    virtual Sense _getSense() const;
120 120

	
121 121
    virtual SolveExitStatus _solve();
122 122

	
123 123
    virtual Value _getPrimal(int i) const;
124 124
    virtual Value _getDual(int i) const;
125 125

	
126 126
    virtual Value _getPrimalValue() const;
127 127

	
128 128
    virtual Value _getPrimalRay(int i) const;
129 129
    virtual Value _getDualRay(int i) const;
130 130

	
131 131
    virtual VarStatus _getColStatus(int i) const;
132 132
    virtual VarStatus _getRowStatus(int i) const;
133 133

	
134 134
    virtual ProblemType _getPrimalType() const;
135 135
    virtual ProblemType _getDualType() const;
136 136

	
137 137
    virtual void _clear();
138 138

	
139
    virtual void _messageLevel(MessageLevel);
140
    
139 141
  public:
140 142

	
141 143
    ///Solves LP with primal simplex method.
142 144
    SolveExitStatus solvePrimal();
143 145

	
144 146
    ///Solves LP with dual simplex method.
145 147
    SolveExitStatus solveDual();
146 148

	
147 149
    ///Solves LP with barrier method.
148 150
    SolveExitStatus solveBarrier();
149 151

	
150 152
    ///Returns the constraint identifier understood by CLP.
151 153
    int clpRow(Row r) const { return rows(id(r)); }
152 154

	
153 155
    ///Returns the variable identifier understood by CLP.
154 156
    int clpCol(Col c) const { return cols(id(c)); }
155 157

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

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

	
176 158
  };
177 159

	
178 160
} //END OF NAMESPACE LEMON
179 161

	
180 162
#endif //LEMON_CLP_H
181 163

	
Show white space 128 line context
... ...
@@ -11,142 +11,145 @@
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

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

	
23 23
#include <lemon/cplex.h>
24 24

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

	
29 29

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

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

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

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

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

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

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

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

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

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

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

	
102 105

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

	
111 114

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

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

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

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

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

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

	
152 155
  int CplexBase::_colByName(const std::string& name) const {
... ...
@@ -377,549 +380,572 @@
377 380
      values.push_back(it->second);
378 381
    }
379 382
    CPXchgobj(cplexEnv(), _prob, values.size(),
380 383
              &indices.front(), &values.front());
381 384

	
382 385
  }
383 386

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

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

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

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

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

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

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

	
444
  void CplexBase::_messageLevel(MessageLevel level) {
445
    switch (level) {
446
    case MESSAGE_NOTHING:
447
      _message_enabled = false;
448
      break;
449
    case MESSAGE_ERROR:
450
    case MESSAGE_WARNING:
451
    case MESSAGE_NORMAL:
452
    case MESSAGE_VERBOSE:
453
      _message_enabled = true;
454
      break;
455
    }
456
  }
457

	
458
  void CplexBase::_applyMessageLevel() {
459
    CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND, 
460
                   _message_enabled ? CPX_ON : CPX_OFF);
461
  }
462

	
441 463
  // CplexLp members
442 464

	
443 465
  CplexLp::CplexLp()
444 466
    : LpBase(), LpSolver(), CplexBase() {}
445 467

	
446 468
  CplexLp::CplexLp(const CplexEnv& env)
447 469
    : LpBase(), LpSolver(), CplexBase(env) {}
448 470

	
449 471
  CplexLp::CplexLp(const CplexLp& other)
450 472
    : LpBase(), LpSolver(), CplexBase(other) {}
451 473

	
452 474
  CplexLp::~CplexLp() {}
453 475

	
454 476
  CplexLp* CplexLp::newSolver() const { return new CplexLp; }
455 477
  CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); }
456 478

	
457 479
  const char* CplexLp::_solverName() const { return "CplexLp"; }
458 480

	
459 481
  void CplexLp::_clear_temporals() {
460 482
    _col_status.clear();
461 483
    _row_status.clear();
462 484
    _primal_ray.clear();
463 485
    _dual_ray.clear();
464 486
  }
465 487

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

	
508 530
  CplexLp::SolveExitStatus CplexLp::_solve() {
509 531
    _clear_temporals();
532
    _applyMessageLevel();
510 533
    return convertStatus(CPXlpopt(cplexEnv(), _prob));
511 534
  }
512 535

	
513 536
  CplexLp::SolveExitStatus CplexLp::solvePrimal() {
514 537
    _clear_temporals();
538
    _applyMessageLevel();
515 539
    return convertStatus(CPXprimopt(cplexEnv(), _prob));
516 540
  }
517 541

	
518 542
  CplexLp::SolveExitStatus CplexLp::solveDual() {
519 543
    _clear_temporals();
544
    _applyMessageLevel();
520 545
    return convertStatus(CPXdualopt(cplexEnv(), _prob));
521 546
  }
522 547

	
523 548
  CplexLp::SolveExitStatus CplexLp::solveBarrier() {
524 549
    _clear_temporals();
550
    _applyMessageLevel();
525 551
    return convertStatus(CPXbaropt(cplexEnv(), _prob));
526 552
  }
527 553

	
528 554
  CplexLp::Value CplexLp::_getPrimal(int i) const {
529 555
    Value x;
530 556
    CPXgetx(cplexEnv(), _prob, &x, i, i);
531 557
    return x;
532 558
  }
533 559

	
534 560
  CplexLp::Value CplexLp::_getDual(int i) const {
535 561
    Value y;
536 562
    CPXgetpi(cplexEnv(), _prob, &y, i, i);
537 563
    return y;
538 564
  }
539 565

	
540 566
  CplexLp::Value CplexLp::_getPrimalValue() const {
541 567
    Value objval;
542 568
    CPXgetobjval(cplexEnv(), _prob, &objval);
543 569
    return objval;
544 570
  }
545 571

	
546 572
  CplexLp::VarStatus CplexLp::_getColStatus(int i) const {
547 573
    if (_col_status.empty()) {
548 574
      _col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
549 575
      CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
550 576
    }
551 577
    switch (_col_status[i]) {
552 578
    case CPX_BASIC:
553 579
      return BASIC;
554 580
    case CPX_FREE_SUPER:
555 581
      return FREE;
556 582
    case CPX_AT_LOWER:
557 583
      return LOWER;
558 584
    case CPX_AT_UPPER:
559 585
      return UPPER;
560 586
    default:
561 587
      LEMON_ASSERT(false, "Wrong column status");
562 588
      return CplexLp::VarStatus();
563 589
    }
564 590
  }
565 591

	
566 592
  CplexLp::VarStatus CplexLp::_getRowStatus(int i) const {
567 593
    if (_row_status.empty()) {
568 594
      _row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
569 595
      CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
570 596
    }
571 597
    switch (_row_status[i]) {
572 598
    case CPX_BASIC:
573 599
      return BASIC;
574 600
    case CPX_AT_LOWER:
575 601
      {
576 602
        char s;
577 603
        CPXgetsense(cplexEnv(), _prob, &s, i, i);
578 604
        return s != 'L' ? LOWER : UPPER;
579 605
      }
580 606
    case CPX_AT_UPPER:
581 607
      return UPPER;
582 608
    default:
583 609
      LEMON_ASSERT(false, "Wrong row status");
584 610
      return CplexLp::VarStatus();
585 611
    }
586 612
  }
587 613

	
588 614
  CplexLp::Value CplexLp::_getPrimalRay(int i) const {
589 615
    if (_primal_ray.empty()) {
590 616
      _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
591 617
      CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
592 618
    }
593 619
    return _primal_ray[i];
594 620
  }
595 621

	
596 622
  CplexLp::Value CplexLp::_getDualRay(int i) const {
597 623
    if (_dual_ray.empty()) {
598 624

	
599 625
    }
600 626
    return _dual_ray[i];
601 627
  }
602 628

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

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

	
656 682
  //Some more interesting stuff:
657 683

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

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

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

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

	
754
  //9.0-as cplex verzio statusai
779
  // Cplex 9.0 status values
755 780
  // CPX_STAT_ABORT_DUAL_OBJ_LIM
756 781
  // CPX_STAT_ABORT_IT_LIM
757 782
  // CPX_STAT_ABORT_OBJ_LIM
758 783
  // CPX_STAT_ABORT_PRIM_OBJ_LIM
759 784
  // CPX_STAT_ABORT_TIME_LIM
760 785
  // CPX_STAT_ABORT_USER
761 786
  // CPX_STAT_FEASIBLE_RELAXED
762 787
  // CPX_STAT_INFEASIBLE
763 788
  // CPX_STAT_INForUNBD
764 789
  // CPX_STAT_NUM_BEST
765 790
  // CPX_STAT_OPTIMAL
766 791
  // CPX_STAT_OPTIMAL_FACE_UNBOUNDED
767 792
  // CPX_STAT_OPTIMAL_INFEAS
768 793
  // CPX_STAT_OPTIMAL_RELAXED
769 794
  // CPX_STAT_UNBOUNDED
770 795

	
771 796
  CplexLp::ProblemType CplexLp::_getDualType() const {
772 797
    int stat = CPXgetstat(cplexEnv(), _prob);
773 798
#if CPX_VERSION >= 800
774 799
    switch (stat) {
775 800
    case CPX_STAT_OPTIMAL:
776 801
      return OPTIMAL;
777 802
    case CPX_STAT_UNBOUNDED:
778 803
      return INFEASIBLE;
779 804
    default:
780 805
      return UNDEFINED;
781 806
    }
782 807
#else
783 808
    statusSwitch(cplexEnv(),stat);
784 809
    switch (stat) {
785 810
    case 0:
786 811
      return UNDEFINED; //Undefined
787 812
    case CPX_OPTIMAL://Optimal
788 813
      return OPTIMAL;
789 814
    case CPX_UNBOUNDED:
790 815
      return INFEASIBLE;
791 816
    default:
792 817
      return UNDEFINED; //Everything else comes here
793 818
      //FIXME error
794 819
    }
795 820
#endif
796 821
  }
797 822

	
798 823
  // CplexMip members
799 824

	
800 825
  CplexMip::CplexMip()
801 826
    : LpBase(), MipSolver(), CplexBase() {
802 827

	
803 828
#if CPX_VERSION < 800
804 829
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
805 830
#else
806 831
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
807 832
#endif
808 833
  }
809 834

	
810 835
  CplexMip::CplexMip(const CplexEnv& env)
811 836
    : LpBase(), MipSolver(), CplexBase(env) {
812 837

	
813 838
#if CPX_VERSION < 800
814 839
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
815 840
#else
816 841
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
817 842
#endif
818 843

	
819 844
  }
820 845

	
821 846
  CplexMip::CplexMip(const CplexMip& other)
822 847
    : LpBase(), MipSolver(), CplexBase(other) {}
823 848

	
824 849
  CplexMip::~CplexMip() {}
825 850

	
826 851
  CplexMip* CplexMip::newSolver() const { return new CplexMip; }
827 852
  CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); }
828 853

	
829 854
  const char* CplexMip::_solverName() const { return "CplexMip"; }
830 855

	
831 856
  void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) {
832 857

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

	
836 861
    switch (col_type){
837 862
    case INTEGER: {
838 863
      const char t = 'I';
839 864
      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
840 865
    } break;
841 866
    case REAL: {
842 867
      const char t = 'C';
843 868
      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
844 869
    } break;
845 870
    default:
846 871
      break;
847 872
    }
848 873
  }
849 874

	
850 875
  CplexMip::ColTypes CplexMip::_getColType(int i) const {
851 876
    char t;
852 877
    CPXgetctype (cplexEnv(), _prob, &t, i, i);
853 878
    switch (t) {
854 879
    case 'I':
855 880
      return INTEGER;
856 881
    case 'C':
857 882
      return REAL;
858 883
    default:
859 884
      LEMON_ASSERT(false, "Invalid column type");
860 885
      return ColTypes();
861 886
    }
862 887

	
863 888
  }
864 889

	
865 890
  CplexMip::SolveExitStatus CplexMip::_solve() {
866 891
    int status;
892
    _applyMessageLevel();
867 893
    status = CPXmipopt (cplexEnv(), _prob);
868 894
    if (status==0)
869 895
      return SOLVED;
870 896
    else
871 897
      return UNSOLVED;
872 898

	
873 899
  }
874 900

	
875 901

	
876 902
  CplexMip::ProblemType CplexMip::_getType() const {
877 903

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

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

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

	
912 938
  CplexMip::Value CplexMip::_getSol(int i) const {
913 939
    Value x;
914 940
    CPXgetmipx(cplexEnv(), _prob, &x, i, i);
915 941
    return x;
916 942
  }
917 943

	
918 944
  CplexMip::Value CplexMip::_getSolValue() const {
919 945
    Value objval;
920 946
    CPXgetmipobjval(cplexEnv(), _prob, &objval);
921 947
    return objval;
922 948
  }
923 949

	
924 950
} //namespace lemon
925 951

	
Show white space 128 line context
... ...
@@ -83,136 +83,151 @@
83 83
  class CplexBase : virtual public LpBase {
84 84
  protected:
85 85

	
86 86
    CplexEnv _env;
87 87
    cpxlp* _prob;
88 88

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	
145 145
    virtual void _clear();
146 146

	
147
    virtual void _messageLevel(MessageLevel level);
148
    void _applyMessageLevel();
149

	
150
    bool _message_enabled;
151

	
147 152
  public:
148 153

	
149 154
    /// Returns the used \c CplexEnv instance
150 155
    const CplexEnv& env() const { return _env; }
156

	
157
    /// \brief Returns the const cpxenv pointer
151 158
    ///
159
    /// \note The cpxenv might be destructed with the solver.
152 160
    const cpxenv* cplexEnv() const { return _env.cplexEnv(); }
153 161

	
162
    /// \brief Returns the const cpxenv pointer
163
    ///
164
    /// \note The cpxenv might be destructed with the solver.
165
    cpxenv* cplexEnv() { return _env.cplexEnv(); }
166

	
167
    /// Returns the cplex problem object
154 168
    cpxlp* cplexLp() { return _prob; }
169
    /// Returns the cplex problem object
155 170
    const cpxlp* cplexLp() const { return _prob; }
156 171

	
157 172
  };
158 173

	
159 174
  /// \brief Interface for the CPLEX LP solver
160 175
  ///
161 176
  /// This class implements an interface for the CPLEX LP solver.
162 177
  ///\ingroup lp_group
163 178
  class CplexLp : public LpSolver, public CplexBase {
164 179
  public:
165 180
    /// \e
166 181
    CplexLp();
167 182
    /// \e
168 183
    CplexLp(const CplexEnv&);
169 184
    /// \e
170 185
    CplexLp(const CplexLp&);
171 186
    /// \e
172 187
    virtual ~CplexLp();
173 188

	
174 189
    /// \e
175 190
    virtual CplexLp* cloneSolver() const;
176 191
    /// \e
177 192
    virtual CplexLp* newSolver() const;
178 193

	
179 194
  private:
180 195

	
181 196
    // these values cannot retrieved element by element
182 197
    mutable std::vector<int> _col_status;
183 198
    mutable std::vector<int> _row_status;
184 199

	
185 200
    mutable std::vector<Value> _primal_ray;
186 201
    mutable std::vector<Value> _dual_ray;
187 202

	
188 203
    void _clear_temporals();
189 204

	
190 205
    SolveExitStatus convertStatus(int status);
191 206

	
192 207
  protected:
193 208

	
194 209
    virtual const char* _solverName() const;
195 210

	
196 211
    virtual SolveExitStatus _solve();
197 212
    virtual Value _getPrimal(int i) const;
198 213
    virtual Value _getDual(int i) const;
199 214
    virtual Value _getPrimalValue() const;
200 215

	
201 216
    virtual VarStatus _getColStatus(int i) const;
202 217
    virtual VarStatus _getRowStatus(int i) const;
203 218

	
204 219
    virtual Value _getPrimalRay(int i) const;
205 220
    virtual Value _getDualRay(int i) const;
206 221

	
207 222
    virtual ProblemType _getPrimalType() const;
208 223
    virtual ProblemType _getDualType() const;
209 224

	
210 225
  public:
211 226

	
212 227
    /// Solve with primal simplex method
213 228
    SolveExitStatus solvePrimal();
214 229

	
215 230
    /// Solve with dual simplex method
216 231
    SolveExitStatus solveDual();
217 232

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

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

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

	
25 25
#include <lemon/assert.h>
26 26

	
27 27
namespace lemon {
28 28

	
29 29
  // GlpkBase members
30 30

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

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

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

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

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

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

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

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

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

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

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

	
91 93
  }
92 94

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

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

	
104 106
  void GlpkBase::_setRowName(int r, const std::string & name) {
105 107
    glp_set_row_name(lp, r, const_cast<char*>(name.c_str()));
... ...
@@ -465,220 +467,212 @@
465 467
  }
466 468

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

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

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

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

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

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

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

	
525 527
  void GlpkBase::freeEnv() {
526 528
    glp_free_env();
527 529
  }
528 530

	
531
  void GlpkBase::_messageLevel(MessageLevel level) {
532
    switch (level) {
533
    case MESSAGE_NOTHING:
534
      _message_level = GLP_MSG_OFF;
535
      break;
536
    case MESSAGE_ERROR:
537
      _message_level = GLP_MSG_ERR;
538
      break;
539
    case MESSAGE_WARNING:
540
      _message_level = GLP_MSG_ERR;
541
      break;
542
    case MESSAGE_NORMAL:
543
      _message_level = GLP_MSG_ON;
544
      break;
545
    case MESSAGE_VERBOSE:
546
      _message_level = GLP_MSG_ALL;
547
      break;
548
    }
549
  }
550

	
529 551
  GlpkBase::FreeEnvHelper GlpkBase::freeEnvHelper;
530 552

	
531 553
  // GlpkLp members
532 554

	
533 555
  GlpkLp::GlpkLp()
534 556
    : LpBase(), LpSolver(), GlpkBase() {
535
    messageLevel(MESSAGE_NO_OUTPUT);
536 557
    presolver(false);
537 558
  }
538 559

	
539 560
  GlpkLp::GlpkLp(const GlpkLp& other)
540 561
    : LpBase(other), LpSolver(other), GlpkBase(other) {
541
    messageLevel(MESSAGE_NO_OUTPUT);
542 562
    presolver(false);
543 563
  }
544 564

	
545 565
  GlpkLp* GlpkLp::newSolver() const { return new GlpkLp; }
546 566
  GlpkLp* GlpkLp::cloneSolver() const { return new GlpkLp(*this); }
547 567

	
548 568
  const char* GlpkLp::_solverName() const { return "GlpkLp"; }
549 569

	
550 570
  void GlpkLp::_clear_temporals() {
551 571
    _primal_ray.clear();
552 572
    _dual_ray.clear();
553 573
  }
554 574

	
555 575
  GlpkLp::SolveExitStatus GlpkLp::_solve() {
556 576
    return solvePrimal();
557 577
  }
558 578

	
559 579
  GlpkLp::SolveExitStatus GlpkLp::solvePrimal() {
560 580
    _clear_temporals();
561 581

	
562 582
    glp_smcp smcp;
563 583
    glp_init_smcp(&smcp);
564 584

	
565
    switch (_message_level) {
566
    case MESSAGE_NO_OUTPUT:
567
      smcp.msg_lev = GLP_MSG_OFF;
568
      break;
569
    case MESSAGE_ERROR_MESSAGE:
570
      smcp.msg_lev = GLP_MSG_ERR;
571
      break;
572
    case MESSAGE_NORMAL_OUTPUT:
573
      smcp.msg_lev = GLP_MSG_ON;
574
      break;
575
    case MESSAGE_FULL_OUTPUT:
576
      smcp.msg_lev = GLP_MSG_ALL;
577
      break;
578
    }
585
    smcp.msg_lev = _message_level;
579 586
    smcp.presolve = _presolve;
580 587

	
581 588
    // If the basis is not valid we get an error return value.
582 589
    // In this case we can try to create a new basis.
583 590
    switch (glp_simplex(lp, &smcp)) {
584 591
    case 0:
585 592
      break;
586 593
    case GLP_EBADB:
587 594
    case GLP_ESING:
588 595
    case GLP_ECOND:
589 596
      glp_term_out(false);
590 597
      glp_adv_basis(lp, 0);
591 598
      glp_term_out(true);
592 599
      if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
593 600
      break;
594 601
    default:
595 602
      return UNSOLVED;
596 603
    }
597 604

	
598 605
    return SOLVED;
599 606
  }
600 607

	
601 608
  GlpkLp::SolveExitStatus GlpkLp::solveDual() {
602 609
    _clear_temporals();
603 610

	
604 611
    glp_smcp smcp;
605 612
    glp_init_smcp(&smcp);
606 613

	
607
    switch (_message_level) {
608
    case MESSAGE_NO_OUTPUT:
609
      smcp.msg_lev = GLP_MSG_OFF;
610
      break;
611
    case MESSAGE_ERROR_MESSAGE:
612
      smcp.msg_lev = GLP_MSG_ERR;
613
      break;
614
    case MESSAGE_NORMAL_OUTPUT:
615
      smcp.msg_lev = GLP_MSG_ON;
616
      break;
617
    case MESSAGE_FULL_OUTPUT:
618
      smcp.msg_lev = GLP_MSG_ALL;
619
      break;
620
    }
614
    smcp.msg_lev = _message_level;
621 615
    smcp.meth = GLP_DUAL;
622 616
    smcp.presolve = _presolve;
623 617

	
624 618
    // If the basis is not valid we get an error return value.
625 619
    // In this case we can try to create a new basis.
626 620
    switch (glp_simplex(lp, &smcp)) {
627 621
    case 0:
628 622
      break;
629 623
    case GLP_EBADB:
630 624
    case GLP_ESING:
631 625
    case GLP_ECOND:
632 626
      glp_term_out(false);
633 627
      glp_adv_basis(lp, 0);
634 628
      glp_term_out(true);
635 629
      if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
636 630
      break;
637 631
    default:
638 632
      return UNSOLVED;
639 633
    }
640 634
    return SOLVED;
641 635
  }
642 636

	
643 637
  GlpkLp::Value GlpkLp::_getPrimal(int i) const {
644 638
    return glp_get_col_prim(lp, i);
645 639
  }
646 640

	
647 641
  GlpkLp::Value GlpkLp::_getDual(int i) const {
648 642
    return glp_get_row_dual(lp, i);
649 643
  }
650 644

	
651 645
  GlpkLp::Value GlpkLp::_getPrimalValue() const {
652 646
    return glp_get_obj_val(lp);
653 647
  }
654 648

	
655 649
  GlpkLp::VarStatus GlpkLp::_getColStatus(int i) const {
656 650
    switch (glp_get_col_stat(lp, i)) {
657 651
    case GLP_BS:
658 652
      return BASIC;
659 653
    case GLP_UP:
660 654
      return UPPER;
661 655
    case GLP_LO:
662 656
      return LOWER;
663 657
    case GLP_NF:
664 658
      return FREE;
665 659
    case GLP_NS:
666 660
      return FIXED;
667 661
    default:
668 662
      LEMON_ASSERT(false, "Wrong column status");
669 663
      return GlpkLp::VarStatus();
670 664
    }
671 665
  }
672 666

	
673 667
  GlpkLp::VarStatus GlpkLp::_getRowStatus(int i) const {
674 668
    switch (glp_get_row_stat(lp, i)) {
675 669
    case GLP_BS:
676 670
      return BASIC;
677 671
    case GLP_UP:
678 672
      return UPPER;
679 673
    case GLP_LO:
680 674
      return LOWER;
681 675
    case GLP_NF:
682 676
      return FREE;
683 677
    case GLP_NS:
684 678
      return FIXED;
... ...
@@ -797,213 +791,177 @@
797 791
              _dual_ray[i] = 1;
798 792
            } else {
799 793
              _dual_ray[i] = 0;
800 794
            }
801 795
            _dual_ray[i] /= glp_get_sjj(lp, index - row_num);
802 796
          }
803 797
        }
804 798

	
805 799
        glp_btran(lp, &_dual_ray.front());
806 800

	
807 801
        for (int i = 1; i <= row_num; ++i) {
808 802
          _dual_ray[i] /= glp_get_rii(lp, i);
809 803
        }
810 804
      }
811 805
    }
812 806
    return _dual_ray[i];
813 807
  }
814 808

	
815 809
  GlpkLp::ProblemType GlpkLp::_getPrimalType() const {
816 810
    if (glp_get_status(lp) == GLP_OPT)
817 811
      return OPTIMAL;
818 812
    switch (glp_get_prim_stat(lp)) {
819 813
    case GLP_UNDEF:
820 814
      return UNDEFINED;
821 815
    case GLP_FEAS:
822 816
    case GLP_INFEAS:
823 817
      if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
824 818
        return UNBOUNDED;
825 819
      } else {
826 820
        return UNDEFINED;
827 821
      }
828 822
    case GLP_NOFEAS:
829 823
      return INFEASIBLE;
830 824
    default:
831 825
      LEMON_ASSERT(false, "Wrong primal type");
832 826
      return  GlpkLp::ProblemType();
833 827
    }
834 828
  }
835 829

	
836 830
  GlpkLp::ProblemType GlpkLp::_getDualType() const {
837 831
    if (glp_get_status(lp) == GLP_OPT)
838 832
      return OPTIMAL;
839 833
    switch (glp_get_dual_stat(lp)) {
840 834
    case GLP_UNDEF:
841 835
      return UNDEFINED;
842 836
    case GLP_FEAS:
843 837
    case GLP_INFEAS:
844 838
      if (glp_get_prim_stat(lp) == GLP_NOFEAS) {
845 839
        return UNBOUNDED;
846 840
      } else {
847 841
        return UNDEFINED;
848 842
      }
849 843
    case GLP_NOFEAS:
850 844
      return INFEASIBLE;
851 845
    default:
852 846
      LEMON_ASSERT(false, "Wrong primal type");
853 847
      return  GlpkLp::ProblemType();
854 848
    }
855 849
  }
856 850

	
857 851
  void GlpkLp::presolver(bool presolve) {
858 852
    _presolve = presolve;
859 853
  }
860 854

	
861
  void GlpkLp::messageLevel(MessageLevel m) {
862
    _message_level = m;
863
  }
864

	
865 855
  // GlpkMip members
866 856

	
867 857
  GlpkMip::GlpkMip()
868 858
    : LpBase(), MipSolver(), GlpkBase() {
869
    messageLevel(MESSAGE_NO_OUTPUT);
870 859
  }
871 860

	
872 861
  GlpkMip::GlpkMip(const GlpkMip& other)
873 862
    : LpBase(), MipSolver(), GlpkBase(other) {
874
    messageLevel(MESSAGE_NO_OUTPUT);
875 863
  }
876 864

	
877 865
  void GlpkMip::_setColType(int i, GlpkMip::ColTypes col_type) {
878 866
    switch (col_type) {
879 867
    case INTEGER:
880 868
      glp_set_col_kind(lp, i, GLP_IV);
881 869
      break;
882 870
    case REAL:
883 871
      glp_set_col_kind(lp, i, GLP_CV);
884 872
      break;
885 873
    }
886 874
  }
887 875

	
888 876
  GlpkMip::ColTypes GlpkMip::_getColType(int i) const {
889 877
    switch (glp_get_col_kind(lp, i)) {
890 878
    case GLP_IV:
891 879
    case GLP_BV:
892 880
      return INTEGER;
893 881
    default:
894 882
      return REAL;
895 883
    }
896 884

	
897 885
  }
898 886

	
899 887
  GlpkMip::SolveExitStatus GlpkMip::_solve() {
900 888
    glp_smcp smcp;
901 889
    glp_init_smcp(&smcp);
902 890

	
903
    switch (_message_level) {
904
    case MESSAGE_NO_OUTPUT:
905
      smcp.msg_lev = GLP_MSG_OFF;
906
      break;
907
    case MESSAGE_ERROR_MESSAGE:
908
      smcp.msg_lev = GLP_MSG_ERR;
909
      break;
910
    case MESSAGE_NORMAL_OUTPUT:
911
      smcp.msg_lev = GLP_MSG_ON;
912
      break;
913
    case MESSAGE_FULL_OUTPUT:
914
      smcp.msg_lev = GLP_MSG_ALL;
915
      break;
916
    }
891
    smcp.msg_lev = _message_level;
917 892
    smcp.meth = GLP_DUAL;
918 893

	
919 894
    // If the basis is not valid we get an error return value.
920 895
    // In this case we can try to create a new basis.
921 896
    switch (glp_simplex(lp, &smcp)) {
922 897
    case 0:
923 898
      break;
924 899
    case GLP_EBADB:
925 900
    case GLP_ESING:
926 901
    case GLP_ECOND:
927 902
      glp_term_out(false);
928 903
      glp_adv_basis(lp, 0);
929 904
      glp_term_out(true);
930 905
      if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
931 906
      break;
932 907
    default:
933 908
      return UNSOLVED;
934 909
    }
935 910

	
936 911
    if (glp_get_status(lp) != GLP_OPT) return SOLVED;
937 912

	
938 913
    glp_iocp iocp;
939 914
    glp_init_iocp(&iocp);
940 915

	
941
    switch (_message_level) {
942
    case MESSAGE_NO_OUTPUT:
943
      iocp.msg_lev = GLP_MSG_OFF;
944
      break;
945
    case MESSAGE_ERROR_MESSAGE:
946
      iocp.msg_lev = GLP_MSG_ERR;
947
      break;
948
    case MESSAGE_NORMAL_OUTPUT:
949
      iocp.msg_lev = GLP_MSG_ON;
950
      break;
951
    case MESSAGE_FULL_OUTPUT:
952
      iocp.msg_lev = GLP_MSG_ALL;
953
      break;
954
    }
916
    iocp.msg_lev = _message_level;
955 917

	
956 918
    if (glp_intopt(lp, &iocp) != 0) return UNSOLVED;
957 919
    return SOLVED;
958 920
  }
959 921

	
960 922

	
961 923
  GlpkMip::ProblemType GlpkMip::_getType() const {
962 924
    switch (glp_get_status(lp)) {
963 925
    case GLP_OPT:
964 926
      switch (glp_mip_status(lp)) {
965 927
      case GLP_UNDEF:
966 928
        return UNDEFINED;
967 929
      case GLP_NOFEAS:
968 930
        return INFEASIBLE;
969 931
      case GLP_FEAS:
970 932
        return FEASIBLE;
971 933
      case GLP_OPT:
972 934
        return OPTIMAL;
973 935
      default:
974 936
        LEMON_ASSERT(false, "Wrong problem type.");
975 937
        return GlpkMip::ProblemType();
976 938
      }
977 939
    case GLP_NOFEAS:
978 940
      return INFEASIBLE;
979 941
    case GLP_INFEAS:
980 942
    case GLP_FEAS:
981 943
      if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
982 944
        return UNBOUNDED;
983 945
      } else {
984 946
        return UNDEFINED;
985 947
      }
986 948
    default:
987 949
      LEMON_ASSERT(false, "Wrong problem type.");
988 950
      return GlpkMip::ProblemType();
989 951
    }
990 952
  }
991 953

	
992 954
  GlpkMip::Value GlpkMip::_getSol(int i) const {
993 955
    return glp_mip_col_val(lp, i);
994 956
  }
995 957

	
996 958
  GlpkMip::Value GlpkMip::_getSolValue() const {
997 959
    return glp_mip_obj_val(lp);
998 960
  }
999 961

	
1000 962
  GlpkMip* GlpkMip::newSolver() const { return new GlpkMip; }
1001 963
  GlpkMip* GlpkMip::cloneSolver() const {return new GlpkMip(*this); }
1002 964

	
1003 965
  const char* GlpkMip::_solverName() const { return "GlpkMip"; }
1004 966

	
1005
  void GlpkMip::messageLevel(MessageLevel m) {
1006
    _message_level = m;
1007
  }
1008

	
1009 967
} //END OF NAMESPACE LEMON
Show white space 128 line context
... ...
@@ -39,239 +39,197 @@
39 39
  ///
40 40
  /// This class implements the common interface of the GLPK LP and MIP solver.
41 41
  /// \ingroup lp_group
42 42
  class GlpkBase : virtual public LpBase {
43 43
  protected:
44 44

	
45 45
    typedef glp_prob LPX;
46 46
    glp_prob* lp;
47 47

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

	
52 52
  protected:
53 53

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	
101 101
    virtual void _clear();
102 102

	
103
    virtual void _messageLevel(MessageLevel level);
104

	
103 105
  private:
104 106

	
105 107
    static void freeEnv();
106 108

	
107 109
    struct FreeEnvHelper {
108 110
      ~FreeEnvHelper() {
109 111
        freeEnv();
110 112
      }
111 113
    };
112 114
    
113 115
    static FreeEnvHelper freeEnvHelper;
114 116
    
117
  protected:
118
    
119
    int _message_level;
120
    
115 121
  public:
116 122

	
117 123
    ///Pointer to the underlying GLPK data structure.
118 124
    LPX *lpx() {return lp;}
119 125
    ///Const pointer to the underlying GLPK data structure.
120 126
    const LPX *lpx() const {return lp;}
121 127

	
122 128
    ///Returns the constraint identifier understood by GLPK.
123 129
    int lpxRow(Row r) const { return rows(id(r)); }
124 130

	
125 131
    ///Returns the variable identifier understood by GLPK.
126 132
    int lpxCol(Col c) const { return cols(id(c)); }
127 133

	
128 134
  };
129 135

	
130 136
  /// \brief Interface for the GLPK LP solver
131 137
  ///
132 138
  /// This class implements an interface for the GLPK LP solver.
133 139
  ///\ingroup lp_group
134 140
  class GlpkLp : public LpSolver, public GlpkBase {
135 141
  public:
136 142

	
137 143
    ///\e
138 144
    GlpkLp();
139 145
    ///\e
140 146
    GlpkLp(const GlpkLp&);
141 147

	
142 148
    ///\e
143 149
    virtual GlpkLp* cloneSolver() const;
144 150
    ///\e
145 151
    virtual GlpkLp* newSolver() const;
146 152

	
147 153
  private:
148 154

	
149 155
    mutable std::vector<double> _primal_ray;
150 156
    mutable std::vector<double> _dual_ray;
151 157

	
152 158
    void _clear_temporals();
153 159

	
154 160
  protected:
155 161

	
156 162
    virtual const char* _solverName() const;
157 163

	
158 164
    virtual SolveExitStatus _solve();
159 165
    virtual Value _getPrimal(int i) const;
160 166
    virtual Value _getDual(int i) const;
161 167

	
162 168
    virtual Value _getPrimalValue() const;
163 169

	
164 170
    virtual VarStatus _getColStatus(int i) const;
165 171
    virtual VarStatus _getRowStatus(int i) const;
166 172

	
167 173
    virtual Value _getPrimalRay(int i) const;
168 174
    virtual Value _getDualRay(int i) const;
169 175

	
170 176
    virtual ProblemType _getPrimalType() const;
171 177
    virtual ProblemType _getDualType() const;
172 178

	
173 179
  public:
174 180

	
175 181
    ///Solve with primal simplex
176 182
    SolveExitStatus solvePrimal();
177 183

	
178 184
    ///Solve with dual simplex
179 185
    SolveExitStatus solveDual();
180 186

	
181 187
  private:
182 188

	
183 189
    bool _presolve;
184 190

	
185 191
  public:
186 192

	
187 193
    ///Turns on or off the presolver
188 194

	
189 195
    ///Turns on (\c b is \c true) or off (\c b is \c false) the presolver
190 196
    ///
191 197
    ///The presolver is off by default.
192 198
    void presolver(bool presolve);
193 199

	
194
    ///Enum for \c messageLevel() parameter
195
    enum MessageLevel {
196
      /// no output (default value)
197
      MESSAGE_NO_OUTPUT = 0,
198
      /// error messages only
199
      MESSAGE_ERROR_MESSAGE = 1,
200
      /// normal output
201
      MESSAGE_NORMAL_OUTPUT = 2,
202
      /// full output (includes informational messages)
203
      MESSAGE_FULL_OUTPUT = 3
204
    };
205

	
206
  private:
207

	
208
    MessageLevel _message_level;
209

	
210
  public:
211

	
212
    ///Set the verbosity of the messages
213

	
214
    ///Set the verbosity of the messages
215
    ///
216
    ///\param m is the level of the messages output by the solver routines.
217
    void messageLevel(MessageLevel m);
218 200
  };
219 201

	
220 202
  /// \brief Interface for the GLPK MIP solver
221 203
  ///
222 204
  /// This class implements an interface for the GLPK MIP solver.
223 205
  ///\ingroup lp_group
224 206
  class GlpkMip : public MipSolver, public GlpkBase {
225 207
  public:
226 208

	
227 209
    ///\e
228 210
    GlpkMip();
229 211
    ///\e
230 212
    GlpkMip(const GlpkMip&);
231 213

	
232 214
    virtual GlpkMip* cloneSolver() const;
233 215
    virtual GlpkMip* newSolver() const;
234 216

	
235 217
  protected:
236 218

	
237 219
    virtual const char* _solverName() const;
238 220

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

	
242 224
    virtual SolveExitStatus _solve();
243 225
    virtual ProblemType _getType() const;
244 226
    virtual Value _getSol(int i) const;
245 227
    virtual Value _getSolValue() const;
246 228

	
247
    ///Enum for \c messageLevel() parameter
248
    enum MessageLevel {
249
      /// no output (default value)
250
      MESSAGE_NO_OUTPUT = 0,
251
      /// error messages only
252
      MESSAGE_ERROR_MESSAGE = 1,
253
      /// normal output
254
      MESSAGE_NORMAL_OUTPUT = 2,
255
      /// full output (includes informational messages)
256
      MESSAGE_FULL_OUTPUT = 3
257
    };
258

	
259
  private:
260

	
261
    MessageLevel _message_level;
262

	
263
  public:
264

	
265
    ///Set the verbosity of the messages
266

	
267
    ///Set the verbosity of the messages
268
    ///
269
    ///\param m is the level of the messages output by the solver routines.
270
    void messageLevel(MessageLevel m);
271 229
  };
272 230

	
273 231

	
274 232
} //END OF NAMESPACE LEMON
275 233

	
276 234
#endif //LEMON_GLPK_H
277 235

	
Show white space 128 line context
... ...
@@ -8,128 +8,143 @@
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
10 10
 * provided that this copyright notice appears in all copies. For
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
#ifndef LEMON_LP_BASE_H
20 20
#define LEMON_LP_BASE_H
21 21

	
22 22
#include<iostream>
23 23
#include<vector>
24 24
#include<map>
25 25
#include<limits>
26 26
#include<lemon/math.h>
27 27

	
28 28
#include<lemon/error.h>
29 29
#include<lemon/assert.h>
30 30

	
31 31
#include<lemon/core.h>
32 32
#include<lemon/bits/solver_bits.h>
33 33

	
34 34
///\file
35 35
///\brief The interface of the LP solver interface.
36 36
///\ingroup lp_group
37 37
namespace lemon {
38 38

	
39 39
  ///Common base class for LP and MIP solvers
40 40

	
41 41
  ///Usually this class is not used directly, please use one of the concrete
42 42
  ///implementations of the solver interface.
43 43
  ///\ingroup lp_group
44 44
  class LpBase {
45 45

	
46 46
  protected:
47 47

	
48 48
    _solver_bits::VarIndex rows;
49 49
    _solver_bits::VarIndex cols;
50 50

	
51 51
  public:
52 52

	
53 53
    ///Possible outcomes of an LP solving procedure
54 54
    enum SolveExitStatus {
55 55
      ///This means that the problem has been successfully solved: either
56 56
      ///an optimal solution has been found or infeasibility/unboundedness
57 57
      ///has been proved.
58 58
      SOLVED = 0,
59 59
      ///Any other case (including the case when some user specified
60 60
      ///limit has been exceeded)
61 61
      UNSOLVED = 1
62 62
    };
63 63

	
64 64
    ///Direction of the optimization
65 65
    enum Sense {
66 66
      /// Minimization
67 67
      MIN,
68 68
      /// Maximization
69 69
      MAX
70 70
    };
71 71

	
72
    ///Enum for \c messageLevel() parameter
73
    enum MessageLevel {
74
      /// no output (default value)
75
      MESSAGE_NOTHING,
76
      /// error messages only
77
      MESSAGE_ERROR,
78
      /// warnings
79
      MESSAGE_WARNING,
80
      /// normal output
81
      MESSAGE_NORMAL,
82
      /// verbose output
83
      MESSAGE_VERBOSE
84
    };
85
    
86

	
72 87
    ///The floating point type used by the solver
73 88
    typedef double Value;
74 89
    ///The infinity constant
75 90
    static const Value INF;
76 91
    ///The not a number constant
77 92
    static const Value NaN;
78 93

	
79 94
    friend class Col;
80 95
    friend class ColIt;
81 96
    friend class Row;
82 97
    friend class RowIt;
83 98

	
84 99
    ///Refer to a column of the LP.
85 100

	
86 101
    ///This type is used to refer to a column of the LP.
87 102
    ///
88 103
    ///Its value remains valid and correct even after the addition or erase of
89 104
    ///other columns.
90 105
    ///
91 106
    ///\note This class is similar to other Item types in LEMON, like
92 107
    ///Node and Arc types in digraph.
93 108
    class Col {
94 109
      friend class LpBase;
95 110
    protected:
96 111
      int _id;
97 112
      explicit Col(int id) : _id(id) {}
98 113
    public:
99 114
      typedef Value ExprValue;
100 115
      typedef True LpCol;
101 116
      /// Default constructor
102 117
      
103 118
      /// \warning The default constructor sets the Col to an
104 119
      /// undefined value.
105 120
      Col() {}
106 121
      /// Invalid constructor \& conversion.
107 122
      
108 123
      /// This constructor initializes the Col to be invalid.
109 124
      /// \sa Invalid for more details.      
110 125
      Col(const Invalid&) : _id(-1) {}
111 126
      /// Equality operator
112 127

	
113 128
      /// Two \ref Col "Col"s are equal if and only if they point to
114 129
      /// the same LP column or both are invalid.
115 130
      bool operator==(Col c) const  {return _id == c._id;}
116 131
      /// Inequality operator
117 132

	
118 133
      /// \sa operator==(Col c)
119 134
      ///
120 135
      bool operator!=(Col c) const  {return _id != c._id;}
121 136
      /// Artificial ordering operator.
122 137

	
123 138
      /// To allow the use of this object in std::map or similar
124 139
      /// associative container we require this.
125 140
      ///
126 141
      /// \note This operator only have to define some strict ordering of
127 142
      /// the items; this order has nothing to do with the iteration
128 143
      /// ordering of the items.
129 144
      bool operator<(Col c) const  {return _id < c._id;}
130 145
    };
131 146

	
132 147
    ///Iterator for iterate over the columns of an LP problem
133 148

	
134 149
    /// Its usage is quite simple, for example you can count the number
135 150
    /// of columns in an LP \c lp:
... ...
@@ -912,128 +927,130 @@
912 927
      bool operator!=(const ExprIterator& it) const {
913 928
        return _host_it != it._host_it;
914 929
      }
915 930

	
916 931
    };
917 932

	
918 933
  protected:
919 934

	
920 935
    //Abstract virtual functions
921 936

	
922 937
    virtual int _addColId(int col) { return cols.addIndex(col); }
923 938
    virtual int _addRowId(int row) { return rows.addIndex(row); }
924 939

	
925 940
    virtual void _eraseColId(int col) { cols.eraseIndex(col); }
926 941
    virtual void _eraseRowId(int row) { rows.eraseIndex(row); }
927 942

	
928 943
    virtual int _addCol() = 0;
929 944
    virtual int _addRow() = 0;
930 945

	
931 946
    virtual void _eraseCol(int col) = 0;
932 947
    virtual void _eraseRow(int row) = 0;
933 948

	
934 949
    virtual void _getColName(int col, std::string& name) const = 0;
935 950
    virtual void _setColName(int col, const std::string& name) = 0;
936 951
    virtual int _colByName(const std::string& name) const = 0;
937 952

	
938 953
    virtual void _getRowName(int row, std::string& name) const = 0;
939 954
    virtual void _setRowName(int row, const std::string& name) = 0;
940 955
    virtual int _rowByName(const std::string& name) const = 0;
941 956

	
942 957
    virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e) = 0;
943 958
    virtual void _getRowCoeffs(int i, InsertIterator b) const = 0;
944 959

	
945 960
    virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e) = 0;
946 961
    virtual void _getColCoeffs(int i, InsertIterator b) const = 0;
947 962

	
948 963
    virtual void _setCoeff(int row, int col, Value value) = 0;
949 964
    virtual Value _getCoeff(int row, int col) const = 0;
950 965

	
951 966
    virtual void _setColLowerBound(int i, Value value) = 0;
952 967
    virtual Value _getColLowerBound(int i) const = 0;
953 968

	
954 969
    virtual void _setColUpperBound(int i, Value value) = 0;
955 970
    virtual Value _getColUpperBound(int i) const = 0;
956 971

	
957 972
    virtual void _setRowLowerBound(int i, Value value) = 0;
958 973
    virtual Value _getRowLowerBound(int i) const = 0;
959 974

	
960 975
    virtual void _setRowUpperBound(int i, Value value) = 0;
961 976
    virtual Value _getRowUpperBound(int i) const = 0;
962 977

	
963 978
    virtual void _setObjCoeffs(ExprIterator b, ExprIterator e) = 0;
964 979
    virtual void _getObjCoeffs(InsertIterator b) const = 0;
965 980

	
966 981
    virtual void _setObjCoeff(int i, Value obj_coef) = 0;
967 982
    virtual Value _getObjCoeff(int i) const = 0;
968 983

	
969 984
    virtual void _setSense(Sense) = 0;
970 985
    virtual Sense _getSense() const = 0;
971 986

	
972 987
    virtual void _clear() = 0;
973 988

	
974 989
    virtual const char* _solverName() const = 0;
975 990

	
991
    virtual void _messageLevel(MessageLevel level) = 0;
992

	
976 993
    //Own protected stuff
977 994

	
978 995
    //Constant component of the objective function
979 996
    Value obj_const_comp;
980 997

	
981 998
    LpBase() : rows(), cols(), obj_const_comp(0) {}
982 999

	
983 1000
  public:
984 1001

	
985 1002
    /// Virtual destructor
986 1003
    virtual ~LpBase() {}
987 1004

	
988 1005
    ///Gives back the name of the solver.
989 1006
    const char* solverName() const {return _solverName();}
990 1007

	
991 1008
    ///\name Build up and modify the LP
992 1009

	
993 1010
    ///@{
994 1011

	
995 1012
    ///Add a new empty column (i.e a new variable) to the LP
996 1013
    Col addCol() { Col c; c._id = _addColId(_addCol()); return c;}
997 1014

	
998 1015
    ///\brief Adds several new columns (i.e variables) at once
999 1016
    ///
1000 1017
    ///This magic function takes a container as its argument and fills
1001 1018
    ///its elements with new columns (i.e. variables)
1002 1019
    ///\param t can be
1003 1020
    ///- a standard STL compatible iterable container with
1004 1021
    ///\ref Col as its \c values_type like
1005 1022
    ///\code
1006 1023
    ///std::vector<LpBase::Col>
1007 1024
    ///std::list<LpBase::Col>
1008 1025
    ///\endcode
1009 1026
    ///- a standard STL compatible iterable container with
1010 1027
    ///\ref Col as its \c mapped_type like
1011 1028
    ///\code
1012 1029
    ///std::map<AnyType,LpBase::Col>
1013 1030
    ///\endcode
1014 1031
    ///- an iterable lemon \ref concepts::WriteMap "write map" like
1015 1032
    ///\code
1016 1033
    ///ListGraph::NodeMap<LpBase::Col>
1017 1034
    ///ListGraph::ArcMap<LpBase::Col>
1018 1035
    ///\endcode
1019 1036
    ///\return The number of the created column.
1020 1037
#ifdef DOXYGEN
1021 1038
    template<class T>
1022 1039
    int addColSet(T &t) { return 0;}
1023 1040
#else
1024 1041
    template<class T>
1025 1042
    typename enable_if<typename T::value_type::LpCol,int>::type
1026 1043
    addColSet(T &t,dummy<0> = 0) {
1027 1044
      int s=0;
1028 1045
      for(typename T::iterator i=t.begin();i!=t.end();++i) {*i=addCol();s++;}
1029 1046
      return s;
1030 1047
    }
1031 1048
    template<class T>
1032 1049
    typename enable_if<typename T::value_type::second_type::LpCol,
1033 1050
                       int>::type
1034 1051
    addColSet(T &t,dummy<1> = 1) {
1035 1052
      int s=0;
1036 1053
      for(typename T::iterator i=t.begin();i!=t.end();++i) {
1037 1054
        i->second=addCol();
1038 1055
        s++;
1039 1056
      }
... ...
@@ -1466,128 +1483,131 @@
1466 1483
      return _getRowLowerBound(rows(id(r)));
1467 1484
    }
1468 1485

	
1469 1486
    /// Set the upper bound of a row (i.e a constraint)
1470 1487

	
1471 1488
    /// The upper bound of a constraint (row) has to be given by an
1472 1489
    /// extended number of type Value, i.e. a finite number of type
1473 1490
    /// Value or -\ref INF.
1474 1491
    void rowUpperBound(Row r, Value value) {
1475 1492
      _setRowUpperBound(rows(id(r)),value);
1476 1493
    }
1477 1494

	
1478 1495
    /// Get the upper bound of a row (i.e a constraint)
1479 1496

	
1480 1497
    /// This function returns the upper bound for row (constraint) \c c
1481 1498
    /// (this might be -\ref INF as well).
1482 1499
    ///\return The upper bound for row \c r
1483 1500
    Value rowUpperBound(Row r) const {
1484 1501
      return _getRowUpperBound(rows(id(r)));
1485 1502
    }
1486 1503

	
1487 1504
    ///Set an element of the objective function
1488 1505
    void objCoeff(Col c, Value v) {_setObjCoeff(cols(id(c)),v); };
1489 1506

	
1490 1507
    ///Get an element of the objective function
1491 1508
    Value objCoeff(Col c) const { return _getObjCoeff(cols(id(c))); };
1492 1509

	
1493 1510
    ///Set the objective function
1494 1511

	
1495 1512
    ///\param e is a linear expression of type \ref Expr.
1496 1513
    ///
1497 1514
    void obj(const Expr& e) {
1498 1515
      _setObjCoeffs(ExprIterator(e.comps.begin(), cols),
1499 1516
                    ExprIterator(e.comps.end(), cols));
1500 1517
      obj_const_comp = *e;
1501 1518
    }
1502 1519

	
1503 1520
    ///Get the objective function
1504 1521

	
1505 1522
    ///\return the objective function as a linear expression of type
1506 1523
    ///Expr.
1507 1524
    Expr obj() const {
1508 1525
      Expr e;
1509 1526
      _getObjCoeffs(InsertIterator(e.comps, cols));
1510 1527
      *e = obj_const_comp;
1511 1528
      return e;
1512 1529
    }
1513 1530

	
1514 1531

	
1515 1532
    ///Set the direction of optimization
1516 1533
    void sense(Sense sense) { _setSense(sense); }
1517 1534

	
1518 1535
    ///Query the direction of the optimization
1519 1536
    Sense sense() const {return _getSense(); }
1520 1537

	
1521 1538
    ///Set the sense to maximization
1522 1539
    void max() { _setSense(MAX); }
1523 1540

	
1524 1541
    ///Set the sense to maximization
1525 1542
    void min() { _setSense(MIN); }
1526 1543

	
1527 1544
    ///Clears the problem
1528 1545
    void clear() { _clear(); }
1529 1546

	
1547
    /// Sets the message level of the solver
1548
    void messageLevel(MessageLevel level) { _messageLevel(level); }
1549

	
1530 1550
    ///@}
1531 1551

	
1532 1552
  };
1533 1553

	
1534 1554
  /// Addition
1535 1555

	
1536 1556
  ///\relates LpBase::Expr
1537 1557
  ///
1538 1558
  inline LpBase::Expr operator+(const LpBase::Expr &a, const LpBase::Expr &b) {
1539 1559
    LpBase::Expr tmp(a);
1540 1560
    tmp+=b;
1541 1561
    return tmp;
1542 1562
  }
1543 1563
  ///Substraction
1544 1564

	
1545 1565
  ///\relates LpBase::Expr
1546 1566
  ///
1547 1567
  inline LpBase::Expr operator-(const LpBase::Expr &a, const LpBase::Expr &b) {
1548 1568
    LpBase::Expr tmp(a);
1549 1569
    tmp-=b;
1550 1570
    return tmp;
1551 1571
  }
1552 1572
  ///Multiply with constant
1553 1573

	
1554 1574
  ///\relates LpBase::Expr
1555 1575
  ///
1556 1576
  inline LpBase::Expr operator*(const LpBase::Expr &a, const LpBase::Value &b) {
1557 1577
    LpBase::Expr tmp(a);
1558 1578
    tmp*=b;
1559 1579
    return tmp;
1560 1580
  }
1561 1581

	
1562 1582
  ///Multiply with constant
1563 1583

	
1564 1584
  ///\relates LpBase::Expr
1565 1585
  ///
1566 1586
  inline LpBase::Expr operator*(const LpBase::Value &a, const LpBase::Expr &b) {
1567 1587
    LpBase::Expr tmp(b);
1568 1588
    tmp*=a;
1569 1589
    return tmp;
1570 1590
  }
1571 1591
  ///Divide with constant
1572 1592

	
1573 1593
  ///\relates LpBase::Expr
1574 1594
  ///
1575 1595
  inline LpBase::Expr operator/(const LpBase::Expr &a, const LpBase::Value &b) {
1576 1596
    LpBase::Expr tmp(a);
1577 1597
    tmp/=b;
1578 1598
    return tmp;
1579 1599
  }
1580 1600

	
1581 1601
  ///Create constraint
1582 1602

	
1583 1603
  ///\relates LpBase::Constr
1584 1604
  ///
1585 1605
  inline LpBase::Constr operator<=(const LpBase::Expr &e,
1586 1606
                                   const LpBase::Expr &f) {
1587 1607
    return LpBase::Constr(0, f - e, LpBase::INF);
1588 1608
  }
1589 1609

	
1590 1610
  ///Create constraint
1591 1611

	
1592 1612
  ///\relates LpBase::Constr
1593 1613
  ///
Show white space 128 line context
... ...
@@ -23,112 +23,114 @@
23 23
namespace lemon {
24 24

	
25 25
  int SkeletonSolverBase::_addCol()
26 26
  {
27 27
    return ++col_num;
28 28
  }
29 29

	
30 30
  int SkeletonSolverBase::_addRow()
31 31
  {
32 32
    return ++row_num;
33 33
  }
34 34

	
35 35
  void SkeletonSolverBase::_eraseCol(int) {}
36 36
  void SkeletonSolverBase::_eraseRow(int) {}
37 37

	
38 38
  void SkeletonSolverBase::_getColName(int, std::string &) const {}
39 39
  void SkeletonSolverBase::_setColName(int, const std::string &) {}
40 40
  int SkeletonSolverBase::_colByName(const std::string&) const { return -1; }
41 41

	
42 42
  void SkeletonSolverBase::_getRowName(int, std::string &) const {}
43 43
  void SkeletonSolverBase::_setRowName(int, const std::string &) {}
44 44
  int SkeletonSolverBase::_rowByName(const std::string&) const { return -1; }
45 45

	
46 46
  void SkeletonSolverBase::_setRowCoeffs(int, ExprIterator, ExprIterator) {}
47 47
  void SkeletonSolverBase::_getRowCoeffs(int, InsertIterator) const {}
48 48

	
49 49
  void SkeletonSolverBase::_setColCoeffs(int, ExprIterator, ExprIterator) {}
50 50
  void SkeletonSolverBase::_getColCoeffs(int, InsertIterator) const {}
51 51

	
52 52
  void SkeletonSolverBase::_setCoeff(int, int, Value) {}
53 53
  SkeletonSolverBase::Value SkeletonSolverBase::_getCoeff(int, int) const
54 54
  { return 0; }
55 55

	
56 56
  void SkeletonSolverBase::_setColLowerBound(int, Value) {}
57 57
  SkeletonSolverBase::Value SkeletonSolverBase::_getColLowerBound(int) const
58 58
  {  return 0; }
59 59

	
60 60
  void SkeletonSolverBase::_setColUpperBound(int, Value) {}
61 61
  SkeletonSolverBase::Value SkeletonSolverBase::_getColUpperBound(int) const
62 62
  {  return 0; }
63 63

	
64 64
  void SkeletonSolverBase::_setRowLowerBound(int, Value) {}
65 65
  SkeletonSolverBase::Value SkeletonSolverBase::_getRowLowerBound(int) const
66 66
  {  return 0; }
67 67

	
68 68
  void SkeletonSolverBase::_setRowUpperBound(int, Value) {}
69 69
  SkeletonSolverBase::Value SkeletonSolverBase::_getRowUpperBound(int) const
70 70
  {  return 0; }
71 71

	
72 72
  void SkeletonSolverBase::_setObjCoeffs(ExprIterator, ExprIterator) {}
73 73
  void SkeletonSolverBase::_getObjCoeffs(InsertIterator) const {};
74 74

	
75 75
  void SkeletonSolverBase::_setObjCoeff(int, Value) {}
76 76
  SkeletonSolverBase::Value SkeletonSolverBase::_getObjCoeff(int) const
77 77
  {  return 0; }
78 78

	
79 79
  void SkeletonSolverBase::_setSense(Sense) {}
80 80
  SkeletonSolverBase::Sense SkeletonSolverBase::_getSense() const
81 81
  { return MIN; }
82 82

	
83 83
  void SkeletonSolverBase::_clear() {
84 84
    row_num = col_num = 0;
85 85
  }
86 86

	
87
  void SkeletonSolverBase::_messageLevel(MessageLevel) {}
88

	
87 89
  LpSkeleton::SolveExitStatus LpSkeleton::_solve() { return SOLVED; }
88 90

	
89 91
  LpSkeleton::Value LpSkeleton::_getPrimal(int) const { return 0; }
90 92
  LpSkeleton::Value LpSkeleton::_getDual(int) const { return 0; }
91 93
  LpSkeleton::Value LpSkeleton::_getPrimalValue() const { return 0; }
92 94

	
93 95
  LpSkeleton::Value LpSkeleton::_getPrimalRay(int) const { return 0; }
94 96
  LpSkeleton::Value LpSkeleton::_getDualRay(int) const { return 0; }
95 97

	
96 98
  LpSkeleton::ProblemType LpSkeleton::_getPrimalType() const
97 99
  { return UNDEFINED; }
98 100

	
99 101
  LpSkeleton::ProblemType LpSkeleton::_getDualType() const
100 102
  { return UNDEFINED; }
101 103

	
102 104
  LpSkeleton::VarStatus LpSkeleton::_getColStatus(int) const
103 105
  { return BASIC; }
104 106

	
105 107
  LpSkeleton::VarStatus LpSkeleton::_getRowStatus(int) const
106 108
  { return BASIC; }
107 109

	
108 110
  LpSkeleton* LpSkeleton::newSolver() const
109 111
  { return static_cast<LpSkeleton*>(0); }
110 112

	
111 113
  LpSkeleton* LpSkeleton::cloneSolver() const
112 114
  { return static_cast<LpSkeleton*>(0); }
113 115

	
114 116
  const char* LpSkeleton::_solverName() const { return "LpSkeleton"; }
115 117

	
116 118
  MipSkeleton::SolveExitStatus MipSkeleton::_solve()
117 119
  { return SOLVED; }
118 120

	
119 121
  MipSkeleton::Value MipSkeleton::_getSol(int) const { return 0; }
120 122
  MipSkeleton::Value MipSkeleton::_getSolValue() const { return 0; }
121 123

	
122 124
  MipSkeleton::ProblemType MipSkeleton::_getType() const
123 125
  { return UNDEFINED; }
124 126

	
125 127
  MipSkeleton* MipSkeleton::newSolver() const
126 128
  { return static_cast<MipSkeleton*>(0); }
127 129

	
128 130
  MipSkeleton* MipSkeleton::cloneSolver() const
129 131
  { return static_cast<MipSkeleton*>(0); }
130 132

	
131 133
  const char* MipSkeleton::_solverName() const { return "MipSkeleton"; }
132 134

	
133 135
} //namespace lemon
134 136

	
Show white space 128 line context
... ...
@@ -79,128 +79,130 @@
79 79
    virtual Value _getCoeff(int row, int col) const;
80 80

	
81 81
    /// The lower bound of a variable (column) have to be given by an
82 82
    /// extended number of type Value, i.e. a finite number of type
83 83
    /// Value or -\ref INF.
84 84
    virtual void _setColLowerBound(int i, Value value);
85 85
    /// \e
86 86

	
87 87
    /// The lower bound of a variable (column) is an
88 88
    /// extended number of type Value, i.e. a finite number of type
89 89
    /// Value or -\ref INF.
90 90
    virtual Value _getColLowerBound(int i) const;
91 91

	
92 92
    /// The upper bound of a variable (column) have to be given by an
93 93
    /// extended number of type Value, i.e. a finite number of type
94 94
    /// Value or \ref INF.
95 95
    virtual void _setColUpperBound(int i, Value value);
96 96
    /// \e
97 97

	
98 98
    /// The upper bound of a variable (column) is an
99 99
    /// extended number of type Value, i.e. a finite number of type
100 100
    /// Value or \ref INF.
101 101
    virtual Value _getColUpperBound(int i) const;
102 102

	
103 103
    /// The lower bound of a constraint (row) have to be given by an
104 104
    /// extended number of type Value, i.e. a finite number of type
105 105
    /// Value or -\ref INF.
106 106
    virtual void _setRowLowerBound(int i, Value value);
107 107
    /// \e
108 108

	
109 109
    /// The lower bound of a constraint (row) is an
110 110
    /// extended number of type Value, i.e. a finite number of type
111 111
    /// Value or -\ref INF.
112 112
    virtual Value _getRowLowerBound(int i) const;
113 113

	
114 114
    /// The upper bound of a constraint (row) have to be given by an
115 115
    /// extended number of type Value, i.e. a finite number of type
116 116
    /// Value or \ref INF.
117 117
    virtual void _setRowUpperBound(int i, Value value);
118 118
    /// \e
119 119

	
120 120
    /// The upper bound of a constraint (row) is an
121 121
    /// extended number of type Value, i.e. a finite number of type
122 122
    /// Value or \ref INF.
123 123
    virtual Value _getRowUpperBound(int i) const;
124 124

	
125 125
    /// \e
126 126
    virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
127 127
    /// \e
128 128
    virtual void _getObjCoeffs(InsertIterator b) const;
129 129

	
130 130
    /// \e
131 131
    virtual void _setObjCoeff(int i, Value obj_coef);
132 132
    /// \e
133 133
    virtual Value _getObjCoeff(int i) const;
134 134

	
135 135
    ///\e
136 136
    virtual void _setSense(Sense);
137 137
    ///\e
138 138
    virtual Sense _getSense() const;
139 139

	
140 140
    ///\e
141 141
    virtual void _clear();
142 142

	
143
    ///\e
144
    virtual void _messageLevel(MessageLevel);
143 145
  };
144 146

	
145 147
  /// \brief Skeleton class for an LP solver interface
146 148
  ///
147 149
  ///This class does nothing, but it can serve as a skeleton when
148 150
  ///implementing an interface to new solvers.
149 151

	
150 152
  ///\ingroup lp_group
151 153
  class LpSkeleton : public LpSolver, public SkeletonSolverBase {
152 154
  public:
153 155
    ///\e
154 156
    LpSkeleton() : LpSolver(), SkeletonSolverBase() {}
155 157
    ///\e
156 158
    virtual LpSkeleton* newSolver() const;
157 159
    ///\e
158 160
    virtual LpSkeleton* cloneSolver() const;
159 161
  protected:
160 162

	
161 163
    ///\e
162 164
    virtual SolveExitStatus _solve();
163 165

	
164 166
    ///\e
165 167
    virtual Value _getPrimal(int i) const;
166 168
    ///\e
167 169
    virtual Value _getDual(int i) const;
168 170

	
169 171
    ///\e
170 172
    virtual Value _getPrimalValue() const;
171 173

	
172 174
    ///\e
173 175
    virtual Value _getPrimalRay(int i) const;
174 176
    ///\e
175 177
    virtual Value _getDualRay(int i) const;
176 178

	
177 179
    ///\e
178 180
    virtual ProblemType _getPrimalType() const;
179 181
    ///\e
180 182
    virtual ProblemType _getDualType() const;
181 183

	
182 184
    ///\e
183 185
    virtual VarStatus _getColStatus(int i) const;
184 186
    ///\e
185 187
    virtual VarStatus _getRowStatus(int i) const;
186 188

	
187 189
    ///\e
188 190
    virtual const char* _solverName() const;
189 191

	
190 192
  };
191 193

	
192 194
  /// \brief Skeleton class for a MIP solver interface
193 195
  ///
194 196
  ///This class does nothing, but it can serve as a skeleton when
195 197
  ///implementing an interface to new solvers.
196 198
  ///\ingroup lp_group
197 199
  class MipSkeleton : public MipSolver, public SkeletonSolverBase {
198 200
  public:
199 201
    ///\e
200 202
    MipSkeleton() : MipSolver(), SkeletonSolverBase() {}
201 203
    ///\e
202 204
    virtual MipSkeleton* newSolver() const;
203 205
    ///\e
204 206
    virtual MipSkeleton* cloneSolver() const;
205 207

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

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

	
22 22
#include <soplex.h>
23
#include <spxout.h>
23 24

	
24 25

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

	
29 30
  SoplexLp::SoplexLp() {
30 31
    soplex = new soplex::SoPlex;
32
    messageLevel(MESSAGE_NOTHING);
31 33
  }
32 34

	
33 35
  SoplexLp::~SoplexLp() {
34 36
    delete soplex;
35 37
  }
36 38

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

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

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

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

	
52
    messageLevel(MESSAGE_NOTHING);
50 53
  }
51 54

	
52 55
  void SoplexLp::_clear_temporals() {
53 56
    _primal_values.clear();
54 57
    _dual_values.clear();
55 58
  }
56 59

	
57 60
  SoplexLp* SoplexLp::newSolver() const {
58 61
    SoplexLp* newlp = new SoplexLp();
59 62
    return newlp;
60 63
  }
61 64

	
62 65
  SoplexLp* SoplexLp::cloneSolver() const {
63 66
    SoplexLp* newlp = new SoplexLp(*this);
64 67
    return newlp;
65 68
  }
66 69

	
67 70
  const char* SoplexLp::_solverName() const { return "SoplexLp"; }
68 71

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

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

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

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

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

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

	
91 94

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

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

	
108 111
  void SoplexLp::_eraseColId(int i) {
109 112
    cols.eraseIndex(i);
110 113
    cols.relocateIndex(i, cols.maxIndex());
111 114
  }
112 115
  void SoplexLp::_eraseRowId(int i) {
113 116
    rows.eraseIndex(i);
... ...
@@ -211,128 +214,130 @@
211 214
    return value != -soplex::infinity ? value : -INF;
212 215
  }
213 216

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

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

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

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

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

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

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

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

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

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

	
271 274
  SoplexLp::SolveExitStatus SoplexLp::_solve() {
272 275

	
273 276
    _clear_temporals();
274 277

	
278
    _applyMessageLevel();
279

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

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

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

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

	
305 310
  SoplexLp::Value SoplexLp::_getPrimalValue() const {
306 311
    return soplex->objValue();
307 312
  }
308 313

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

	
327 332
  SoplexLp::VarStatus SoplexLp::_getRowStatus(int i) const {
328 333
    switch (soplex->getBasisRowStatus(i)) {
329 334
    case soplex::SPxSolver::BASIC:
330 335
      return BASIC;
331 336
    case soplex::SPxSolver::ON_UPPER:
332 337
      return UPPER;
333 338
    case soplex::SPxSolver::ON_LOWER:
334 339
      return LOWER;
335 340
    case soplex::SPxSolver::FIXED:
336 341
      return FIXED;
337 342
    case soplex::SPxSolver::ZERO:
338 343
      return FREE;
... ...
@@ -358,66 +363,90 @@
358 363
      soplex->getDualfarkas(dv);
359 364
    }
360 365
    return _dual_ray[i];
361 366
  }
362 367

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

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

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

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

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

	
427
  void SoplexLp::_messageLevel(MessageLevel level) {
428
    switch (level) {
429
    case MESSAGE_NOTHING:
430
      _message_level = -1;
431
      break;
432
    case MESSAGE_ERROR:
433
      _message_level = soplex::SPxOut::ERROR;
434
      break;
435
    case MESSAGE_WARNING:
436
      _message_level = soplex::SPxOut::WARNING;
437
      break;
438
    case MESSAGE_NORMAL:
439
      _message_level = soplex::SPxOut::INFO2;
440
      break;
441
    case MESSAGE_VERBOSE:
442
      _message_level = soplex::SPxOut::DEBUG;
443
      break;
444
    }
445
  }
446

	
447
  void SoplexLp::_applyMessageLevel() {
448
    soplex::Param::setVerbose(_message_level);
449
  }
450

	
422 451
} //namespace lemon
423 452

	
Show white space 128 line context
... ...
@@ -83,70 +83,75 @@
83 83
    virtual const char* _solverName() const;
84 84

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	
134 134
    virtual Value _getPrimalValue() const;
135 135

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

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

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

	
145 145
    virtual void _clear();
146 146

	
147
    void _messageLevel(MessageLevel m);
148
    void _applyMessageLevel();
149

	
150
    int _message_level;
151

	
147 152
  };
148 153

	
149 154
} //END OF NAMESPACE LEMON
150 155

	
151 156
#endif //LEMON_SOPLEX_H
152 157

	
0 comments (0 inline)