COIN-OR::LEMON - Graph Library

source: lemon/lemon/cplex.cc @ 1349:f8ec64f78b5f

Last change on this file since 1349:f8ec64f78b5f was 1349:f8ec64f78b5f, checked in by Alpar Juttner <alpar@…>, 4 years ago

Merge bugfix #473

File size: 27.1 KB
Line 
1/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 *
3 * This file is a part of LEMON, a generic C++ optimization library.
4 *
5 * Copyright (C) 2003-2013
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 *
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
12 *
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
15 * purpose.
16 *
17 */
18
19#include <iostream>
20#include <vector>
21#include <cstring>
22
23#include <lemon/cplex.h>
24
25extern "C" {
26#include <ilcplex/cplex.h>
27}
28
29
30///\file
31///\brief Implementation of the LEMON-CPLEX lp solver interface.
32namespace lemon {
33
34  CplexEnv::LicenseError::LicenseError(int status) {
35    if (!CPXgeterrorstring(0, status, _message)) {
36      std::strcpy(_message, "Cplex unknown error");
37    }
38  }
39
40  void CplexEnv::incCnt()
41  {
42    _cnt_lock->lock();
43    ++(*_cnt);
44    _cnt_lock->unlock();
45  }
46
47  void CplexEnv::decCnt()
48  {
49    _cnt_lock->lock();
50    --(*_cnt);
51    if (*_cnt == 0) {
52      delete _cnt;
53      _cnt_lock->unlock();
54      delete _cnt_lock;
55      CPXcloseCPLEX(&_env);
56    }
57    else _cnt_lock->unlock();
58  }
59 
60  CplexEnv::CplexEnv() {
61    int status;
62    _env = CPXopenCPLEX(&status);
63    if (_env == 0)
64      throw LicenseError(status);
65    _cnt = new int;
66    (*_cnt) = 1;
67    _cnt_lock = new bits::Lock;
68  }
69
70  CplexEnv::CplexEnv(const CplexEnv& other) {
71    _env = other._env;
72    _cnt = other._cnt;
73    _cnt_lock = other._cnt_lock;
74    incCnt();
75  }
76
77  CplexEnv& CplexEnv::operator=(const CplexEnv& other) {
78    decCnt();
79    _env = other._env;
80    _cnt = other._cnt;
81    _cnt_lock = other._cnt_lock;
82    incCnt();
83    return *this;
84  }
85
86  CplexEnv::~CplexEnv() {
87    decCnt();
88  }
89
90  CplexBase::CplexBase() : LpBase() {
91    int status;
92    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
93    messageLevel(MESSAGE_NOTHING);
94  }
95
96  CplexBase::CplexBase(const CplexEnv& env)
97    : LpBase(), _env(env) {
98    int status;
99    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
100    messageLevel(MESSAGE_NOTHING);
101  }
102
103  CplexBase::CplexBase(const CplexBase& cplex)
104    : LpBase() {
105    int status;
106    _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status);
107    _rows = cplex._rows;
108    _cols = cplex._cols;
109    messageLevel(MESSAGE_NOTHING);
110  }
111
112  CplexBase::~CplexBase() {
113    CPXfreeprob(cplexEnv(),&_prob);
114  }
115
116  int CplexBase::_addCol() {
117    int i = CPXgetnumcols(cplexEnv(), _prob);
118    double lb = -INF, ub = INF;
119    CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0);
120    return i;
121  }
122
123
124  int CplexBase::_addRow() {
125    int i = CPXgetnumrows(cplexEnv(), _prob);
126    const double ub = INF;
127    const char s = 'L';
128    CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
129    return i;
130  }
131
132  int CplexBase::_addRow(Value lb, ExprIterator b,
133                         ExprIterator e, Value ub) {
134    int i = CPXgetnumrows(cplexEnv(), _prob);
135
136    int rmatbeg = 0;
137   
138    std::vector<int> indices;
139    std::vector<Value> values;
140
141    for(ExprIterator it=b; it!=e; ++it) {
142      indices.push_back(it->first);
143      values.push_back(it->second);
144    }
145
146    if (lb == -INF) {
147      const char s = 'L';
148      CPXaddrows(cplexEnv(), _prob, 0, 1, values.size(), &ub, &s,
149                 &rmatbeg, &indices.front(), &values.front(), 0, 0);
150    } else if (ub == INF) {
151      const char s = 'G';
152      CPXaddrows(cplexEnv(), _prob, 0, 1, values.size(), &lb, &s,
153                 &rmatbeg, &indices.front(), &values.front(), 0, 0);
154    } else if (lb == ub){
155      const char s = 'E';
156      CPXaddrows(cplexEnv(), _prob, 0, 1, values.size(), &lb, &s,
157                 &rmatbeg, &indices.front(), &values.front(), 0, 0);
158    } else {
159      const char s = 'R';
160      double len = ub - lb;
161      CPXaddrows(cplexEnv(), _prob, 0, 1, values.size(), &ub, &s,
162                 &rmatbeg, &indices.front(), &values.front(), 0, 0);
163      CPXchgrngval(cplexEnv(), _prob, 1, &i, &len);
164    }
165   
166    return i;
167  }
168
169  void CplexBase::_eraseCol(int i) {
170    CPXdelcols(cplexEnv(), _prob, i, i);
171  }
172
173  void CplexBase::_eraseRow(int i) {
174    CPXdelrows(cplexEnv(), _prob, i, i);
175  }
176
177  void CplexBase::_eraseColId(int i) {
178    _cols.eraseIndex(i);
179    _cols.shiftIndices(i);
180  }
181  void CplexBase::_eraseRowId(int i) {
182    _rows.eraseIndex(i);
183    _rows.shiftIndices(i);
184  }
185
186  void CplexBase::_getColName(int col, std::string &name) const {
187    int size;
188    CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col);
189    if (size == 0) {
190      name.clear();
191      return;
192    }
193
194    size *= -1;
195    std::vector<char> buf(size);
196    char *cname;
197    int tmp;
198    CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size,
199                  &tmp, col, col);
200    name = cname;
201  }
202
203  void CplexBase::_setColName(int col, const std::string &name) {
204    char *cname;
205    cname = const_cast<char*>(name.c_str());
206    CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname);
207  }
208
209  int CplexBase::_colByName(const std::string& name) const {
210    int index;
211    if (CPXgetcolindex(cplexEnv(), _prob,
212                       const_cast<char*>(name.c_str()), &index) == 0) {
213      return index;
214    }
215    return -1;
216  }
217
218  void CplexBase::_getRowName(int row, std::string &name) const {
219    int size;
220    CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row);
221    if (size == 0) {
222      name.clear();
223      return;
224    }
225
226    size *= -1;
227    std::vector<char> buf(size);
228    char *cname;
229    int tmp;
230    CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size,
231                  &tmp, row, row);
232    name = cname;
233  }
234
235  void CplexBase::_setRowName(int row, const std::string &name) {
236    char *cname;
237    cname = const_cast<char*>(name.c_str());
238    CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname);
239  }
240
241  int CplexBase::_rowByName(const std::string& name) const {
242    int index;
243    if (CPXgetrowindex(cplexEnv(), _prob,
244                       const_cast<char*>(name.c_str()), &index) == 0) {
245      return index;
246    }
247    return -1;
248  }
249
250  void CplexBase::_setRowCoeffs(int i, ExprIterator b,
251                                      ExprIterator e)
252  {
253    std::vector<int> indices;
254    std::vector<int> rowlist;
255    std::vector<Value> values;
256
257    for(ExprIterator it=b; it!=e; ++it) {
258      indices.push_back(it->first);
259      values.push_back(it->second);
260      rowlist.push_back(i);
261    }
262
263    CPXchgcoeflist(cplexEnv(), _prob, values.size(),
264                   &rowlist.front(), &indices.front(), &values.front());
265  }
266
267  void CplexBase::_getRowCoeffs(int i, InsertIterator b) const {
268    int tmp1, tmp2, tmp3, length;
269    CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
270
271    length = -length;
272    std::vector<int> indices(length);
273    std::vector<double> values(length);
274
275    CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2,
276               &indices.front(), &values.front(),
277               length, &tmp3, i, i);
278
279    for (int i = 0; i < length; ++i) {
280      *b = std::make_pair(indices[i], values[i]);
281      ++b;
282    }
283  }
284
285  void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) {
286    std::vector<int> indices;
287    std::vector<int> collist;
288    std::vector<Value> values;
289
290    for(ExprIterator it=b; it!=e; ++it) {
291      indices.push_back(it->first);
292      values.push_back(it->second);
293      collist.push_back(i);
294    }
295
296    CPXchgcoeflist(cplexEnv(), _prob, values.size(),
297                   &indices.front(), &collist.front(), &values.front());
298  }
299
300  void CplexBase::_getColCoeffs(int i, InsertIterator b) const {
301
302    int tmp1, tmp2, tmp3, length;
303    CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
304
305    length = -length;
306    std::vector<int> indices(length);
307    std::vector<double> values(length);
308
309    CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2,
310               &indices.front(), &values.front(),
311               length, &tmp3, i, i);
312
313    for (int i = 0; i < length; ++i) {
314      *b = std::make_pair(indices[i], values[i]);
315      ++b;
316    }
317
318  }
319
320  void CplexBase::_setCoeff(int row, int col, Value value) {
321    CPXchgcoef(cplexEnv(), _prob, row, col, value);
322  }
323
324  CplexBase::Value CplexBase::_getCoeff(int row, int col) const {
325    CplexBase::Value value;
326    CPXgetcoef(cplexEnv(), _prob, row, col, &value);
327    return value;
328  }
329
330  void CplexBase::_setColLowerBound(int i, Value value) {
331    const char s = 'L';
332    CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
333  }
334
335  CplexBase::Value CplexBase::_getColLowerBound(int i) const {
336    CplexBase::Value res;
337    CPXgetlb(cplexEnv(), _prob, &res, i, i);
338    return res <= -CPX_INFBOUND ? -INF : res;
339  }
340
341  void CplexBase::_setColUpperBound(int i, Value value)
342  {
343    const char s = 'U';
344    CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
345  }
346
347  CplexBase::Value CplexBase::_getColUpperBound(int i) const {
348    CplexBase::Value res;
349    CPXgetub(cplexEnv(), _prob, &res, i, i);
350    return res >= CPX_INFBOUND ? INF : res;
351  }
352
353  CplexBase::Value CplexBase::_getRowLowerBound(int i) const {
354    char s;
355    CPXgetsense(cplexEnv(), _prob, &s, i, i);
356    CplexBase::Value res;
357
358    switch (s) {
359    case 'G':
360    case 'R':
361    case 'E':
362      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
363      return res <= -CPX_INFBOUND ? -INF : res;
364    default:
365      return -INF;
366    }
367  }
368
369  CplexBase::Value CplexBase::_getRowUpperBound(int i) const {
370    char s;
371    CPXgetsense(cplexEnv(), _prob, &s, i, i);
372    CplexBase::Value res;
373
374    switch (s) {
375    case 'L':
376    case 'E':
377      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
378      return res >= CPX_INFBOUND ? INF : res;
379    case 'R':
380      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
381      {
382        double rng;
383        CPXgetrngval(cplexEnv(), _prob, &rng, i, i);
384        res += rng;
385      }
386      return res >= CPX_INFBOUND ? INF : res;
387    default:
388      return INF;
389    }
390  }
391
392  //This is easier to implement
393  void CplexBase::_set_row_bounds(int i, Value lb, Value ub) {
394    if (lb == -INF) {
395      const char s = 'L';
396      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
397      CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub);
398    } else if (ub == INF) {
399      const char s = 'G';
400      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
401      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
402    } else if (lb == ub){
403      const char s = 'E';
404      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
405      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
406    } else {
407      const char s = 'R';
408      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
409      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
410      double len = ub - lb;
411      CPXchgrngval(cplexEnv(), _prob, 1, &i, &len);
412    }
413  }
414
415  void CplexBase::_setRowLowerBound(int i, Value lb)
416  {
417    LEMON_ASSERT(lb != INF, "Invalid bound");
418    _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i));
419  }
420
421  void CplexBase::_setRowUpperBound(int i, Value ub)
422  {
423
424    LEMON_ASSERT(ub != -INF, "Invalid bound");
425    _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub);
426  }
427
428  void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e)
429  {
430    std::vector<int> indices;
431    std::vector<Value> values;
432    for(ExprIterator it=b; it!=e; ++it) {
433      indices.push_back(it->first);
434      values.push_back(it->second);
435    }
436    CPXchgobj(cplexEnv(), _prob, values.size(),
437              &indices.front(), &values.front());
438
439  }
440
441  void CplexBase::_getObjCoeffs(InsertIterator b) const
442  {
443    int num = CPXgetnumcols(cplexEnv(), _prob);
444    std::vector<Value> x(num);
445
446    CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1);
447    for (int i = 0; i < num; ++i) {
448      if (x[i] != 0.0) {
449        *b = std::make_pair(i, x[i]);
450        ++b;
451      }
452    }
453  }
454
455  void CplexBase::_setObjCoeff(int i, Value obj_coef)
456  {
457    CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef);
458  }
459
460  CplexBase::Value CplexBase::_getObjCoeff(int i) const
461  {
462    Value x;
463    CPXgetobj(cplexEnv(), _prob, &x, i, i);
464    return x;
465  }
466
467  void CplexBase::_setSense(CplexBase::Sense sense) {
468    switch (sense) {
469    case MIN:
470      CPXchgobjsen(cplexEnv(), _prob, CPX_MIN);
471      break;
472    case MAX:
473      CPXchgobjsen(cplexEnv(), _prob, CPX_MAX);
474      break;
475    }
476  }
477
478  CplexBase::Sense CplexBase::_getSense() const {
479    switch (CPXgetobjsen(cplexEnv(), _prob)) {
480    case CPX_MIN:
481      return MIN;
482    case CPX_MAX:
483      return MAX;
484    default:
485      LEMON_ASSERT(false, "Invalid sense");
486      return CplexBase::Sense();
487    }
488  }
489
490  void CplexBase::_clear() {
491    CPXfreeprob(cplexEnv(),&_prob);
492    int status;
493    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
494  }
495
496  void CplexBase::_messageLevel(MessageLevel level) {
497    switch (level) {
498    case MESSAGE_NOTHING:
499      _message_enabled = false;
500      break;
501    case MESSAGE_ERROR:
502    case MESSAGE_WARNING:
503    case MESSAGE_NORMAL:
504    case MESSAGE_VERBOSE:
505      _message_enabled = true;
506      break;
507    }
508  }
509
510  void CplexBase::_applyMessageLevel() {
511    CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND,
512                   _message_enabled ? CPX_ON : CPX_OFF);
513  }
514
515  void CplexBase::_write(std::string file, std::string format) const
516  {
517    if(format == "MPS" || format == "LP")
518      CPXwriteprob(cplexEnv(), cplexLp(), file.c_str(), format.c_str());
519    else if(format == "SOL")
520      CPXsolwrite(cplexEnv(), cplexLp(), file.c_str());
521    else throw UnsupportedFormatError(format);
522  }
523
524
525
526  // CplexLp members
527
528  CplexLp::CplexLp()
529    : LpBase(), LpSolver(), CplexBase() {}
530
531  CplexLp::CplexLp(const CplexEnv& env)
532    : LpBase(), LpSolver(), CplexBase(env) {}
533
534  CplexLp::CplexLp(const CplexLp& other)
535    : LpBase(), LpSolver(), CplexBase(other) {}
536
537  CplexLp::~CplexLp() {}
538
539  CplexLp* CplexLp::newSolver() const { return new CplexLp; }
540  CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); }
541
542  const char* CplexLp::_solverName() const { return "CplexLp"; }
543
544  void CplexLp::_clear_temporals() {
545    _col_status.clear();
546    _row_status.clear();
547    _primal_ray.clear();
548    _dual_ray.clear();
549  }
550
551  // The routine returns zero unless an error occurred during the
552  // optimization. Examples of errors include exhausting available
553  // memory (CPXERR_NO_MEMORY) or encountering invalid data in the
554  // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a
555  // user-specified CPLEX limit, or proving the model infeasible or
556  // unbounded, are not considered errors. Note that a zero return
557  // value does not necessarily mean that a solution exists. Use query
558  // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain
559  // further information about the status of the optimization.
560  CplexLp::SolveExitStatus CplexLp::convertStatus(int status) {
561#if CPX_VERSION >= 800
562    if (status == 0) {
563      switch (CPXgetstat(cplexEnv(), _prob)) {
564      case CPX_STAT_OPTIMAL:
565      case CPX_STAT_INFEASIBLE:
566      case CPX_STAT_UNBOUNDED:
567        return SOLVED;
568      default:
569        return UNSOLVED;
570      }
571    } else {
572      return UNSOLVED;
573    }
574#else
575    if (status == 0) {
576      //We want to exclude some cases
577      switch (CPXgetstat(cplexEnv(), _prob)) {
578      case CPX_OBJ_LIM:
579      case CPX_IT_LIM_FEAS:
580      case CPX_IT_LIM_INFEAS:
581      case CPX_TIME_LIM_FEAS:
582      case CPX_TIME_LIM_INFEAS:
583        return UNSOLVED;
584      default:
585        return SOLVED;
586      }
587    } else {
588      return UNSOLVED;
589    }
590#endif
591  }
592
593  CplexLp::SolveExitStatus CplexLp::_solve() {
594    _clear_temporals();
595    _applyMessageLevel();
596    return convertStatus(CPXlpopt(cplexEnv(), _prob));
597  }
598
599  CplexLp::SolveExitStatus CplexLp::solvePrimal() {
600    _clear_temporals();
601    _applyMessageLevel();
602    return convertStatus(CPXprimopt(cplexEnv(), _prob));
603  }
604
605  CplexLp::SolveExitStatus CplexLp::solveDual() {
606    _clear_temporals();
607    _applyMessageLevel();
608    return convertStatus(CPXdualopt(cplexEnv(), _prob));
609  }
610
611  CplexLp::SolveExitStatus CplexLp::solveBarrier() {
612    _clear_temporals();
613    _applyMessageLevel();
614    return convertStatus(CPXbaropt(cplexEnv(), _prob));
615  }
616
617  CplexLp::Value CplexLp::_getPrimal(int i) const {
618    Value x;
619    CPXgetx(cplexEnv(), _prob, &x, i, i);
620    return x;
621  }
622
623  CplexLp::Value CplexLp::_getDual(int i) const {
624    Value y;
625    CPXgetpi(cplexEnv(), _prob, &y, i, i);
626    return y;
627  }
628
629  CplexLp::Value CplexLp::_getPrimalValue() const {
630    Value objval;
631    CPXgetobjval(cplexEnv(), _prob, &objval);
632    return objval;
633  }
634
635  CplexLp::VarStatus CplexLp::_getColStatus(int i) const {
636    if (_col_status.empty()) {
637      _col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
638      CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
639    }
640    switch (_col_status[i]) {
641    case CPX_BASIC:
642      return BASIC;
643    case CPX_FREE_SUPER:
644      return FREE;
645    case CPX_AT_LOWER:
646      return LOWER;
647    case CPX_AT_UPPER:
648      return UPPER;
649    default:
650      LEMON_ASSERT(false, "Wrong column status");
651      return CplexLp::VarStatus();
652    }
653  }
654
655  CplexLp::VarStatus CplexLp::_getRowStatus(int i) const {
656    if (_row_status.empty()) {
657      _row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
658      CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
659    }
660    switch (_row_status[i]) {
661    case CPX_BASIC:
662      return BASIC;
663    case CPX_AT_LOWER:
664      {
665        char s;
666        CPXgetsense(cplexEnv(), _prob, &s, i, i);
667        return s != 'L' ? LOWER : UPPER;
668      }
669    case CPX_AT_UPPER:
670      return UPPER;
671    default:
672      LEMON_ASSERT(false, "Wrong row status");
673      return CplexLp::VarStatus();
674    }
675  }
676
677  CplexLp::Value CplexLp::_getPrimalRay(int i) const {
678    if (_primal_ray.empty()) {
679      _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
680      CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
681    }
682    return _primal_ray[i];
683  }
684
685  CplexLp::Value CplexLp::_getDualRay(int i) const {
686    if (_dual_ray.empty()) {
687
688    }
689    return _dual_ray[i];
690  }
691
692  // Cplex 7.0 status values
693  // This table lists the statuses, returned by the CPXgetstat()
694  // routine, for solutions to LP problems or mixed integer problems. If
695  // no solution exists, the return value is zero.
696
697  // For Simplex, Barrier
698  // 1          CPX_OPTIMAL
699  //          Optimal solution found
700  // 2          CPX_INFEASIBLE
701  //          Problem infeasible
702  // 3    CPX_UNBOUNDED
703  //          Problem unbounded
704  // 4          CPX_OBJ_LIM
705  //          Objective limit exceeded in Phase II
706  // 5          CPX_IT_LIM_FEAS
707  //          Iteration limit exceeded in Phase II
708  // 6          CPX_IT_LIM_INFEAS
709  //          Iteration limit exceeded in Phase I
710  // 7          CPX_TIME_LIM_FEAS
711  //          Time limit exceeded in Phase II
712  // 8          CPX_TIME_LIM_INFEAS
713  //          Time limit exceeded in Phase I
714  // 9          CPX_NUM_BEST_FEAS
715  //          Problem non-optimal, singularities in Phase II
716  // 10         CPX_NUM_BEST_INFEAS
717  //          Problem non-optimal, singularities in Phase I
718  // 11         CPX_OPTIMAL_INFEAS
719  //          Optimal solution found, unscaled infeasibilities
720  // 12         CPX_ABORT_FEAS
721  //          Aborted in Phase II
722  // 13         CPX_ABORT_INFEAS
723  //          Aborted in Phase I
724  // 14          CPX_ABORT_DUAL_INFEAS
725  //          Aborted in barrier, dual infeasible
726  // 15          CPX_ABORT_PRIM_INFEAS
727  //          Aborted in barrier, primal infeasible
728  // 16          CPX_ABORT_PRIM_DUAL_INFEAS
729  //          Aborted in barrier, primal and dual infeasible
730  // 17          CPX_ABORT_PRIM_DUAL_FEAS
731  //          Aborted in barrier, primal and dual feasible
732  // 18          CPX_ABORT_CROSSOVER
733  //          Aborted in crossover
734  // 19          CPX_INForUNBD
735  //          Infeasible or unbounded
736  // 20   CPX_PIVOT
737  //       User pivot used
738  //
739  // Pending return values
740  // ??case CPX_ABORT_DUAL_INFEAS
741  // ??case CPX_ABORT_CROSSOVER
742  // ??case CPX_INForUNBD
743  // ??case CPX_PIVOT
744
745  //Some more interesting stuff:
746
747  // CPX_PARAM_PROBMETHOD  1062  int  LPMETHOD
748  // 0 Automatic
749  // 1 Primal Simplex
750  // 2 Dual Simplex
751  // 3 Network Simplex
752  // 4 Standard Barrier
753  // Default: 0
754  // Description: Method for linear optimization.
755  // Determines which algorithm is used when CPXlpopt() (or "optimize"
756  // in the Interactive Optimizer) is called. Currently the behavior of
757  // the "Automatic" setting is that CPLEX simply invokes the dual
758  // simplex method, but this capability may be expanded in the future
759  // so that CPLEX chooses the method based on problem characteristics
760#if CPX_VERSION < 900
761  void statusSwitch(CPXENVptr cplexEnv(),int& stat){
762    int lpmethod;
763    CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod);
764    if (lpmethod==2){
765      if (stat==CPX_UNBOUNDED){
766        stat=CPX_INFEASIBLE;
767      }
768      else{
769        if (stat==CPX_INFEASIBLE)
770          stat=CPX_UNBOUNDED;
771      }
772    }
773  }
774#else
775  void statusSwitch(CPXENVptr,int&){}
776#endif
777
778  CplexLp::ProblemType CplexLp::_getPrimalType() const {
779    // Unboundedness not treated well: the following is from cplex 9.0 doc
780    // About Unboundedness
781
782    // The treatment of models that are unbounded involves a few
783    // subtleties. Specifically, a declaration of unboundedness means that
784    // ILOG CPLEX has determined that the model has an unbounded
785    // ray. Given any feasible solution x with objective z, a multiple of
786    // the unbounded ray can be added to x to give a feasible solution
787    // with objective z-1 (or z+1 for maximization models). Thus, if a
788    // feasible solution exists, then the optimal objective is
789    // unbounded. Note that ILOG CPLEX has not necessarily concluded that
790    // a feasible solution exists. Users can call the routine CPXsolninfo
791    // to determine whether ILOG CPLEX has also concluded that the model
792    // has a feasible solution.
793
794    int stat = CPXgetstat(cplexEnv(), _prob);
795#if CPX_VERSION >= 800
796    switch (stat)
797      {
798      case CPX_STAT_OPTIMAL:
799        return OPTIMAL;
800      case CPX_STAT_UNBOUNDED:
801        return UNBOUNDED;
802      case CPX_STAT_INFEASIBLE:
803        return INFEASIBLE;
804      default:
805        return UNDEFINED;
806      }
807#else
808    statusSwitch(cplexEnv(),stat);
809    //CPXgetstat(cplexEnv(), _prob);
810    switch (stat) {
811    case 0:
812      return UNDEFINED; //Undefined
813    case CPX_OPTIMAL://Optimal
814      return OPTIMAL;
815    case CPX_UNBOUNDED://Unbounded
816      return INFEASIBLE;//In case of dual simplex
817      //return UNBOUNDED;
818    case CPX_INFEASIBLE://Infeasible
819      //    case CPX_IT_LIM_INFEAS:
820      //     case CPX_TIME_LIM_INFEAS:
821      //     case CPX_NUM_BEST_INFEAS:
822      //     case CPX_OPTIMAL_INFEAS:
823      //     case CPX_ABORT_INFEAS:
824      //     case CPX_ABORT_PRIM_INFEAS:
825      //     case CPX_ABORT_PRIM_DUAL_INFEAS:
826      return UNBOUNDED;//In case of dual simplex
827      //return INFEASIBLE;
828      //     case CPX_OBJ_LIM:
829      //     case CPX_IT_LIM_FEAS:
830      //     case CPX_TIME_LIM_FEAS:
831      //     case CPX_NUM_BEST_FEAS:
832      //     case CPX_ABORT_FEAS:
833      //     case CPX_ABORT_PRIM_DUAL_FEAS:
834      //       return FEASIBLE;
835    default:
836      return UNDEFINED; //Everything else comes here
837      //FIXME error
838    }
839#endif
840  }
841
842  // Cplex 9.0 status values
843  // CPX_STAT_ABORT_DUAL_OBJ_LIM
844  // CPX_STAT_ABORT_IT_LIM
845  // CPX_STAT_ABORT_OBJ_LIM
846  // CPX_STAT_ABORT_PRIM_OBJ_LIM
847  // CPX_STAT_ABORT_TIME_LIM
848  // CPX_STAT_ABORT_USER
849  // CPX_STAT_FEASIBLE_RELAXED
850  // CPX_STAT_INFEASIBLE
851  // CPX_STAT_INForUNBD
852  // CPX_STAT_NUM_BEST
853  // CPX_STAT_OPTIMAL
854  // CPX_STAT_OPTIMAL_FACE_UNBOUNDED
855  // CPX_STAT_OPTIMAL_INFEAS
856  // CPX_STAT_OPTIMAL_RELAXED
857  // CPX_STAT_UNBOUNDED
858
859  CplexLp::ProblemType CplexLp::_getDualType() const {
860    int stat = CPXgetstat(cplexEnv(), _prob);
861#if CPX_VERSION >= 800
862    switch (stat) {
863    case CPX_STAT_OPTIMAL:
864      return OPTIMAL;
865    case CPX_STAT_UNBOUNDED:
866      return INFEASIBLE;
867    default:
868      return UNDEFINED;
869    }
870#else
871    statusSwitch(cplexEnv(),stat);
872    switch (stat) {
873    case 0:
874      return UNDEFINED; //Undefined
875    case CPX_OPTIMAL://Optimal
876      return OPTIMAL;
877    case CPX_UNBOUNDED:
878      return INFEASIBLE;
879    default:
880      return UNDEFINED; //Everything else comes here
881      //FIXME error
882    }
883#endif
884  }
885
886  // CplexMip members
887
888  CplexMip::CplexMip()
889    : LpBase(), MipSolver(), CplexBase() {
890
891#if CPX_VERSION < 800
892    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
893#else
894    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
895#endif
896  }
897
898  CplexMip::CplexMip(const CplexEnv& env)
899    : LpBase(), MipSolver(), CplexBase(env) {
900
901#if CPX_VERSION < 800
902    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
903#else
904    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
905#endif
906
907  }
908
909  CplexMip::CplexMip(const CplexMip& other)
910    : LpBase(), MipSolver(), CplexBase(other) {}
911
912  CplexMip::~CplexMip() {}
913
914  CplexMip* CplexMip::newSolver() const { return new CplexMip; }
915  CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); }
916
917  const char* CplexMip::_solverName() const { return "CplexMip"; }
918
919  void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) {
920
921    // Note If a variable is to be changed to binary, a call to CPXchgbds
922    // should also be made to change the bounds to 0 and 1.
923
924    switch (col_type){
925    case INTEGER: {
926      const char t = 'I';
927      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
928    } break;
929    case REAL: {
930      const char t = 'C';
931      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
932    } break;
933    default:
934      break;
935    }
936  }
937
938  CplexMip::ColTypes CplexMip::_getColType(int i) const {
939    char t;
940    CPXgetctype (cplexEnv(), _prob, &t, i, i);
941    switch (t) {
942    case 'I':
943      return INTEGER;
944    case 'C':
945      return REAL;
946    default:
947      LEMON_ASSERT(false, "Invalid column type");
948      return ColTypes();
949    }
950
951  }
952
953  CplexMip::SolveExitStatus CplexMip::_solve() {
954    int status;
955    _applyMessageLevel();
956    status = CPXmipopt (cplexEnv(), _prob);
957    if (status==0)
958      return SOLVED;
959    else
960      return UNSOLVED;
961
962  }
963
964
965  CplexMip::ProblemType CplexMip::_getType() const {
966
967    int stat = CPXgetstat(cplexEnv(), _prob);
968
969    //Fortunately, MIP statuses did not change for cplex 8.0
970    switch (stat) {
971    case CPXMIP_OPTIMAL:
972      // Optimal integer solution has been found.
973    case CPXMIP_OPTIMAL_TOL:
974      // Optimal soluton with the tolerance defined by epgap or epagap has
975      // been found.
976      return OPTIMAL;
977      //This also exists in later issues
978      //    case CPXMIP_UNBOUNDED:
979      //return UNBOUNDED;
980      case CPXMIP_INFEASIBLE:
981        return INFEASIBLE;
982    default:
983      return UNDEFINED;
984    }
985    //Unboundedness not treated well: the following is from cplex 9.0 doc
986    // About Unboundedness
987
988    // The treatment of models that are unbounded involves a few
989    // subtleties. Specifically, a declaration of unboundedness means that
990    // ILOG CPLEX has determined that the model has an unbounded
991    // ray. Given any feasible solution x with objective z, a multiple of
992    // the unbounded ray can be added to x to give a feasible solution
993    // with objective z-1 (or z+1 for maximization models). Thus, if a
994    // feasible solution exists, then the optimal objective is
995    // unbounded. Note that ILOG CPLEX has not necessarily concluded that
996    // a feasible solution exists. Users can call the routine CPXsolninfo
997    // to determine whether ILOG CPLEX has also concluded that the model
998    // has a feasible solution.
999  }
1000
1001  CplexMip::Value CplexMip::_getSol(int i) const {
1002    Value x;
1003    CPXgetmipx(cplexEnv(), _prob, &x, i, i);
1004    return x;
1005  }
1006
1007  CplexMip::Value CplexMip::_getSolValue() const {
1008    Value objval;
1009    CPXgetmipobjval(cplexEnv(), _prob, &objval);
1010    return objval;
1011  }
1012
1013} //namespace lemon
1014
Note: See TracBrowser for help on using the repository browser.