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 
25 extern "C" {
26 #include <ilcplex/cplex.h>
27 }
28 
29 
30 ///\file
31 ///\brief Implementation of the LEMON-CPLEX lp solver interface.
32 namespace lemon {
33 
LicenseError(int status)34   CplexEnv::LicenseError::LicenseError(int status) {
35     if (!CPXgeterrorstring(0, status, _message)) {
36       std::strcpy(_message, "Cplex unknown error");
37     }
38   }
39 
CplexEnv()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 
CplexEnv(const CplexEnv & other)52   CplexEnv::CplexEnv(const CplexEnv& other) {
53     _env = other._env;
54     _cnt = other._cnt;
55     ++(*_cnt);
56   }
57 
operator =(const CplexEnv & other)58   CplexEnv& CplexEnv::operator=(const CplexEnv& other) {
59     _env = other._env;
60     _cnt = other._cnt;
61     ++(*_cnt);
62     return *this;
63   }
64 
~CplexEnv()65   CplexEnv::~CplexEnv() {
66     --(*_cnt);
67     if (*_cnt == 0) {
68       delete _cnt;
69       CPXcloseCPLEX(&_env);
70     }
71   }
72 
CplexBase()73   CplexBase::CplexBase() : LpBase() {
74     int status;
75     _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
76     messageLevel(MESSAGE_NOTHING);
77   }
78 
CplexBase(const CplexEnv & env)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 
CplexBase(const CplexBase & cplex)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 
~CplexBase()95   CplexBase::~CplexBase() {
96     CPXfreeprob(cplexEnv(),&_prob);
97   }
98 
_addCol()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 
_addRow()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 
_addRow(Value lb,ExprIterator b,ExprIterator e,Value ub)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 
_eraseCol(int i)149   void CplexBase::_eraseCol(int i) {
150     CPXdelcols(cplexEnv(), _prob, i, i);
151   }
152 
_eraseRow(int i)153   void CplexBase::_eraseRow(int i) {
154     CPXdelrows(cplexEnv(), _prob, i, i);
155   }
156 
_eraseColId(int i)157   void CplexBase::_eraseColId(int i) {
158     cols.eraseIndex(i);
159     cols.shiftIndices(i);
160   }
_eraseRowId(int i)161   void CplexBase::_eraseRowId(int i) {
162     rows.eraseIndex(i);
163     rows.shiftIndices(i);
164   }
165 
_getColName(int col,std::string & name) const166   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 
_setColName(int col,const std::string & name)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 
_colByName(const std::string & name) const189   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 
_getRowName(int row,std::string & name) const198   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 
_setRowName(int row,const std::string & name)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 
_rowByName(const std::string & name) const221   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 
_setRowCoeffs(int i,ExprIterator b,ExprIterator e)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 
_getRowCoeffs(int i,InsertIterator b) const247   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 
_setColCoeffs(int i,ExprIterator b,ExprIterator e)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 
_getColCoeffs(int i,InsertIterator b) const280   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 
_setCoeff(int row,int col,Value value)300   void CplexBase::_setCoeff(int row, int col, Value value) {
301     CPXchgcoef(cplexEnv(), _prob, row, col, value);
302   }
303 
_getCoeff(int row,int col) const304   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 
_setColLowerBound(int i,Value value)310   void CplexBase::_setColLowerBound(int i, Value value) {
311     const char s = 'L';
312     CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
313   }
314 
_getColLowerBound(int i) const315   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 
_setColUpperBound(int i,Value value)321   void CplexBase::_setColUpperBound(int i, Value value)
322   {
323     const char s = 'U';
324     CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
325   }
326 
_getColUpperBound(int i) const327   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 
_getRowLowerBound(int i) const333   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 
_getRowUpperBound(int i) const349   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
_set_row_bounds(int i,Value lb,Value ub)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 
_setRowLowerBound(int i,Value lb)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 
_setRowUpperBound(int i,Value ub)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 
_setObjCoeffs(ExprIterator b,ExprIterator e)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 
_getObjCoeffs(InsertIterator b) const421   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 
_setObjCoeff(int i,Value obj_coef)435   void CplexBase::_setObjCoeff(int i, Value obj_coef)
436   {
437     CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef);
438   }
439 
_getObjCoeff(int i) const440   CplexBase::Value CplexBase::_getObjCoeff(int i) const
441   {
442     Value x;
443     CPXgetobj(cplexEnv(), _prob, &x, i, i);
444     return x;
445   }
446 
_setSense(CplexBase::Sense sense)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 
_getSense() const458   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 
_clear()470   void CplexBase::_clear() {
471     CPXfreeprob(cplexEnv(),&_prob);
472     int status;
473     _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
474   }
475 
_messageLevel(MessageLevel level)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 
_applyMessageLevel()490   void CplexBase::_applyMessageLevel() {
491     CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND,
492                    _message_enabled ? CPX_ON : CPX_OFF);
493   }
494 
_write(std::string file,std::string format) const495   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 
CplexLp()508   CplexLp::CplexLp()
509     : LpBase(), LpSolver(), CplexBase() {}
510 
CplexLp(const CplexEnv & env)511   CplexLp::CplexLp(const CplexEnv& env)
512     : LpBase(), LpSolver(), CplexBase(env) {}
513 
CplexLp(const CplexLp & other)514   CplexLp::CplexLp(const CplexLp& other)
515     : LpBase(), LpSolver(), CplexBase(other) {}
516 
~CplexLp()517   CplexLp::~CplexLp() {}
518 
newSolver() const519   CplexLp* CplexLp::newSolver() const { return new CplexLp; }
cloneSolver() const520   CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); }
521 
_solverName() const522   const char* CplexLp::_solverName() const { return "CplexLp"; }
523 
_clear_temporals()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.
convertStatus(int status)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 
_solve()573   CplexLp::SolveExitStatus CplexLp::_solve() {
574     _clear_temporals();
575     _applyMessageLevel();
576     return convertStatus(CPXlpopt(cplexEnv(), _prob));
577   }
578 
solvePrimal()579   CplexLp::SolveExitStatus CplexLp::solvePrimal() {
580     _clear_temporals();
581     _applyMessageLevel();
582     return convertStatus(CPXprimopt(cplexEnv(), _prob));
583   }
584 
solveDual()585   CplexLp::SolveExitStatus CplexLp::solveDual() {
586     _clear_temporals();
587     _applyMessageLevel();
588     return convertStatus(CPXdualopt(cplexEnv(), _prob));
589   }
590 
solveBarrier()591   CplexLp::SolveExitStatus CplexLp::solveBarrier() {
592     _clear_temporals();
593     _applyMessageLevel();
594     return convertStatus(CPXbaropt(cplexEnv(), _prob));
595   }
596 
_getPrimal(int i) const597   CplexLp::Value CplexLp::_getPrimal(int i) const {
598     Value x;
599     CPXgetx(cplexEnv(), _prob, &x, i, i);
600     return x;
601   }
602 
_getDual(int i) const603   CplexLp::Value CplexLp::_getDual(int i) const {
604     Value y;
605     CPXgetpi(cplexEnv(), _prob, &y, i, i);
606     return y;
607   }
608 
_getPrimalValue() const609   CplexLp::Value CplexLp::_getPrimalValue() const {
610     Value objval;
611     CPXgetobjval(cplexEnv(), _prob, &objval);
612     return objval;
613   }
614 
_getColStatus(int i) const615   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 
_getRowStatus(int i) const635   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 
_getPrimalRay(int i) const657   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 
_getDualRay(int i) const665   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
statusSwitch(CPXENVptr cplexEnv (),int & stat)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
statusSwitch(CPXENVptr,int &)755   void statusSwitch(CPXENVptr,int&){}
756 #endif
757 
_getPrimalType() const758   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 
_getDualType() const839   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 
CplexMip()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 
CplexMip(const CplexEnv & env)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 
CplexMip(const CplexMip & other)889   CplexMip::CplexMip(const CplexMip& other)
890     : LpBase(), MipSolver(), CplexBase(other) {}
891 
~CplexMip()892   CplexMip::~CplexMip() {}
893 
newSolver() const894   CplexMip* CplexMip::newSolver() const { return new CplexMip; }
cloneSolver() const895   CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); }
896 
_solverName() const897   const char* CplexMip::_solverName() const { return "CplexMip"; }
898 
_setColType(int i,CplexMip::ColTypes col_type)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 
_getColType(int i) const918   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 
_solve()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 
_getType() const945   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 
_getSol(int i) const981   CplexMip::Value CplexMip::_getSol(int i) const {
982     Value x;
983     CPXgetmipx(cplexEnv(), _prob, &x, i, i);
984     return x;
985   }
986 
_getSolValue() const987   CplexMip::Value CplexMip::_getSolValue() const {
988     Value objval;
989     CPXgetmipobjval(cplexEnv(), _prob, &objval);
990     return objval;
991   }
992 
993 } //namespace lemon
994 
995