# HG changeset patch
# User Balazs Dezso <deba@inf.elte.hu>
# Date 2009-04-08 22:49:28
# Node ID 745e182d01397d0fda77e4f76d031b11d7ad63aa
# Parent  37216ca5b9c610a335e9dcdb941115003d1f3769

Unified message handling for LP and MIP solvers (#9)

diff --git a/lemon/cbc.cc b/lemon/cbc.cc
--- a/lemon/cbc.cc
+++ b/lemon/cbc.cc
@@ -55,12 +55,15 @@
     _prob->setProblemName("LEMON");
     _osi_solver = 0;
     _cbc_model = 0;
+    messageLevel(MESSAGE_NOTHING);
   }
 
   CbcMip::CbcMip(const CbcMip& other) {
     _prob = new CoinModel(*other._prob);
+    _prob->setProblemName("LEMON");
     _osi_solver = 0;
     _cbc_model = 0;
+    messageLevel(MESSAGE_NOTHING);
   }
 
   CbcMip::~CbcMip() {
@@ -270,24 +273,8 @@
     }
     _cbc_model= new CbcModel(*_osi_solver);
 
-    switch (_message_level) {
-    case MESSAGE_NO_OUTPUT:
-      _osi_solver->messageHandler()->setLogLevel(0);
-      _cbc_model->setLogLevel(0);
-      break;
-    case MESSAGE_ERROR_MESSAGE:
-      _osi_solver->messageHandler()->setLogLevel(1);
-      _cbc_model->setLogLevel(1);
-      break;
-    case MESSAGE_NORMAL_OUTPUT:
-      _osi_solver->messageHandler()->setLogLevel(2);
-      _cbc_model->setLogLevel(2);
-      break;
-    case MESSAGE_FULL_OUTPUT:
-      _osi_solver->messageHandler()->setLogLevel(3);
-      _cbc_model->setLogLevel(3);
-      break;
-    }
+    _osi_solver->messageHandler()->setLogLevel(_message_level);
+    _cbc_model->setLogLevel(_message_level);
 
     _cbc_model->initialSolve();
     _cbc_model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
@@ -453,8 +440,24 @@
     cols.clear();
   }
 
-  void CbcMip::messageLevel(MessageLevel m) {
-    _message_level = m;
+  void CbcMip::_messageLevel(MessageLevel level) {
+    switch (level) {
+    case MESSAGE_NOTHING:
+      _message_level = 0;
+      break;
+    case MESSAGE_ERROR:
+      _message_level = 1;
+      break;
+    case MESSAGE_WARNING:
+      _message_level = 1;
+      break;
+    case MESSAGE_NORMAL:
+      _message_level = 2;
+      break;
+    case MESSAGE_VERBOSE:
+      _message_level = 3;
+      break;
+    }
   }
 
 } //END OF NAMESPACE LEMON
diff --git a/lemon/cbc.h b/lemon/cbc.h
--- a/lemon/cbc.h
+++ b/lemon/cbc.h
@@ -115,33 +115,12 @@
 
     virtual void _clear();
 
-  public:
+    virtual void _messageLevel(MessageLevel level);
+    void _applyMessageLevel();
 
-    ///Enum for \c messageLevel() parameter
-    enum MessageLevel {
-      /// no output (default value)
-      MESSAGE_NO_OUTPUT = 0,
-      /// error messages only
-      MESSAGE_ERROR_MESSAGE = 1,
-      /// normal output
-      MESSAGE_NORMAL_OUTPUT = 2,
-      /// full output (includes informational messages)
-      MESSAGE_FULL_OUTPUT = 3
-    };
+    int _message_level;
 
-  private:
-
-    MessageLevel _message_level;
-
-  public:
-
-    ///Set the verbosity of the messages
-
-    ///Set the verbosity of the messages
-    ///
-    ///\param m is the level of the messages output by the solver routines.
-    void messageLevel(MessageLevel m);
-
+    
 
   };
 
diff --git a/lemon/clp.cc b/lemon/clp.cc
--- a/lemon/clp.cc
+++ b/lemon/clp.cc
@@ -24,7 +24,7 @@
   ClpLp::ClpLp() {
     _prob = new ClpSimplex();
     _init_temporals();
-    messageLevel(MESSAGE_NO_OUTPUT);
+    messageLevel(MESSAGE_NOTHING);
   }
 
   ClpLp::ClpLp(const ClpLp& other) {
@@ -32,7 +32,7 @@
     rows = other.rows;
     cols = other.cols;
     _init_temporals();
-    messageLevel(MESSAGE_NO_OUTPUT);
+    messageLevel(MESSAGE_NOTHING);
   }
 
   ClpLp::~ClpLp() {
@@ -430,8 +430,24 @@
     _clear_temporals();
   }
 
-  void ClpLp::messageLevel(MessageLevel m) {
-    _prob->setLogLevel(static_cast<int>(m));
+  void ClpLp::_messageLevel(MessageLevel level) {
+    switch (level) {
+    case MESSAGE_NOTHING:
+      _prob->setLogLevel(0);
+      break;
+    case MESSAGE_ERROR:
+      _prob->setLogLevel(1);
+      break;
+    case MESSAGE_WARNING:
+      _prob->setLogLevel(2);
+      break;
+    case MESSAGE_NORMAL:
+      _prob->setLogLevel(3);
+      break;
+    case MESSAGE_VERBOSE:
+      _prob->setLogLevel(4);
+      break;
+    }
   }
 
 } //END OF NAMESPACE LEMON
diff --git a/lemon/clp.h b/lemon/clp.h
--- a/lemon/clp.h
+++ b/lemon/clp.h
@@ -136,6 +136,8 @@
 
     virtual void _clear();
 
+    virtual void _messageLevel(MessageLevel);
+    
   public:
 
     ///Solves LP with primal simplex method.
@@ -153,26 +155,6 @@
     ///Returns the variable identifier understood by CLP.
     int clpCol(Col c) const { return cols(id(c)); }
 
-    ///Enum for \c messageLevel() parameter
-    enum MessageLevel {
-      /// no output (default value)
-      MESSAGE_NO_OUTPUT = 0,
-      /// print final solution
-      MESSAGE_FINAL_SOLUTION = 1,
-      /// print factorization
-      MESSAGE_FACTORIZATION = 2,
-      /// normal output
-      MESSAGE_NORMAL_OUTPUT = 3,
-      /// verbose output
-      MESSAGE_VERBOSE_OUTPUT = 4
-    };
-    ///Set the verbosity of the messages
-
-    ///Set the verbosity of the messages
-    ///
-    ///\param m is the level of the messages output by the solver routines.
-    void messageLevel(MessageLevel m);
-
   };
 
 } //END OF NAMESPACE LEMON
diff --git a/lemon/cplex.cc b/lemon/cplex.cc
--- a/lemon/cplex.cc
+++ b/lemon/cplex.cc
@@ -72,12 +72,14 @@
   CplexBase::CplexBase() : LpBase() {
     int status;
     _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
+    messageLevel(MESSAGE_NOTHING);
   }
 
   CplexBase::CplexBase(const CplexEnv& env)
     : LpBase(), _env(env) {
     int status;
     _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
+    messageLevel(MESSAGE_NOTHING);
   }
 
   CplexBase::CplexBase(const CplexBase& cplex)
@@ -86,6 +88,7 @@
     _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status);
     rows = cplex.rows;
     cols = cplex.cols;
+    messageLevel(MESSAGE_NOTHING);
   }
 
   CplexBase::~CplexBase() {
@@ -438,6 +441,25 @@
     cols.clear();
   }
 
+  void CplexBase::_messageLevel(MessageLevel level) {
+    switch (level) {
+    case MESSAGE_NOTHING:
+      _message_enabled = false;
+      break;
+    case MESSAGE_ERROR:
+    case MESSAGE_WARNING:
+    case MESSAGE_NORMAL:
+    case MESSAGE_VERBOSE:
+      _message_enabled = true;
+      break;
+    }
+  }
+
+  void CplexBase::_applyMessageLevel() {
+    CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND, 
+                   _message_enabled ? CPX_ON : CPX_OFF);
+  }
+
   // CplexLp members
 
   CplexLp::CplexLp()
@@ -507,21 +529,25 @@
 
   CplexLp::SolveExitStatus CplexLp::_solve() {
     _clear_temporals();
+    _applyMessageLevel();
     return convertStatus(CPXlpopt(cplexEnv(), _prob));
   }
 
   CplexLp::SolveExitStatus CplexLp::solvePrimal() {
     _clear_temporals();
+    _applyMessageLevel();
     return convertStatus(CPXprimopt(cplexEnv(), _prob));
   }
 
   CplexLp::SolveExitStatus CplexLp::solveDual() {
     _clear_temporals();
+    _applyMessageLevel();
     return convertStatus(CPXdualopt(cplexEnv(), _prob));
   }
 
   CplexLp::SolveExitStatus CplexLp::solveBarrier() {
     _clear_temporals();
+    _applyMessageLevel();
     return convertStatus(CPXbaropt(cplexEnv(), _prob));
   }
 
@@ -600,7 +626,7 @@
     return _dual_ray[i];
   }
 
-  //7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!)
+  // Cplex 7.0 status values
   // 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.
@@ -647,7 +673,7 @@
   // 20   CPX_PIVOT
   //       User pivot used
   //
-  //     Ezeket hova tegyem:
+  // Pending return values
   // ??case CPX_ABORT_DUAL_INFEAS
   // ??case CPX_ABORT_CROSSOVER
   // ??case CPX_INForUNBD
@@ -718,7 +744,6 @@
 #else
     statusSwitch(cplexEnv(),stat);
     //CPXgetstat(cplexEnv(), _prob);
-    //printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL);
     switch (stat) {
     case 0:
       return UNDEFINED; //Undefined
@@ -751,7 +776,7 @@
 #endif
   }
 
-  //9.0-as cplex verzio statusai
+  // Cplex 9.0 status values
   // CPX_STAT_ABORT_DUAL_OBJ_LIM
   // CPX_STAT_ABORT_IT_LIM
   // CPX_STAT_ABORT_OBJ_LIM
@@ -864,6 +889,7 @@
 
   CplexMip::SolveExitStatus CplexMip::_solve() {
     int status;
+    _applyMessageLevel();
     status = CPXmipopt (cplexEnv(), _prob);
     if (status==0)
       return SOLVED;
diff --git a/lemon/cplex.h b/lemon/cplex.h
--- a/lemon/cplex.h
+++ b/lemon/cplex.h
@@ -144,14 +144,29 @@
 
     virtual void _clear();
 
+    virtual void _messageLevel(MessageLevel level);
+    void _applyMessageLevel();
+
+    bool _message_enabled;
+
   public:
 
     /// Returns the used \c CplexEnv instance
     const CplexEnv& env() const { return _env; }
+
+    /// \brief Returns the const cpxenv pointer
     ///
+    /// \note The cpxenv might be destructed with the solver.
     const cpxenv* cplexEnv() const { return _env.cplexEnv(); }
 
+    /// \brief Returns the const cpxenv pointer
+    ///
+    /// \note The cpxenv might be destructed with the solver.
+    cpxenv* cplexEnv() { return _env.cplexEnv(); }
+
+    /// Returns the cplex problem object
     cpxlp* cplexLp() { return _prob; }
+    /// Returns the cplex problem object
     const cpxlp* cplexLp() const { return _prob; }
 
   };
diff --git a/lemon/glpk.cc b/lemon/glpk.cc
--- a/lemon/glpk.cc
+++ b/lemon/glpk.cc
@@ -31,6 +31,7 @@
   GlpkBase::GlpkBase() : LpBase() {
     lp = glp_create_prob();
     glp_create_index(lp);
+    messageLevel(MESSAGE_NOTHING);
   }
 
   GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() {
@@ -39,6 +40,7 @@
     glp_create_index(lp);
     rows = other.rows;
     cols = other.cols;
+    messageLevel(MESSAGE_NOTHING);
   }
 
   GlpkBase::~GlpkBase() {
@@ -526,19 +528,37 @@
     glp_free_env();
   }
 
+  void GlpkBase::_messageLevel(MessageLevel level) {
+    switch (level) {
+    case MESSAGE_NOTHING:
+      _message_level = GLP_MSG_OFF;
+      break;
+    case MESSAGE_ERROR:
+      _message_level = GLP_MSG_ERR;
+      break;
+    case MESSAGE_WARNING:
+      _message_level = GLP_MSG_ERR;
+      break;
+    case MESSAGE_NORMAL:
+      _message_level = GLP_MSG_ON;
+      break;
+    case MESSAGE_VERBOSE:
+      _message_level = GLP_MSG_ALL;
+      break;
+    }
+  }
+
   GlpkBase::FreeEnvHelper GlpkBase::freeEnvHelper;
 
   // GlpkLp members
 
   GlpkLp::GlpkLp()
     : LpBase(), LpSolver(), GlpkBase() {
-    messageLevel(MESSAGE_NO_OUTPUT);
     presolver(false);
   }
 
   GlpkLp::GlpkLp(const GlpkLp& other)
     : LpBase(other), LpSolver(other), GlpkBase(other) {
-    messageLevel(MESSAGE_NO_OUTPUT);
     presolver(false);
   }
 
@@ -562,20 +582,7 @@
     glp_smcp smcp;
     glp_init_smcp(&smcp);
 
-    switch (_message_level) {
-    case MESSAGE_NO_OUTPUT:
-      smcp.msg_lev = GLP_MSG_OFF;
-      break;
-    case MESSAGE_ERROR_MESSAGE:
-      smcp.msg_lev = GLP_MSG_ERR;
-      break;
-    case MESSAGE_NORMAL_OUTPUT:
-      smcp.msg_lev = GLP_MSG_ON;
-      break;
-    case MESSAGE_FULL_OUTPUT:
-      smcp.msg_lev = GLP_MSG_ALL;
-      break;
-    }
+    smcp.msg_lev = _message_level;
     smcp.presolve = _presolve;
 
     // If the basis is not valid we get an error return value.
@@ -604,20 +611,7 @@
     glp_smcp smcp;
     glp_init_smcp(&smcp);
 
-    switch (_message_level) {
-    case MESSAGE_NO_OUTPUT:
-      smcp.msg_lev = GLP_MSG_OFF;
-      break;
-    case MESSAGE_ERROR_MESSAGE:
-      smcp.msg_lev = GLP_MSG_ERR;
-      break;
-    case MESSAGE_NORMAL_OUTPUT:
-      smcp.msg_lev = GLP_MSG_ON;
-      break;
-    case MESSAGE_FULL_OUTPUT:
-      smcp.msg_lev = GLP_MSG_ALL;
-      break;
-    }
+    smcp.msg_lev = _message_level;
     smcp.meth = GLP_DUAL;
     smcp.presolve = _presolve;
 
@@ -858,20 +852,14 @@
     _presolve = presolve;
   }
 
-  void GlpkLp::messageLevel(MessageLevel m) {
-    _message_level = m;
-  }
-
   // GlpkMip members
 
   GlpkMip::GlpkMip()
     : LpBase(), MipSolver(), GlpkBase() {
-    messageLevel(MESSAGE_NO_OUTPUT);
   }
 
   GlpkMip::GlpkMip(const GlpkMip& other)
     : LpBase(), MipSolver(), GlpkBase(other) {
-    messageLevel(MESSAGE_NO_OUTPUT);
   }
 
   void GlpkMip::_setColType(int i, GlpkMip::ColTypes col_type) {
@@ -900,20 +888,7 @@
     glp_smcp smcp;
     glp_init_smcp(&smcp);
 
-    switch (_message_level) {
-    case MESSAGE_NO_OUTPUT:
-      smcp.msg_lev = GLP_MSG_OFF;
-      break;
-    case MESSAGE_ERROR_MESSAGE:
-      smcp.msg_lev = GLP_MSG_ERR;
-      break;
-    case MESSAGE_NORMAL_OUTPUT:
-      smcp.msg_lev = GLP_MSG_ON;
-      break;
-    case MESSAGE_FULL_OUTPUT:
-      smcp.msg_lev = GLP_MSG_ALL;
-      break;
-    }
+    smcp.msg_lev = _message_level;
     smcp.meth = GLP_DUAL;
 
     // If the basis is not valid we get an error return value.
@@ -938,20 +913,7 @@
     glp_iocp iocp;
     glp_init_iocp(&iocp);
 
-    switch (_message_level) {
-    case MESSAGE_NO_OUTPUT:
-      iocp.msg_lev = GLP_MSG_OFF;
-      break;
-    case MESSAGE_ERROR_MESSAGE:
-      iocp.msg_lev = GLP_MSG_ERR;
-      break;
-    case MESSAGE_NORMAL_OUTPUT:
-      iocp.msg_lev = GLP_MSG_ON;
-      break;
-    case MESSAGE_FULL_OUTPUT:
-      iocp.msg_lev = GLP_MSG_ALL;
-      break;
-    }
+    iocp.msg_lev = _message_level;
 
     if (glp_intopt(lp, &iocp) != 0) return UNSOLVED;
     return SOLVED;
@@ -1002,8 +964,4 @@
 
   const char* GlpkMip::_solverName() const { return "GlpkMip"; }
 
-  void GlpkMip::messageLevel(MessageLevel m) {
-    _message_level = m;
-  }
-
 } //END OF NAMESPACE LEMON
diff --git a/lemon/glpk.h b/lemon/glpk.h
--- a/lemon/glpk.h
+++ b/lemon/glpk.h
@@ -100,6 +100,8 @@
 
     virtual void _clear();
 
+    virtual void _messageLevel(MessageLevel level);
+
   private:
 
     static void freeEnv();
@@ -111,6 +113,10 @@
     };
     
     static FreeEnvHelper freeEnvHelper;
+
+  protected:
+    
+    int _message_level;
     
   public:
 
@@ -191,30 +197,6 @@
     ///The presolver is off by default.
     void presolver(bool presolve);
 
-    ///Enum for \c messageLevel() parameter
-    enum MessageLevel {
-      /// no output (default value)
-      MESSAGE_NO_OUTPUT = 0,
-      /// error messages only
-      MESSAGE_ERROR_MESSAGE = 1,
-      /// normal output
-      MESSAGE_NORMAL_OUTPUT = 2,
-      /// full output (includes informational messages)
-      MESSAGE_FULL_OUTPUT = 3
-    };
-
-  private:
-
-    MessageLevel _message_level;
-
-  public:
-
-    ///Set the verbosity of the messages
-
-    ///Set the verbosity of the messages
-    ///
-    ///\param m is the level of the messages output by the solver routines.
-    void messageLevel(MessageLevel m);
   };
 
   /// \brief Interface for the GLPK MIP solver
@@ -244,30 +226,6 @@
     virtual Value _getSol(int i) const;
     virtual Value _getSolValue() const;
 
-    ///Enum for \c messageLevel() parameter
-    enum MessageLevel {
-      /// no output (default value)
-      MESSAGE_NO_OUTPUT = 0,
-      /// error messages only
-      MESSAGE_ERROR_MESSAGE = 1,
-      /// normal output
-      MESSAGE_NORMAL_OUTPUT = 2,
-      /// full output (includes informational messages)
-      MESSAGE_FULL_OUTPUT = 3
-    };
-
-  private:
-
-    MessageLevel _message_level;
-
-  public:
-
-    ///Set the verbosity of the messages
-
-    ///Set the verbosity of the messages
-    ///
-    ///\param m is the level of the messages output by the solver routines.
-    void messageLevel(MessageLevel m);
   };
 
 
diff --git a/lemon/lp_base.h b/lemon/lp_base.h
--- a/lemon/lp_base.h
+++ b/lemon/lp_base.h
@@ -69,6 +69,21 @@
       MAX
     };
 
+    ///Enum for \c messageLevel() parameter
+    enum MessageLevel {
+      /// no output (default value)
+      MESSAGE_NOTHING,
+      /// error messages only
+      MESSAGE_ERROR,
+      /// warnings
+      MESSAGE_WARNING,
+      /// normal output
+      MESSAGE_NORMAL,
+      /// verbose output
+      MESSAGE_VERBOSE
+    };
+    
+
     ///The floating point type used by the solver
     typedef double Value;
     ///The infinity constant
@@ -973,6 +988,8 @@
 
     virtual const char* _solverName() const = 0;
 
+    virtual void _messageLevel(MessageLevel level) = 0;
+
     //Own protected stuff
 
     //Constant component of the objective function
@@ -1527,6 +1544,9 @@
     ///Clears the problem
     void clear() { _clear(); }
 
+    /// Sets the message level of the solver
+    void messageLevel(MessageLevel level) { _messageLevel(level); }
+
     ///@}
 
   };
diff --git a/lemon/lp_skeleton.cc b/lemon/lp_skeleton.cc
--- a/lemon/lp_skeleton.cc
+++ b/lemon/lp_skeleton.cc
@@ -84,6 +84,8 @@
     row_num = col_num = 0;
   }
 
+  void SkeletonSolverBase::_messageLevel(MessageLevel) {}
+
   LpSkeleton::SolveExitStatus LpSkeleton::_solve() { return SOLVED; }
 
   LpSkeleton::Value LpSkeleton::_getPrimal(int) const { return 0; }
diff --git a/lemon/lp_skeleton.h b/lemon/lp_skeleton.h
--- a/lemon/lp_skeleton.h
+++ b/lemon/lp_skeleton.h
@@ -140,6 +140,8 @@
     ///\e
     virtual void _clear();
 
+    ///\e
+    virtual void _messageLevel(MessageLevel);
   };
 
   /// \brief Skeleton class for an LP solver interface
diff --git a/lemon/soplex.cc b/lemon/soplex.cc
--- a/lemon/soplex.cc
+++ b/lemon/soplex.cc
@@ -20,6 +20,7 @@
 #include <lemon/soplex.h>
 
 #include <soplex.h>
+#include <spxout.h>
 
 
 ///\file
@@ -28,6 +29,7 @@
 
   SoplexLp::SoplexLp() {
     soplex = new soplex::SoPlex;
+    messageLevel(MESSAGE_NOTHING);
   }
 
   SoplexLp::~SoplexLp() {
@@ -47,6 +49,7 @@
     _row_names = lp._row_names;
     _row_names_ref = lp._row_names_ref;
 
+    messageLevel(MESSAGE_NOTHING);
   }
 
   void SoplexLp::_clear_temporals() {
@@ -271,6 +274,8 @@
   SoplexLp::SolveExitStatus SoplexLp::_solve() {
 
     _clear_temporals();
+    
+    _applyMessageLevel();
 
     soplex::SPxSolver::Status status = soplex->solve();
 
@@ -419,5 +424,29 @@
     _clear_temporals();
   }
 
+  void SoplexLp::_messageLevel(MessageLevel level) {
+    switch (level) {
+    case MESSAGE_NOTHING:
+      _message_level = -1;
+      break;
+    case MESSAGE_ERROR:
+      _message_level = soplex::SPxOut::ERROR;
+      break;
+    case MESSAGE_WARNING:
+      _message_level = soplex::SPxOut::WARNING;
+      break;
+    case MESSAGE_NORMAL:
+      _message_level = soplex::SPxOut::INFO2;
+      break;
+    case MESSAGE_VERBOSE:
+      _message_level = soplex::SPxOut::DEBUG;
+      break;
+    }
+  }
+
+  void SoplexLp::_applyMessageLevel() {
+    soplex::Param::setVerbose(_message_level);
+  }
+
 } //namespace lemon
 
diff --git a/lemon/soplex.h b/lemon/soplex.h
--- a/lemon/soplex.h
+++ b/lemon/soplex.h
@@ -144,6 +144,11 @@
 
     virtual void _clear();
 
+    void _messageLevel(MessageLevel m);
+    void _applyMessageLevel();
+
+    int _message_level;
+
   };
 
 } //END OF NAMESPACE LEMON