COIN-OR::LEMON - Graph Library

source: lemon-main/lemon/cplex.cc @ 1139:0900cfe4a84d

Last change on this file since 1139:0900cfe4a84d was 1139:0900cfe4a84d, checked in by Alpar Juttner <alpar@…>, 5 years ago

Threadsafe CplexEnv? (#473)

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