[Lemon-commits] deba: r3183 - in hugo/trunk: doc lemon

Lemon SVN svn at lemon.cs.elte.hu
Mon Feb 19 13:11:42 CET 2007


Author: deba
Date: Mon Feb 19 13:11:41 2007
New Revision: 3183

Modified:
   hugo/trunk/doc/groups.dox
   hugo/trunk/lemon/lemon_reader.h
   hugo/trunk/lemon/lp_base.h
   hugo/trunk/lemon/lp_glpk.cc
   hugo/trunk/lemon/lp_soplex.cc
   hugo/trunk/lemon/lp_utils.h

Log:
Bug fixes
Documentation



Modified: hugo/trunk/doc/groups.dox
==============================================================================
--- hugo/trunk/doc/groups.dox	(original)
+++ hugo/trunk/doc/groups.dox	Mon Feb 19 13:11:41 2007
@@ -213,6 +213,17 @@
 
 */
 
+/** 
+\ingroup gen_opt_group 
+ at defgroup gen_opt_tools Various Tools for Optimization 
+\brief This group adds some helper tools to general optimization
+framework implemented in LEMON.
+
+This group adds some helper tools to general optimization framework
+implemented in LEMON.
+
+*/
+
 /**
 @defgroup misc Miscellaneous Tools
 Here you can find several useful tools for development,

Modified: hugo/trunk/lemon/lemon_reader.h
==============================================================================
--- hugo/trunk/lemon/lemon_reader.h	(original)
+++ hugo/trunk/lemon/lemon_reader.h	Mon Feb 19 13:11:41 2007
@@ -740,9 +740,9 @@
   /// \ingroup section_io
   /// \brief SectionReader for reading a graph's nodeset.
   ///
-  /// The lemon format can store multiple graph nodesets with several maps.
-  /// The nodeset section's header line is \c \@nodeset \c nodeset_name, but the
-  /// \c nodeset_name may be empty.
+  /// The lemon format can store multiple graph nodesets with several
+  /// maps.  The nodeset section's header line is \c \@nodeset \c
+  /// nodeset_name, but the \c nodeset_name may be empty.
   ///
   /// The first line of the section contains the names of the maps separated
   /// with white spaces. Each next lines describes a node in the nodeset, and

Modified: hugo/trunk/lemon/lp_base.h
==============================================================================
--- hugo/trunk/lemon/lp_base.h	(original)
+++ hugo/trunk/lemon/lp_base.h	Mon Feb 19 13:11:41 2007
@@ -1060,6 +1060,15 @@
     void colName(Col c, const std::string& name) {
       _setColName(_lpId(c), name);
     }
+
+    /// Get the column by its name
+    
+    ///\param name The name of the column
+    ///\return the proper column or \c INVALID
+    Col colByName(const std::string& name) const {
+      int k = _colByName(name);
+      return k != -1 ? Col(cols.fixId(k)) : Col(INVALID);
+    }
     
     /// Set an element of the coefficient matrix of the LP
 

Modified: hugo/trunk/lemon/lp_glpk.cc
==============================================================================
--- hugo/trunk/lemon/lp_glpk.cc	(original)
+++ hugo/trunk/lemon/lp_glpk.cc	Mon Feb 19 13:11:41 2007
@@ -28,6 +28,7 @@
     rows = _lp_bits::LpId(1);
     cols = _lp_bits::LpId(1);
     lp = lpx_create_prob();
+    lpx_create_index(lp);
     ///\todo control function for this:
     lpx_set_int_parm(lp, LPX_K_DUAL, 1);
     messageLevel(0);

Modified: hugo/trunk/lemon/lp_soplex.cc
==============================================================================
--- hugo/trunk/lemon/lp_soplex.cc	(original)
+++ hugo/trunk/lemon/lp_soplex.cc	Mon Feb 19 13:11:41 2007
@@ -76,7 +76,9 @@
 
   void LpSoplex::_eraseCol(int i) {
     soplex->removeCol(i);
+    invColNames.erase(colNames[i]);
     colNames[i] = colNames.back();
+    invColNames[colNames.back()] = i;
     colNames.pop_back();
     primal_value[i] = primal_value.back();
     primal_value.pop_back();

Modified: hugo/trunk/lemon/lp_utils.h
==============================================================================
--- hugo/trunk/lemon/lp_utils.h	(original)
+++ hugo/trunk/lemon/lp_utils.h	Mon Feb 19 13:11:41 2007
@@ -24,8 +24,294 @@
 #include <lemon/lemon_reader.h>
 #include <lemon/lemon_writer.h>
 
+#include <map>
+#include <set>
+
+
 namespace lemon {
 
+  /// \ingroup gen_opt_tools
+  ///
+  /// \brief The map for the result of the lp variables.
+  ///
+  /// The map for the result of the lp variables.
+  class LpResultMap {
+  public:
+    typedef LpSolverBase::Col Key;
+    typedef LpSolverBase::Value Value;
+
+    /// \brief Constructor
+    ///
+    /// Constructor
+    LpResultMap(const LpSolverBase& _lp) : lp(_lp) {}
+    LpSolverBase::Value operator[](const LpSolverBase::Col col) const {
+      return lp.primal(col);
+    }
+  private:
+    const LpSolverBase& lp;
+  };
+
+  /// \ingroup gen_opt_tools
+  ///
+  /// \brief The map for the name of the lp variables.
+  ///
+  /// The map for the name of the lp variables.
+  class LpColNameMap {
+  public:
+    typedef LpSolverBase::Col Key;
+    typedef std::string Value;
+
+    /// \brief Constructor
+    ///
+    /// Constructor
+    LpColNameMap(const LpSolverBase& _lp) : lp(_lp) {}
+    std::string operator[](const LpSolverBase::Col col) const {
+      return lp.colName(col);
+    }
+  private:
+    const LpSolverBase& lp;
+  };
+
+  /// \ingroup gen_opt_tools
+  ///
+  /// \brief Writeable map for the name of the lp variables.
+  ///
+  /// Writeable map for the name of the lp variables.
+  class LpColNameWriteMap {
+  public:
+    typedef LpSolverBase::Col Key;
+    typedef std::string Value;
+
+    /// \brief Constructor
+    ///
+    /// Constructor
+    LpColNameWriteMap(LpSolverBase& _lp) : lp(_lp) {}
+    std::string operator[](const LpSolverBase::Col col) const {
+      return lp.colName(col);
+    }
+    void set(const LpSolverBase::Col col, const std::string& name) {
+      lp.colName(col, name);
+    }
+  private:
+    LpSolverBase& lp;
+  };
+
+  /// \ingroup gen_opt_tools
+  ///
+  /// \brief Returns an \ref LpColNameMap class
+  ///
+  /// This function just returns an \ref LpColNameMap class.
+  /// \relates LpColNameMap
+  LpColNameMap lpColNameMap(const LpSolverBase& lp) {
+    return LpColNameMap(lp);
+  }
+
+  LpColNameWriteMap lpColNameMap(LpSolverBase& lp) {
+    return LpColNameWriteMap(lp);
+  }
+
+  /// \ingroup gen_opt_tools
+  ///
+  /// \brief Lp variable item reader for Lemon IO
+  ///
+  /// This class is an Lp variable item reader for Lemon IO. It makes
+  /// possible to store lp variables in lemon file. The usage of this
+  /// class is very simple:
+  ///
+  ///\code
+  /// Graph graph;
+  /// Lp lp;
+  /// Graph::EdgeMap<Lp::Col> var(graph); 
+  ///
+  /// GraphReader<Graph> reader(cin, graph);
+  /// reader.readEdgeMap("lpvar", var, LpColReader(lp));
+  /// reader.run();
+  ///\endcode
+  ///
+  /// If there is already a variable with the same name in the lp then
+  /// it will be used for the return value. If there is no such variable
+  /// then it will be constructed. The file could contain \c '-' as value
+  /// which means that no lp variable associated to the current item and
+  /// in this case INVALID will be returned.
+  class LpColReader {
+  public:
+
+    /// \brief The value type of reader.
+    ///
+    /// The value type of reader.
+    typedef LpSolverBase::Col Value;
+
+    /// \brief Constructor for the reader.
+    ///
+    /// Constructor for the reader.
+    LpColReader(LpSolverBase& _lp) : lp(_lp) {}
+
+    /// \brief Reads an lp variable from the given stream.
+    ///
+    /// Reads an lp variable string from the given stream.
+    void read(std::istream& is, LpSolverBase::Col& col) const {
+      char x;
+      is >> std::ws;
+      if (!is.get(x))
+        throw DataFormatError("Wrong Lp Column format!");
+      if (varFirstChar(x)) {
+        std::string var;
+        var += x;
+        
+        while (is.get(x) && varChar(x)) {
+          var += x;
+        }
+        if (!is) {
+          is.clear();
+        } else {
+          is.putback(x);
+        }
+        col = lp.colByName(var);
+        if (col == INVALID) {
+          col = lp.addCol();
+          lp.colName(col, var);
+        }
+      } else if (x == '-') {
+        col = INVALID;
+        is >> std::ws;
+      } else {
+        std::cerr << x << std::endl;
+        throw DataFormatError("Wrong Lp Column format");
+      }
+    }
+
+  private:
+
+    static bool varFirstChar(char c) {
+      return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+    }
+
+    static bool varChar(char c) {
+      return (c >= '0' && c <= '9') || 
+        (c >= 'a' && c <= 'z') || 
+        (c >= 'A' && c <= 'Z') ||
+        c == '[' || c == ']';
+    }
+    
+    LpSolverBase& lp;
+
+  };
+
+  /// \ingroup gen_opt_tools
+  ///
+  /// \brief Lp variable item writer for Lemon IO
+  ///
+  /// This class is an Lp variable item writer for Lemon IO. It makes
+  /// possible to store lp variables in lemon file. The usage of this
+  /// class is very simple:
+  ///
+  ///\code
+  /// Graph graph;
+  /// Lp lp;
+  /// Graph::EdgeMap<Lp::Col> var(graph); 
+  ///
+  /// GraphWriter<Graph> writer(cin, graph);
+  /// writer.writeEdgeMap("lpvar", var, LpColWriter(lp));
+  /// writer.run();
+  ///\endcode
+  ///
+  /// If there is no name associated to the current item then the name
+  /// will automatically constructed. If the value is INVALID then it
+  /// will write an \c '-' value to the file.
+  class LpColWriter {
+  public:
+
+    /// \brief The value type of writer.
+    ///
+    /// The value type of writer.
+    typedef LpSolverBase::Col Value;
+
+    /// \brief Constructor for the writer.
+    ///
+    /// Constructor for the writer.
+    LpColWriter(const LpSolverBase& _lp) : lp(_lp), num(0) {}
+
+    /// \brief Writes an lp variable to the given stream.
+    ///
+    /// Writes an lp variable to the given stream.
+    void write(std::ostream& os, const LpSolverBase::Col& col) const {
+      if (col != INVALID) {
+        std::string name = lp.colName(col);
+        if (name.empty()) {
+          std::ostringstream ls;
+          ls << "x" << num;
+          ++num;
+          while (lp.colByName(ls.str()) != INVALID) {
+            ls.str(std::string());
+            ls << "x" << num;
+            ++num;
+          }
+          const_cast<LpSolverBase&>(lp).colName(col, ls.str());
+          os << ls.str();
+        } else {
+          os << name;
+        }
+      } else {
+        os << "-";
+      }
+    }
+
+  private:
+
+    const LpSolverBase& lp;
+    mutable int num;
+
+  };
+
+  /// \ingroup gen_opt_tools
+  ///
+  /// \brief Lp section reader for lemon IO
+  ///
+  /// This section reader provides an easy way to read an Lp problem
+  /// from a file. The lemon lp section format contains three parts.
+  ///
+  ///\code
+  /// @lp
+  /// constraints
+  ///   7 == x1 - 1 * x2
+  ///   2 * x1 + x3 / 2 <= 7
+  ///   x2 + -3 * x3 >= 8
+  ///   3 <= x2 - 2 * x1 <= 8
+  /// bounds
+  ///   x1 >= 3
+  ///   2 <= x2 <= 5
+  ///   0 <= x3 <= 8
+  /// objective
+  ///   min x1 + 2 * x2 - x3
+  ///\endcode
+  ///
+  /// The first part gives the constraints to the lp. The constraints
+  /// could be equality, lower bound, upper bound or range for an
+  /// expression or equality, less or more for two expressions.
+  ///
+  /// The second part gives the bounds for the variables. The bounds
+  /// could be the same as for the single expression so equality,
+  /// lower bound, upper bound or range.
+  ///
+  /// The third part is the objective function, it should start with
+  /// \c min or \c max and then a valid linear expression.
+  ///
+  /// The reader constructs automatically the variable for a name if
+  /// there is not already a variable with the same name.
+  ///
+  /// The basic way to read an LP problem is made by the next code:
+  ///\code
+  /// Lp lp;
+  ///
+  /// LemonReader reader(filename_or_istream);
+  /// LpReader lpreader(reader, lp);
+  /// 
+  /// reader.run();
+  ///\endcode
+  ///
+  /// Of course instead of \c LemonReader you can give a \c
+  /// GraphReader to the LpReader constructor. Also useful that you
+  /// can mix lp problems and graphs in the same file.
   class LpReader : public LemonReader::SectionReader {
     typedef LemonReader::SectionReader Parent;
   public:
@@ -33,7 +319,7 @@
 
     /// \brief Constructor.
     ///
-    /// Constructor for LpReader. It creates the LpReader and attach
+    /// Constructor for LpReader. It creates the LpReader and attachs
     /// it into the given LemonReader. The lp reader will add
     /// variables, constraints and objective function to the
     /// given lp solver.
@@ -44,7 +330,7 @@
 
     /// \brief Destructor.
     ///
-    /// Destructor for NodeSetReader.
+    /// Destructor for LpReader.
     virtual ~LpReader() {}
 
   private:
@@ -68,7 +354,7 @@
 
   private:
 
-    enum SubSection {
+    enum Part {
       CONSTRAINTS, BOUNDS, OBJECTIVE
     };
 
@@ -210,6 +496,7 @@
             lp.colLowerBound(c, w);
             lp.colUpperBound(c, v);
           }
+          is >> std::ws;
           if (is.get(x)) {
             throw DataFormatError("Wrong variable bounds format");
           }
@@ -343,12 +630,9 @@
       } else {
         is.putback(x);
       }
-      ColMap::const_iterator it = cols.find(var);
-      if (cols.find(var) != cols.end()) {
-        c = it->second;
-      } else {
+      c = lp.colByName(var);
+      if (c == INVALID) {
         c = lp.addCol();
-        cols.insert(std::make_pair(var, c));
         lp.colName(c, var);
       }
       return is;
@@ -390,7 +674,7 @@
     static bool numFirstChar(char c) {
       return (c >= '0' && c <= '9') || c == '.';
     }
-
+    
     static bool varChar(char c) {
       return (c >= '0' && c <= '9') || 
         (c >= 'a' && c <= 'z') || 
@@ -405,20 +689,32 @@
     /// It reads the content of the section.
     virtual void read(std::istream& is) {
       std::string line;
-      SubSection sub = CONSTRAINTS;
+      Part part = CONSTRAINTS;
       while (getline(is, line)) {
         std::istringstream ls(line);
         std::string type;
         ls >> type;
         if (type == "constraints") {
-          sub = CONSTRAINTS;
+          part = CONSTRAINTS;
+          ls >> std::ws;
+          char x;
+          if (ls.get(x))
+            throw DataFormatError("Wrong Lp format");
         } else if (type == "bounds") {
-          sub = BOUNDS;
+          part = BOUNDS;
+          ls >> std::ws;
+          char x;
+          if (ls.get(x))
+            throw DataFormatError("Wrong Lp format");
         } else if (type == "objective") {
-          sub = OBJECTIVE;
+          part = OBJECTIVE;
+          ls >> std::ws;
+          char x;
+          if (ls.get(x))
+            throw DataFormatError("Wrong Lp format");
         } else {
           ls.str(line);
-          switch (sub) {
+          switch (part) {
           case CONSTRAINTS:
             readConstraint(ls);
             break;
@@ -429,7 +725,7 @@
             readObjective(ls);
             break;
           }
-        }        
+        }
       }
     }
       
@@ -441,14 +737,62 @@
 
   private:
 
-    typedef std::map<std::string, LpSolverBase::Col> ColMap;
       
     LpSolverBase& lp;
     std::string name;
-    ColMap cols;
   };
 
 
+  /// \ingroup gen_opt_tools
+  ///
+  /// \brief Lp section writer for lemon IO
+  ///
+  /// This section reader provides an easy way to write an Lp problem
+  /// to a file. The lemon lp section format contains three parts.
+  ///
+  ///\code
+  /// @lp
+  /// constraints
+  ///   7 == x1 - 1 * x2
+  ///   2 * x1 + x3 / 2 <= 7
+  ///   x2 + -3 * x3 >= 8
+  ///   3 <= x2 - 2 * x1 <= 8
+  /// bounds
+  ///   x1 >= 3
+  ///   2 <= x2 <= 5
+  ///   0 <= x3 <= 8
+  /// objective
+  ///   min x1 + 2 * x2 - x3
+  ///\endcode
+  ///
+  /// The first part gives the constraints to the lp. The constraints
+  /// could be equality, lower bound, upper bound or range for an
+  /// expression or equality, less or more for two expressions.
+  ///
+  /// The second part gives the bounds for the variables. The bounds
+  /// could be the same as for the single expression so equality,
+  /// lower bound, upper bound or range.
+  ///
+  /// The third part is the objective function, it should start with
+  /// \c min or \c max and then a valid linear expression.
+  ///
+  /// If an LP variable does not have name in the writer, then it will
+  /// automatically created in the writer. This make a slight change
+  /// in the \c const variable.
+  ///
+  /// The basic way to write an LP problem is made by the next code:
+  ///\code
+  /// Lp lp;
+  ///
+  /// LemonWriter writer(filename_or_ostream);
+  /// LpWriter lpwriter(writer, lp);
+  /// 
+  /// writer.run();
+  ///\endcode
+  ///
+  /// Of course instead of \c LemonWriter you can give a \c
+  /// GraphWriter to the LpWriter constructor. Also useful that you
+  /// can mix lp problems and graphs in the same file.
   class LpWriter : public LemonWriter::SectionWriter {
     typedef LemonWriter::SectionWriter Parent;
   public:
@@ -457,17 +801,15 @@
     /// \brief Constructor.
     ///
     /// Constructor for LpWriter. It creates the LpWriter and attach
-    /// it into the given LemonWriter. The lp writer will add
-    /// variables, constraints and objective function to the
-    /// given lp solver.
-    LpWriter(LemonWriter& _writer, LpSolverBase& _lp, 
+    /// it into the given LemonWriter.
+    LpWriter(LemonWriter& _writer, const LpSolverBase& _lp, 
              const std::string& _name = std::string())
       : Parent(_writer), lp(_lp), name(_name) {} 
 
 
     /// \brief Destructor.
     ///
-    /// Destructor for NodeSetWriter.
+    /// Destructor for LpWriter.
     virtual ~LpWriter() {}
 
   private:
@@ -489,21 +831,20 @@
   private:
 
     void createCols() {
-      int num = 1;
-
-      std::map<std::string, LpSolverBase::Col> inverse;
+      int num = 0;
 
       for (LpSolverBase::ColIt it(lp); it != INVALID; ++it) {
         std::string name = lp.colName(it);
-        if (!name.empty() && inverse.find(name) == inverse.end()) {
-          cols.insert(std::make_pair(it, name));
-          inverse.insert(std::make_pair(name, it));
-        } else {
+        if (name.empty()) {
           std::ostringstream ls;
-          ls << "var" << num;
+          ls << "x" << num;
           ++num;
-          cols.insert(std::make_pair(it, ls.str()));
-          inverse.insert(std::make_pair(ls.str(), it));
+          while (lp.colByName(ls.str()) != INVALID) {
+            ls.str(std::string());
+            ls << "x" << num;
+            ++num;
+          }
+          const_cast<LpSolverBase&>(lp).colName(it, ls.str());
         }
       }
     }
@@ -526,7 +867,7 @@
           }          
         }
         first = false;
-        os << cols[jt->first] << " ";
+        os << lp.colName(jt->first) << " ";
       }
       if (e.constComp() < 0.0) {
         os << "- " << -e.constComp() << " ";
@@ -589,13 +930,13 @@
             os << lower << " <= ";
           }
           
-          os << cols[it] << " ";
+          os << lp.colName(it) << " ";
           
           if (upper != LpSolverBase::INF) {
             os << "<= " << upper << " ";
           }
         } else {
-          os << cols[it] << " == " << upper << " ";
+          os << lp.colName(it) << " == " << upper << " ";
         }
         os << std::endl;
       }
@@ -614,11 +955,8 @@
 
   private:
 
-    typedef std::map<LpSolverBase::Col, std::string> ColMap;
-      
-    LpSolverBase& lp;
+    const LpSolverBase& lp;
     std::string name;
-    ColMap cols;
   };
 
 }



More information about the Lemon-commits mailing list