lemon/soplex.cc
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 982 bb70ad62c95f
parent 587 9db62975c32b
child 793 e4554cd6b2bf
child 1081 f1398882a928
permissions -rw-r--r--
Fix critical bug in preflow (#372)

The wrong transition between the bound decrease and highest active
heuristics caused the bug. The last node chosen in bound decrease mode
is used in the first iteration in highest active mode.
     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 <lemon/soplex.h>
    21 
    22 #include <soplex.h>
    23 #include <spxout.h>
    24 
    25 
    26 ///\file
    27 ///\brief Implementation of the LEMON-SOPLEX lp solver interface.
    28 namespace lemon {
    29 
    30   SoplexLp::SoplexLp() {
    31     soplex = new soplex::SoPlex;
    32     messageLevel(MESSAGE_NOTHING);
    33   }
    34 
    35   SoplexLp::~SoplexLp() {
    36     delete soplex;
    37   }
    38 
    39   SoplexLp::SoplexLp(const SoplexLp& lp) {
    40     rows = lp.rows;
    41     cols = lp.cols;
    42 
    43     soplex = new soplex::SoPlex;
    44     (*static_cast<soplex::SPxLP*>(soplex)) = *(lp.soplex);
    45 
    46     _col_names = lp._col_names;
    47     _col_names_ref = lp._col_names_ref;
    48 
    49     _row_names = lp._row_names;
    50     _row_names_ref = lp._row_names_ref;
    51 
    52     messageLevel(MESSAGE_NOTHING);
    53   }
    54 
    55   void SoplexLp::_clear_temporals() {
    56     _primal_values.clear();
    57     _dual_values.clear();
    58   }
    59 
    60   SoplexLp* SoplexLp::newSolver() const {
    61     SoplexLp* newlp = new SoplexLp();
    62     return newlp;
    63   }
    64 
    65   SoplexLp* SoplexLp::cloneSolver() const {
    66     SoplexLp* newlp = new SoplexLp(*this);
    67     return newlp;
    68   }
    69 
    70   const char* SoplexLp::_solverName() const { return "SoplexLp"; }
    71 
    72   int SoplexLp::_addCol() {
    73     soplex::LPCol c;
    74     c.setLower(-soplex::infinity);
    75     c.setUpper(soplex::infinity);
    76     soplex->addCol(c);
    77 
    78     _col_names.push_back(std::string());
    79 
    80     return soplex->nCols() - 1;
    81   }
    82 
    83   int SoplexLp::_addRow() {
    84     soplex::LPRow r;
    85     r.setLhs(-soplex::infinity);
    86     r.setRhs(soplex::infinity);
    87     soplex->addRow(r);
    88 
    89     _row_names.push_back(std::string());
    90 
    91     return soplex->nRows() - 1;
    92   }
    93 
    94 
    95   void SoplexLp::_eraseCol(int i) {
    96     soplex->removeCol(i);
    97     _col_names_ref.erase(_col_names[i]);
    98     _col_names[i] = _col_names.back();
    99     _col_names_ref[_col_names.back()] = i;
   100     _col_names.pop_back();
   101   }
   102 
   103   void SoplexLp::_eraseRow(int i) {
   104     soplex->removeRow(i);
   105     _row_names_ref.erase(_row_names[i]);
   106     _row_names[i] = _row_names.back();
   107     _row_names_ref[_row_names.back()] = i;
   108     _row_names.pop_back();
   109   }
   110 
   111   void SoplexLp::_eraseColId(int i) {
   112     cols.eraseIndex(i);
   113     cols.relocateIndex(i, cols.maxIndex());
   114   }
   115   void SoplexLp::_eraseRowId(int i) {
   116     rows.eraseIndex(i);
   117     rows.relocateIndex(i, rows.maxIndex());
   118   }
   119 
   120   void SoplexLp::_getColName(int c, std::string &name) const {
   121     name = _col_names[c];
   122   }
   123 
   124   void SoplexLp::_setColName(int c, const std::string &name) {
   125     _col_names_ref.erase(_col_names[c]);
   126     _col_names[c] = name;
   127     if (!name.empty()) {
   128       _col_names_ref.insert(std::make_pair(name, c));
   129     }
   130   }
   131 
   132   int SoplexLp::_colByName(const std::string& name) const {
   133     std::map<std::string, int>::const_iterator it =
   134       _col_names_ref.find(name);
   135     if (it != _col_names_ref.end()) {
   136       return it->second;
   137     } else {
   138       return -1;
   139     }
   140   }
   141 
   142   void SoplexLp::_getRowName(int r, std::string &name) const {
   143     name = _row_names[r];
   144   }
   145 
   146   void SoplexLp::_setRowName(int r, const std::string &name) {
   147     _row_names_ref.erase(_row_names[r]);
   148     _row_names[r] = name;
   149     if (!name.empty()) {
   150       _row_names_ref.insert(std::make_pair(name, r));
   151     }
   152   }
   153 
   154   int SoplexLp::_rowByName(const std::string& name) const {
   155     std::map<std::string, int>::const_iterator it =
   156       _row_names_ref.find(name);
   157     if (it != _row_names_ref.end()) {
   158       return it->second;
   159     } else {
   160       return -1;
   161     }
   162   }
   163 
   164 
   165   void SoplexLp::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
   166     for (int j = 0; j < soplex->nCols(); ++j) {
   167       soplex->changeElement(i, j, 0.0);
   168     }
   169     for(ExprIterator it = b; it != e; ++it) {
   170       soplex->changeElement(i, it->first, it->second);
   171     }
   172   }
   173 
   174   void SoplexLp::_getRowCoeffs(int i, InsertIterator b) const {
   175     const soplex::SVector& vec = soplex->rowVector(i);
   176     for (int k = 0; k < vec.size(); ++k) {
   177       *b = std::make_pair(vec.index(k), vec.value(k));
   178       ++b;
   179     }
   180   }
   181 
   182   void SoplexLp::_setColCoeffs(int j, ExprIterator b, ExprIterator e) {
   183     for (int i = 0; i < soplex->nRows(); ++i) {
   184       soplex->changeElement(i, j, 0.0);
   185     }
   186     for(ExprIterator it = b; it != e; ++it) {
   187       soplex->changeElement(it->first, j, it->second);
   188     }
   189   }
   190 
   191   void SoplexLp::_getColCoeffs(int i, InsertIterator b) const {
   192     const soplex::SVector& vec = soplex->colVector(i);
   193     for (int k = 0; k < vec.size(); ++k) {
   194       *b = std::make_pair(vec.index(k), vec.value(k));
   195       ++b;
   196     }
   197   }
   198 
   199   void SoplexLp::_setCoeff(int i, int j, Value value) {
   200     soplex->changeElement(i, j, value);
   201   }
   202 
   203   SoplexLp::Value SoplexLp::_getCoeff(int i, int j) const {
   204     return soplex->rowVector(i)[j];
   205   }
   206 
   207   void SoplexLp::_setColLowerBound(int i, Value value) {
   208     LEMON_ASSERT(value != INF, "Invalid bound");
   209     soplex->changeLower(i, value != -INF ? value : -soplex::infinity);
   210   }
   211 
   212   SoplexLp::Value SoplexLp::_getColLowerBound(int i) const {
   213     double value = soplex->lower(i);
   214     return value != -soplex::infinity ? value : -INF;
   215   }
   216 
   217   void SoplexLp::_setColUpperBound(int i, Value value) {
   218     LEMON_ASSERT(value != -INF, "Invalid bound");
   219     soplex->changeUpper(i, value != INF ? value : soplex::infinity);
   220   }
   221 
   222   SoplexLp::Value SoplexLp::_getColUpperBound(int i) const {
   223     double value = soplex->upper(i);
   224     return value != soplex::infinity ? value : INF;
   225   }
   226 
   227   void SoplexLp::_setRowLowerBound(int i, Value lb) {
   228     LEMON_ASSERT(lb != INF, "Invalid bound");
   229     soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, soplex->rhs(i));
   230   }
   231 
   232   SoplexLp::Value SoplexLp::_getRowLowerBound(int i) const {
   233     double res = soplex->lhs(i);
   234     return res == -soplex::infinity ? -INF : res;
   235   }
   236 
   237   void SoplexLp::_setRowUpperBound(int i, Value ub) {
   238     LEMON_ASSERT(ub != -INF, "Invalid bound");
   239     soplex->changeRange(i, soplex->lhs(i), ub != INF ? ub : soplex::infinity);
   240   }
   241 
   242   SoplexLp::Value SoplexLp::_getRowUpperBound(int i) const {
   243     double res = soplex->rhs(i);
   244     return res == soplex::infinity ? INF : res;
   245   }
   246 
   247   void SoplexLp::_setObjCoeffs(ExprIterator b, ExprIterator e) {
   248     for (int j = 0; j < soplex->nCols(); ++j) {
   249       soplex->changeObj(j, 0.0);
   250     }
   251     for (ExprIterator it = b; it != e; ++it) {
   252       soplex->changeObj(it->first, it->second);
   253     }
   254   }
   255 
   256   void SoplexLp::_getObjCoeffs(InsertIterator b) const {
   257     for (int j = 0; j < soplex->nCols(); ++j) {
   258       Value coef = soplex->obj(j);
   259       if (coef != 0.0) {
   260         *b = std::make_pair(j, coef);
   261         ++b;
   262       }
   263     }
   264   }
   265 
   266   void SoplexLp::_setObjCoeff(int i, Value obj_coef) {
   267     soplex->changeObj(i, obj_coef);
   268   }
   269 
   270   SoplexLp::Value SoplexLp::_getObjCoeff(int i) const {
   271     return soplex->obj(i);
   272   }
   273 
   274   SoplexLp::SolveExitStatus SoplexLp::_solve() {
   275 
   276     _clear_temporals();
   277     
   278     _applyMessageLevel();
   279 
   280     soplex::SPxSolver::Status status = soplex->solve();
   281 
   282     switch (status) {
   283     case soplex::SPxSolver::OPTIMAL:
   284     case soplex::SPxSolver::INFEASIBLE:
   285     case soplex::SPxSolver::UNBOUNDED:
   286       return SOLVED;
   287     default:
   288       return UNSOLVED;
   289     }
   290   }
   291 
   292   SoplexLp::Value SoplexLp::_getPrimal(int i) const {
   293     if (_primal_values.empty()) {
   294       _primal_values.resize(soplex->nCols());
   295       soplex::Vector pv(_primal_values.size(), &_primal_values.front());
   296       soplex->getPrimal(pv);
   297     }
   298     return _primal_values[i];
   299   }
   300 
   301   SoplexLp::Value SoplexLp::_getDual(int i) const {
   302     if (_dual_values.empty()) {
   303       _dual_values.resize(soplex->nRows());
   304       soplex::Vector dv(_dual_values.size(), &_dual_values.front());
   305       soplex->getDual(dv);
   306     }
   307     return _dual_values[i];
   308   }
   309 
   310   SoplexLp::Value SoplexLp::_getPrimalValue() const {
   311     return soplex->objValue();
   312   }
   313 
   314   SoplexLp::VarStatus SoplexLp::_getColStatus(int i) const {
   315     switch (soplex->getBasisColStatus(i)) {
   316     case soplex::SPxSolver::BASIC:
   317       return BASIC;
   318     case soplex::SPxSolver::ON_UPPER:
   319       return UPPER;
   320     case soplex::SPxSolver::ON_LOWER:
   321       return LOWER;
   322     case soplex::SPxSolver::FIXED:
   323       return FIXED;
   324     case soplex::SPxSolver::ZERO:
   325       return FREE;
   326     default:
   327       LEMON_ASSERT(false, "Wrong column status");
   328       return VarStatus();
   329     }
   330   }
   331 
   332   SoplexLp::VarStatus SoplexLp::_getRowStatus(int i) const {
   333     switch (soplex->getBasisRowStatus(i)) {
   334     case soplex::SPxSolver::BASIC:
   335       return BASIC;
   336     case soplex::SPxSolver::ON_UPPER:
   337       return UPPER;
   338     case soplex::SPxSolver::ON_LOWER:
   339       return LOWER;
   340     case soplex::SPxSolver::FIXED:
   341       return FIXED;
   342     case soplex::SPxSolver::ZERO:
   343       return FREE;
   344     default:
   345       LEMON_ASSERT(false, "Wrong row status");
   346       return VarStatus();
   347     }
   348   }
   349 
   350   SoplexLp::Value SoplexLp::_getPrimalRay(int i) const {
   351     if (_primal_ray.empty()) {
   352       _primal_ray.resize(soplex->nCols());
   353       soplex::Vector pv(_primal_ray.size(), &_primal_ray.front());
   354       soplex->getDualfarkas(pv);
   355     }
   356     return _primal_ray[i];
   357   }
   358 
   359   SoplexLp::Value SoplexLp::_getDualRay(int i) const {
   360     if (_dual_ray.empty()) {
   361       _dual_ray.resize(soplex->nRows());
   362       soplex::Vector dv(_dual_ray.size(), &_dual_ray.front());
   363       soplex->getDualfarkas(dv);
   364     }
   365     return _dual_ray[i];
   366   }
   367 
   368   SoplexLp::ProblemType SoplexLp::_getPrimalType() const {
   369     switch (soplex->status()) {
   370     case soplex::SPxSolver::OPTIMAL:
   371       return OPTIMAL;
   372     case soplex::SPxSolver::UNBOUNDED:
   373       return UNBOUNDED;
   374     case soplex::SPxSolver::INFEASIBLE:
   375       return INFEASIBLE;
   376     default:
   377       return UNDEFINED;
   378     }
   379   }
   380 
   381   SoplexLp::ProblemType SoplexLp::_getDualType() const {
   382     switch (soplex->status()) {
   383     case soplex::SPxSolver::OPTIMAL:
   384       return OPTIMAL;
   385     case soplex::SPxSolver::UNBOUNDED:
   386       return UNBOUNDED;
   387     case soplex::SPxSolver::INFEASIBLE:
   388       return INFEASIBLE;
   389     default:
   390       return UNDEFINED;
   391     }
   392   }
   393 
   394   void SoplexLp::_setSense(Sense sense) {
   395     switch (sense) {
   396     case MIN:
   397       soplex->changeSense(soplex::SPxSolver::MINIMIZE);
   398       break;
   399     case MAX:
   400       soplex->changeSense(soplex::SPxSolver::MAXIMIZE);
   401     }
   402   }
   403 
   404   SoplexLp::Sense SoplexLp::_getSense() const {
   405     switch (soplex->spxSense()) {
   406     case soplex::SPxSolver::MAXIMIZE:
   407       return MAX;
   408     case soplex::SPxSolver::MINIMIZE:
   409       return MIN;
   410     default:
   411       LEMON_ASSERT(false, "Wrong sense.");
   412       return SoplexLp::Sense();
   413     }
   414   }
   415 
   416   void SoplexLp::_clear() {
   417     soplex->clear();
   418     _col_names.clear();
   419     _col_names_ref.clear();
   420     _row_names.clear();
   421     _row_names_ref.clear();
   422     cols.clear();
   423     rows.clear();
   424     _clear_temporals();
   425   }
   426 
   427   void SoplexLp::_messageLevel(MessageLevel level) {
   428     switch (level) {
   429     case MESSAGE_NOTHING:
   430       _message_level = -1;
   431       break;
   432     case MESSAGE_ERROR:
   433       _message_level = soplex::SPxOut::ERROR;
   434       break;
   435     case MESSAGE_WARNING:
   436       _message_level = soplex::SPxOut::WARNING;
   437       break;
   438     case MESSAGE_NORMAL:
   439       _message_level = soplex::SPxOut::INFO2;
   440       break;
   441     case MESSAGE_VERBOSE:
   442       _message_level = soplex::SPxOut::DEBUG;
   443       break;
   444     }
   445   }
   446 
   447   void SoplexLp::_applyMessageLevel() {
   448     soplex::Param::setVerbose(_message_level);
   449   }
   450 
   451 } //namespace lemon
   452