COIN-OR::LEMON - Graph Library

source: lemon/lemon/cplex.cc @ 1270:dceba191c00d

Last change on this file since 1270:dceba191c00d was 1270:dceba191c00d, checked in by Alpar Juttner <alpar@…>, 6 years ago

Apply unify-sources.sh to the source tree

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