COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/lp_cplex.cc @ 2363:2aabce558574

Last change on this file since 2363:2aabce558574 was 2363:2aabce558574, checked in by Balazs Dezso, 17 years ago

Changes on the LP interface

_FixId => LpId?

  • handling of not common ids soplex

LpGlpk? row and col erase bug fix

  • calling lpx_std_basis before simplex

LpSoplex?

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