|
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-2008 |
|
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 <lemon/lp_cplex.h> |
|
22 |
|
23 extern "C" { |
|
24 #include <ilcplex/cplex.h> |
|
25 } |
|
26 |
|
27 |
|
28 ///\file |
|
29 ///\brief Implementation of the LEMON-CPLEX lp solver interface. |
|
30 namespace lemon { |
|
31 |
|
32 LpCplex::LpCplex() { |
|
33 // env = CPXopenCPLEXdevelop(&status); |
|
34 env = CPXopenCPLEX(&status); |
|
35 lp = CPXcreateprob(env, &status, "LP problem"); |
|
36 } |
|
37 |
|
38 LpCplex::LpCplex(const LpCplex& cplex) : LpSolverBase() { |
|
39 env = CPXopenCPLEX(&status); |
|
40 lp = CPXcloneprob(env, cplex.lp, &status); |
|
41 rows = cplex.rows; |
|
42 cols = cplex.cols; |
|
43 } |
|
44 |
|
45 LpCplex::~LpCplex() { |
|
46 CPXfreeprob(env,&lp); |
|
47 CPXcloseCPLEX(&env); |
|
48 } |
|
49 |
|
50 LpSolverBase* LpCplex::_newLp() |
|
51 { |
|
52 //The first approach opens a new environment |
|
53 return new LpCplex(); |
|
54 } |
|
55 |
|
56 LpSolverBase* LpCplex::_copyLp() { |
|
57 return new LpCplex(*this); |
|
58 } |
|
59 |
|
60 int LpCplex::_addCol() |
|
61 { |
|
62 int i = CPXgetnumcols(env, lp); |
|
63 Value lb[1],ub[1]; |
|
64 lb[0]=-INF; |
|
65 ub[0]=INF; |
|
66 status = CPXnewcols(env, lp, 1, NULL, lb, ub, NULL, NULL); |
|
67 return i; |
|
68 } |
|
69 |
|
70 |
|
71 int LpCplex::_addRow() |
|
72 { |
|
73 //We want a row that is not constrained |
|
74 char sense[1]; |
|
75 sense[0]='L';//<= constraint |
|
76 Value rhs[1]; |
|
77 rhs[0]=INF; |
|
78 int i = CPXgetnumrows(env, lp); |
|
79 status = CPXnewrows(env, lp, 1, rhs, sense, NULL, NULL); |
|
80 return i; |
|
81 } |
|
82 |
|
83 |
|
84 void LpCplex::_eraseCol(int i) { |
|
85 CPXdelcols(env, lp, i, i); |
|
86 } |
|
87 |
|
88 void LpCplex::_eraseRow(int i) { |
|
89 CPXdelrows(env, lp, i, i); |
|
90 } |
|
91 |
|
92 void LpCplex::_getColName(int col, std::string &name) const |
|
93 { |
|
94 ///\bug Untested |
|
95 int storespace; |
|
96 CPXgetcolname(env, lp, 0, 0, 0, &storespace, col, col); |
|
97 if (storespace == 0) { |
|
98 name.clear(); |
|
99 return; |
|
100 } |
|
101 |
|
102 storespace *= -1; |
|
103 std::vector<char> buf(storespace); |
|
104 char *names[1]; |
|
105 int dontcare; |
|
106 ///\bug return code unchecked for error |
|
107 CPXgetcolname(env, lp, names, &*buf.begin(), storespace, |
|
108 &dontcare, col, col); |
|
109 name = names[0]; |
|
110 } |
|
111 |
|
112 void LpCplex::_setColName(int col, const std::string &name) |
|
113 { |
|
114 ///\bug Untested |
|
115 char *names[1]; |
|
116 names[0] = const_cast<char*>(name.c_str()); |
|
117 ///\bug return code unchecked for error |
|
118 CPXchgcolname(env, lp, 1, &col, names); |
|
119 } |
|
120 |
|
121 int LpCplex::_colByName(const std::string& name) const |
|
122 { |
|
123 int index; |
|
124 if (CPXgetcolindex(env, lp, |
|
125 const_cast<char*>(name.c_str()), &index) == 0) { |
|
126 return index; |
|
127 } |
|
128 return -1; |
|
129 } |
|
130 |
|
131 ///\warning Data at index 0 is ignored in the arrays. |
|
132 void LpCplex::_setRowCoeffs(int i, ConstRowIterator b, ConstRowIterator e) |
|
133 { |
|
134 std::vector<int> indices; |
|
135 std::vector<int> rowlist; |
|
136 std::vector<Value> values; |
|
137 |
|
138 for(ConstRowIterator it=b; it!=e; ++it) { |
|
139 indices.push_back(it->first); |
|
140 values.push_back(it->second); |
|
141 rowlist.push_back(i); |
|
142 } |
|
143 |
|
144 status = CPXchgcoeflist(env, lp, values.size(), |
|
145 &rowlist[0], &indices[0], &values[0]); |
|
146 } |
|
147 |
|
148 void LpCplex::_getRowCoeffs(int i, RowIterator b) const { |
|
149 int tmp1, tmp2, tmp3, length; |
|
150 CPXgetrows(env, lp, &tmp1, &tmp2, 0, 0, 0, &length, i, i); |
|
151 |
|
152 length = -length; |
|
153 std::vector<int> indices(length); |
|
154 std::vector<double> values(length); |
|
155 |
|
156 CPXgetrows(env, lp, &tmp1, &tmp2, &indices[0], &values[0], |
|
157 length, &tmp3, i, i); |
|
158 |
|
159 for (int i = 0; i < length; ++i) { |
|
160 *b = std::make_pair(indices[i], values[i]); |
|
161 ++b; |
|
162 } |
|
163 |
|
164 /// \todo implement |
|
165 } |
|
166 |
|
167 void LpCplex::_setColCoeffs(int i, ConstColIterator b, ConstColIterator e) |
|
168 { |
|
169 std::vector<int> indices; |
|
170 std::vector<int> collist; |
|
171 std::vector<Value> values; |
|
172 |
|
173 for(ConstColIterator it=b; it!=e; ++it) { |
|
174 indices.push_back(it->first); |
|
175 values.push_back(it->second); |
|
176 collist.push_back(i); |
|
177 } |
|
178 |
|
179 status = CPXchgcoeflist(env, lp, values.size(), |
|
180 &indices[0], &collist[0], &values[0]); |
|
181 } |
|
182 |
|
183 void LpCplex::_getColCoeffs(int i, ColIterator b) const { |
|
184 |
|
185 int tmp1, tmp2, tmp3, length; |
|
186 CPXgetcols(env, lp, &tmp1, &tmp2, 0, 0, 0, &length, i, i); |
|
187 |
|
188 length = -length; |
|
189 std::vector<int> indices(length); |
|
190 std::vector<double> values(length); |
|
191 |
|
192 CPXgetcols(env, lp, &tmp1, &tmp2, &indices[0], &values[0], |
|
193 length, &tmp3, i, i); |
|
194 |
|
195 for (int i = 0; i < length; ++i) { |
|
196 *b = std::make_pair(indices[i], values[i]); |
|
197 ++b; |
|
198 } |
|
199 |
|
200 } |
|
201 |
|
202 void LpCplex::_setCoeff(int row, int col, Value value) |
|
203 { |
|
204 CPXchgcoef(env, lp, row, col, value); |
|
205 } |
|
206 |
|
207 LpCplex::Value LpCplex::_getCoeff(int row, int col) const |
|
208 { |
|
209 LpCplex::Value value; |
|
210 CPXgetcoef(env, lp, row, col, &value); |
|
211 return value; |
|
212 } |
|
213 |
|
214 void LpCplex::_setColLowerBound(int i, Value value) |
|
215 { |
|
216 int indices[1]; |
|
217 indices[0]=i; |
|
218 char lu[1]; |
|
219 lu[0]='L'; |
|
220 Value bd[1]; |
|
221 bd[0]=value; |
|
222 status = CPXchgbds(env, lp, 1, indices, lu, bd); |
|
223 |
|
224 } |
|
225 |
|
226 LpCplex::Value LpCplex::_getColLowerBound(int i) const |
|
227 { |
|
228 LpCplex::Value x; |
|
229 CPXgetlb (env, lp, &x, i, i); |
|
230 if (x <= -CPX_INFBOUND) x = -INF; |
|
231 return x; |
|
232 } |
|
233 |
|
234 void LpCplex::_setColUpperBound(int i, Value value) |
|
235 { |
|
236 int indices[1]; |
|
237 indices[0]=i; |
|
238 char lu[1]; |
|
239 lu[0]='U'; |
|
240 Value bd[1]; |
|
241 bd[0]=value; |
|
242 status = CPXchgbds(env, lp, 1, indices, lu, bd); |
|
243 } |
|
244 |
|
245 LpCplex::Value LpCplex::_getColUpperBound(int i) const |
|
246 { |
|
247 LpCplex::Value x; |
|
248 CPXgetub (env, lp, &x, i, i); |
|
249 if (x >= CPX_INFBOUND) x = INF; |
|
250 return x; |
|
251 } |
|
252 |
|
253 //This will be easier to implement |
|
254 void LpCplex::_setRowBounds(int i, Value lb, Value ub) |
|
255 { |
|
256 //Bad parameter |
|
257 if (lb==INF || ub==-INF) { |
|
258 //FIXME error |
|
259 } |
|
260 |
|
261 int cnt=1; |
|
262 int indices[1]; |
|
263 indices[0]=i; |
|
264 char sense[1]; |
|
265 |
|
266 if (lb==-INF){ |
|
267 sense[0]='L'; |
|
268 CPXchgsense(env, lp, cnt, indices, sense); |
|
269 CPXchgcoef(env, lp, i, -1, ub); |
|
270 |
|
271 } |
|
272 else{ |
|
273 if (ub==INF){ |
|
274 sense[0]='G'; |
|
275 CPXchgsense(env, lp, cnt, indices, sense); |
|
276 CPXchgcoef(env, lp, i, -1, lb); |
|
277 } |
|
278 else{ |
|
279 if (lb == ub){ |
|
280 sense[0]='E'; |
|
281 CPXchgsense(env, lp, cnt, indices, sense); |
|
282 CPXchgcoef(env, lp, i, -1, lb); |
|
283 } |
|
284 else{ |
|
285 sense[0]='R'; |
|
286 CPXchgsense(env, lp, cnt, indices, sense); |
|
287 CPXchgcoef(env, lp, i, -1, lb); |
|
288 CPXchgcoef(env, lp, i, -2, ub-lb); |
|
289 } |
|
290 } |
|
291 } |
|
292 } |
|
293 |
|
294 // void LpCplex::_setRowLowerBound(int i, Value value) |
|
295 // { |
|
296 // //Not implemented, obsolete |
|
297 // } |
|
298 |
|
299 // void LpCplex::_setRowUpperBound(int i, Value value) |
|
300 // { |
|
301 // //Not implemented, obsolete |
|
302 // // //TODO Ezt kell meg megirni |
|
303 // // //type of the problem |
|
304 // // char sense[1]; |
|
305 // // status = CPXgetsense(env, lp, sense, i, i); |
|
306 // // Value rhs[1]; |
|
307 // // status = CPXgetrhs(env, lp, rhs, i, i); |
|
308 |
|
309 // // switch (sense[0]) { |
|
310 // // case 'L'://<= constraint |
|
311 // // break; |
|
312 // // case 'E'://= constraint |
|
313 // // break; |
|
314 // // case 'G'://>= constraint |
|
315 // // break; |
|
316 // // case 'R'://ranged constraint |
|
317 // // break; |
|
318 // // default: ; |
|
319 // // //FIXME error |
|
320 // // } |
|
321 |
|
322 // // status = CPXchgcoef(env, lp, i, -2, value_rng); |
|
323 // } |
|
324 |
|
325 void LpCplex::_getRowBounds(int i, Value &lb, Value &ub) const |
|
326 { |
|
327 char sense; |
|
328 CPXgetsense(env, lp, &sense,i,i); |
|
329 lb=-INF; |
|
330 ub=INF; |
|
331 switch (sense) |
|
332 { |
|
333 case 'L': |
|
334 CPXgetcoef(env, lp, i, -1, &ub); |
|
335 break; |
|
336 case 'G': |
|
337 CPXgetcoef(env, lp, i, -1, &lb); |
|
338 break; |
|
339 case 'E': |
|
340 CPXgetcoef(env, lp, i, -1, &lb); |
|
341 ub=lb; |
|
342 break; |
|
343 case 'R': |
|
344 CPXgetcoef(env, lp, i, -1, &lb); |
|
345 Value x; |
|
346 CPXgetcoef(env, lp, i, -2, &x); |
|
347 ub=lb+x; |
|
348 break; |
|
349 } |
|
350 } |
|
351 |
|
352 void LpCplex::_setObjCoeff(int i, Value obj_coef) |
|
353 { |
|
354 CPXchgcoef(env, lp, -1, i, obj_coef); |
|
355 } |
|
356 |
|
357 LpCplex::Value LpCplex::_getObjCoeff(int i) const |
|
358 { |
|
359 Value x; |
|
360 CPXgetcoef(env, lp, -1, i, &x); |
|
361 return x; |
|
362 } |
|
363 |
|
364 void LpCplex::_clearObj() |
|
365 { |
|
366 for (int i=0;i< CPXgetnumcols(env, lp);++i){ |
|
367 CPXchgcoef(env, lp, -1, i, 0); |
|
368 } |
|
369 |
|
370 } |
|
371 // The routine returns zero unless an error occurred during the |
|
372 // optimization. Examples of errors include exhausting available |
|
373 // memory (CPXERR_NO_MEMORY) or encountering invalid data in the |
|
374 // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a |
|
375 // user-specified CPLEX limit, or proving the model infeasible or |
|
376 // unbounded, are not considered errors. Note that a zero return |
|
377 // value does not necessarily mean that a solution exists. Use query |
|
378 // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain |
|
379 // further information about the status of the optimization. |
|
380 LpCplex::SolveExitStatus LpCplex::_solve() |
|
381 { |
|
382 //CPX_PARAM_LPMETHOD |
|
383 status = CPXlpopt(env, lp); |
|
384 //status = CPXprimopt(env, lp); |
|
385 #if CPX_VERSION >= 800 |
|
386 if (status) |
|
387 { |
|
388 return UNSOLVED; |
|
389 } |
|
390 else |
|
391 { |
|
392 switch (CPXgetstat(env, lp)) |
|
393 { |
|
394 case CPX_STAT_OPTIMAL: |
|
395 case CPX_STAT_INFEASIBLE: |
|
396 case CPX_STAT_UNBOUNDED: |
|
397 return SOLVED; |
|
398 default: |
|
399 return UNSOLVED; |
|
400 } |
|
401 } |
|
402 #else |
|
403 if (status == 0){ |
|
404 //We want to exclude some cases |
|
405 switch (CPXgetstat(env, lp)){ |
|
406 case CPX_OBJ_LIM: |
|
407 case CPX_IT_LIM_FEAS: |
|
408 case CPX_IT_LIM_INFEAS: |
|
409 case CPX_TIME_LIM_FEAS: |
|
410 case CPX_TIME_LIM_INFEAS: |
|
411 return UNSOLVED; |
|
412 default: |
|
413 return SOLVED; |
|
414 } |
|
415 } |
|
416 else{ |
|
417 return UNSOLVED; |
|
418 } |
|
419 #endif |
|
420 } |
|
421 |
|
422 LpCplex::Value LpCplex::_getPrimal(int i) const |
|
423 { |
|
424 Value x; |
|
425 CPXgetx(env, lp, &x, i, i); |
|
426 return x; |
|
427 } |
|
428 |
|
429 LpCplex::Value LpCplex::_getDual(int i) const |
|
430 { |
|
431 Value y; |
|
432 CPXgetpi(env, lp, &y, i, i); |
|
433 return y; |
|
434 } |
|
435 |
|
436 LpCplex::Value LpCplex::_getPrimalValue() const |
|
437 { |
|
438 Value objval; |
|
439 //method = CPXgetmethod (env, lp); |
|
440 //printf("CPXgetprobtype %d \n",CPXgetprobtype(env,lp)); |
|
441 CPXgetobjval(env, lp, &objval); |
|
442 //printf("Objective value: %g \n",objval); |
|
443 return objval; |
|
444 } |
|
445 bool LpCplex::_isBasicCol(int i) const |
|
446 { |
|
447 std::vector<int> cstat(CPXgetnumcols(env, lp)); |
|
448 CPXgetbase(env, lp, &*cstat.begin(), NULL); |
|
449 return (cstat[i]==CPX_BASIC); |
|
450 } |
|
451 |
|
452 //7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!) |
|
453 // This table lists the statuses, returned by the CPXgetstat() |
|
454 // routine, for solutions to LP problems or mixed integer problems. If |
|
455 // no solution exists, the return value is zero. |
|
456 |
|
457 // For Simplex, Barrier |
|
458 // 1 CPX_OPTIMAL |
|
459 // Optimal solution found |
|
460 // 2 CPX_INFEASIBLE |
|
461 // Problem infeasible |
|
462 // 3 CPX_UNBOUNDED |
|
463 // Problem unbounded |
|
464 // 4 CPX_OBJ_LIM |
|
465 // Objective limit exceeded in Phase II |
|
466 // 5 CPX_IT_LIM_FEAS |
|
467 // Iteration limit exceeded in Phase II |
|
468 // 6 CPX_IT_LIM_INFEAS |
|
469 // Iteration limit exceeded in Phase I |
|
470 // 7 CPX_TIME_LIM_FEAS |
|
471 // Time limit exceeded in Phase II |
|
472 // 8 CPX_TIME_LIM_INFEAS |
|
473 // Time limit exceeded in Phase I |
|
474 // 9 CPX_NUM_BEST_FEAS |
|
475 // Problem non-optimal, singularities in Phase II |
|
476 // 10 CPX_NUM_BEST_INFEAS |
|
477 // Problem non-optimal, singularities in Phase I |
|
478 // 11 CPX_OPTIMAL_INFEAS |
|
479 // Optimal solution found, unscaled infeasibilities |
|
480 // 12 CPX_ABORT_FEAS |
|
481 // Aborted in Phase II |
|
482 // 13 CPX_ABORT_INFEAS |
|
483 // Aborted in Phase I |
|
484 // 14 CPX_ABORT_DUAL_INFEAS |
|
485 // Aborted in barrier, dual infeasible |
|
486 // 15 CPX_ABORT_PRIM_INFEAS |
|
487 // Aborted in barrier, primal infeasible |
|
488 // 16 CPX_ABORT_PRIM_DUAL_INFEAS |
|
489 // Aborted in barrier, primal and dual infeasible |
|
490 // 17 CPX_ABORT_PRIM_DUAL_FEAS |
|
491 // Aborted in barrier, primal and dual feasible |
|
492 // 18 CPX_ABORT_CROSSOVER |
|
493 // Aborted in crossover |
|
494 // 19 CPX_INForUNBD |
|
495 // Infeasible or unbounded |
|
496 // 20 CPX_PIVOT |
|
497 // User pivot used |
|
498 // |
|
499 // Ezeket hova tegyem: |
|
500 // ??case CPX_ABORT_DUAL_INFEAS |
|
501 // ??case CPX_ABORT_CROSSOVER |
|
502 // ??case CPX_INForUNBD |
|
503 // ??case CPX_PIVOT |
|
504 |
|
505 //Some more interesting stuff: |
|
506 |
|
507 // CPX_PARAM_LPMETHOD 1062 int LPMETHOD |
|
508 // 0 Automatic |
|
509 // 1 Primal Simplex |
|
510 // 2 Dual Simplex |
|
511 // 3 Network Simplex |
|
512 // 4 Standard Barrier |
|
513 // Default: 0 |
|
514 // Description: Method for linear optimization. |
|
515 // Determines which algorithm is used when CPXlpopt() (or "optimize" |
|
516 // in the Interactive Optimizer) is called. Currently the behavior of |
|
517 // the "Automatic" setting is that CPLEX simply invokes the dual |
|
518 // simplex method, but this capability may be expanded in the future |
|
519 // so that CPLEX chooses the method based on problem characteristics |
|
520 #if CPX_VERSION < 900 |
|
521 void statusSwitch(CPXENVptr env,int& stat){ |
|
522 int lpmethod; |
|
523 CPXgetintparam (env,CPX_PARAM_LPMETHOD,&lpmethod); |
|
524 if (lpmethod==2){ |
|
525 if (stat==CPX_UNBOUNDED){ |
|
526 stat=CPX_INFEASIBLE; |
|
527 } |
|
528 else{ |
|
529 if (stat==CPX_INFEASIBLE) |
|
530 stat=CPX_UNBOUNDED; |
|
531 } |
|
532 } |
|
533 } |
|
534 #else |
|
535 void statusSwitch(CPXENVptr,int&){} |
|
536 #endif |
|
537 |
|
538 LpCplex::SolutionStatus LpCplex::_getPrimalStatus() const |
|
539 { |
|
540 //Unboundedness not treated well: the following is from cplex 9.0 doc |
|
541 // About Unboundedness |
|
542 |
|
543 // The treatment of models that are unbounded involves a few |
|
544 // subtleties. Specifically, a declaration of unboundedness means that |
|
545 // ILOG CPLEX has determined that the model has an unbounded |
|
546 // ray. Given any feasible solution x with objective z, a multiple of |
|
547 // the unbounded ray can be added to x to give a feasible solution |
|
548 // with objective z-1 (or z+1 for maximization models). Thus, if a |
|
549 // feasible solution exists, then the optimal objective is |
|
550 // unbounded. Note that ILOG CPLEX has not necessarily concluded that |
|
551 // a feasible solution exists. Users can call the routine CPXsolninfo |
|
552 // to determine whether ILOG CPLEX has also concluded that the model |
|
553 // has a feasible solution. |
|
554 |
|
555 int stat = CPXgetstat(env, lp); |
|
556 #if CPX_VERSION >= 800 |
|
557 switch (stat) |
|
558 { |
|
559 case CPX_STAT_OPTIMAL: |
|
560 return OPTIMAL; |
|
561 case CPX_STAT_UNBOUNDED: |
|
562 return INFINITE; |
|
563 case CPX_STAT_INFEASIBLE: |
|
564 return INFEASIBLE; |
|
565 default: |
|
566 return UNDEFINED; |
|
567 } |
|
568 #else |
|
569 statusSwitch(env,stat); |
|
570 //CPXgetstat(env, lp); |
|
571 //printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL); |
|
572 switch (stat) { |
|
573 case 0: |
|
574 return UNDEFINED; //Undefined |
|
575 case CPX_OPTIMAL://Optimal |
|
576 return OPTIMAL; |
|
577 case CPX_UNBOUNDED://Unbounded |
|
578 return INFEASIBLE;//In case of dual simplex |
|
579 //return INFINITE; |
|
580 case CPX_INFEASIBLE://Infeasible |
|
581 // case CPX_IT_LIM_INFEAS: |
|
582 // case CPX_TIME_LIM_INFEAS: |
|
583 // case CPX_NUM_BEST_INFEAS: |
|
584 // case CPX_OPTIMAL_INFEAS: |
|
585 // case CPX_ABORT_INFEAS: |
|
586 // case CPX_ABORT_PRIM_INFEAS: |
|
587 // case CPX_ABORT_PRIM_DUAL_INFEAS: |
|
588 return INFINITE;//In case of dual simplex |
|
589 //return INFEASIBLE; |
|
590 // case CPX_OBJ_LIM: |
|
591 // case CPX_IT_LIM_FEAS: |
|
592 // case CPX_TIME_LIM_FEAS: |
|
593 // case CPX_NUM_BEST_FEAS: |
|
594 // case CPX_ABORT_FEAS: |
|
595 // case CPX_ABORT_PRIM_DUAL_FEAS: |
|
596 // return FEASIBLE; |
|
597 default: |
|
598 return UNDEFINED; //Everything else comes here |
|
599 //FIXME error |
|
600 } |
|
601 #endif |
|
602 } |
|
603 |
|
604 //9.0-as cplex verzio statusai |
|
605 // CPX_STAT_ABORT_DUAL_OBJ_LIM |
|
606 // CPX_STAT_ABORT_IT_LIM |
|
607 // CPX_STAT_ABORT_OBJ_LIM |
|
608 // CPX_STAT_ABORT_PRIM_OBJ_LIM |
|
609 // CPX_STAT_ABORT_TIME_LIM |
|
610 // CPX_STAT_ABORT_USER |
|
611 // CPX_STAT_FEASIBLE_RELAXED |
|
612 // CPX_STAT_INFEASIBLE |
|
613 // CPX_STAT_INForUNBD |
|
614 // CPX_STAT_NUM_BEST |
|
615 // CPX_STAT_OPTIMAL |
|
616 // CPX_STAT_OPTIMAL_FACE_UNBOUNDED |
|
617 // CPX_STAT_OPTIMAL_INFEAS |
|
618 // CPX_STAT_OPTIMAL_RELAXED |
|
619 // CPX_STAT_UNBOUNDED |
|
620 |
|
621 LpCplex::SolutionStatus LpCplex::_getDualStatus() const |
|
622 { |
|
623 int stat = CPXgetstat(env, lp); |
|
624 #if CPX_VERSION >= 800 |
|
625 switch (stat) |
|
626 { |
|
627 case CPX_STAT_OPTIMAL: |
|
628 return OPTIMAL; |
|
629 case CPX_STAT_UNBOUNDED: |
|
630 return INFEASIBLE; |
|
631 default: |
|
632 return UNDEFINED; |
|
633 } |
|
634 #else |
|
635 statusSwitch(env,stat); |
|
636 switch (stat) { |
|
637 case 0: |
|
638 return UNDEFINED; //Undefined |
|
639 case CPX_OPTIMAL://Optimal |
|
640 return OPTIMAL; |
|
641 case CPX_UNBOUNDED: |
|
642 return INFEASIBLE; |
|
643 default: |
|
644 return UNDEFINED; //Everything else comes here |
|
645 //FIXME error |
|
646 } |
|
647 #endif |
|
648 } |
|
649 |
|
650 LpCplex::ProblemTypes LpCplex::_getProblemType() const |
|
651 { |
|
652 int stat = CPXgetstat(env, lp); |
|
653 #if CPX_VERSION >= 800 |
|
654 switch (stat) |
|
655 { |
|
656 case CPX_STAT_OPTIMAL: |
|
657 return PRIMAL_DUAL_FEASIBLE; |
|
658 case CPX_STAT_UNBOUNDED: |
|
659 return PRIMAL_FEASIBLE_DUAL_INFEASIBLE; |
|
660 default: |
|
661 return UNKNOWN; |
|
662 } |
|
663 #else |
|
664 switch (stat) { |
|
665 case CPX_OPTIMAL://Optimal |
|
666 return PRIMAL_DUAL_FEASIBLE; |
|
667 case CPX_UNBOUNDED: |
|
668 return PRIMAL_FEASIBLE_DUAL_INFEASIBLE; |
|
669 // return PRIMAL_INFEASIBLE_DUAL_FEASIBLE; |
|
670 // return PRIMAL_DUAL_INFEASIBLE; |
|
671 |
|
672 //Seems to be that this is all we can say for sure |
|
673 default: |
|
674 //In all other cases |
|
675 return UNKNOWN; |
|
676 //FIXME error |
|
677 } |
|
678 #endif |
|
679 } |
|
680 |
|
681 void LpCplex::_setMax() |
|
682 { |
|
683 CPXchgobjsen(env, lp, CPX_MAX); |
|
684 } |
|
685 void LpCplex::_setMin() |
|
686 { |
|
687 CPXchgobjsen(env, lp, CPX_MIN); |
|
688 } |
|
689 |
|
690 bool LpCplex::_isMax() const |
|
691 { |
|
692 if (CPXgetobjsen(env, lp)==CPX_MAX) |
|
693 return true; |
|
694 else |
|
695 return false; |
|
696 } |
|
697 |
|
698 } //namespace lemon |
|
699 |