lemon/lp_utils.h
changeset 2364 3a5e67bd42d2
parent 2363 2aabce558574
child 2368 6b2e8b734ae7
     1.1 --- a/lemon/lp_utils.h	Thu Feb 15 14:22:08 2007 +0000
     1.2 +++ b/lemon/lp_utils.h	Thu Feb 15 19:15:14 2007 +0000
     1.3 @@ -68,11 +68,16 @@
     1.4  
     1.5    private:
     1.6  
     1.7 +    enum SubSection {
     1.8 +      CONSTRAINTS, BOUNDS, OBJECTIVE
     1.9 +    };
    1.10 +
    1.11      enum Relation {
    1.12        LE, EQ, GE
    1.13      };
    1.14  
    1.15 -    std::istream& readConstraint(std::istream& is, LpSolverBase::Constr& c) {
    1.16 +    std::istream& readConstraint(std::istream& is) {
    1.17 +      LpSolverBase::Constr c;
    1.18        char x;
    1.19        LpSolverBase::Expr e1, e2;
    1.20        Relation op1;
    1.21 @@ -82,13 +87,27 @@
    1.22        readRelation(is, op1);
    1.23        is >> std::ws;
    1.24        readExpression(is, e2);
    1.25 +      is >> std::ws;
    1.26        if (!is.get(x)) {
    1.27          if (op1 == LE) {
    1.28 +          if (e1.size() == 0) {
    1.29 +            c = e2 >= e1;
    1.30 +          } else {
    1.31 +            c = e1 <= e2;
    1.32 +          }
    1.33            c = e1 <= e2;
    1.34          } else if (op1 == GE) {
    1.35 -          c = e1 >= e2;
    1.36 +          if (e1.size() == 0) {
    1.37 +            c = e2 <= e1;
    1.38 +          } else {
    1.39 +            c = e1 >= e2;
    1.40 +          }
    1.41          } else {
    1.42 -          c = e1 == e2;
    1.43 +          if (e1.size() == 0) {
    1.44 +            c = e2 == e1;
    1.45 +          } else {
    1.46 +            c = e1 == e2;
    1.47 +          }
    1.48          }
    1.49        } else {
    1.50          is.putback(x);
    1.51 @@ -108,7 +127,104 @@
    1.52          } else {
    1.53            c = e1.constComp() >= e2 >= e3.constComp();
    1.54          }
    1.55 +        is >> std::ws;
    1.56 +        if (is.get(x)) {
    1.57 +          throw DataFormatError("Wrong variable bounds format");
    1.58 +        }
    1.59        }
    1.60 +      lp.addRow(c);
    1.61 +      return is;
    1.62 +    }
    1.63 +
    1.64 +    std::istream& readObjective(std::istream& is) {
    1.65 +      is >> std::ws;
    1.66 +      std::string sense;
    1.67 +      is >> sense;
    1.68 +      if (sense != "min" && sense != "max") {
    1.69 +        throw DataFormatError("Wrong objective function format");
    1.70 +      }
    1.71 +      LpSolverBase::Expr expr;
    1.72 +      is >> std::ws;
    1.73 +      readExpression(is, expr);
    1.74 +      lp.setObj(expr);
    1.75 +      if (sense == "min") {
    1.76 +        lp.min();
    1.77 +      } else {
    1.78 +        lp.max();
    1.79 +      }
    1.80 +      return is;
    1.81 +    }
    1.82 +
    1.83 +    std::istream& readBounds(std::istream& is) {
    1.84 +      LpSolverBase::Col c;
    1.85 +      char x;
    1.86 +      is >> std::ws;
    1.87 +      if (!is.get(x)) {
    1.88 +        throw DataFormatError("Wrong variable bounds format");
    1.89 +      }
    1.90 +      if (varFirstChar(x)) {
    1.91 +        is.putback(x);
    1.92 +        readCol(is, c);
    1.93 +        is >> std::ws;
    1.94 +        Relation op1;
    1.95 +        readRelation(is, op1);
    1.96 +        double v;
    1.97 +        readNum(is, v);
    1.98 +        if (op1 == EQ) {
    1.99 +          lp.colLowerBound(c, v);
   1.100 +          lp.colUpperBound(c, v);
   1.101 +        } else if (op1 == LE) {
   1.102 +          lp.colUpperBound(c, v);
   1.103 +        } else {
   1.104 +          lp.colLowerBound(c, v);
   1.105 +        }
   1.106 +        is >> std::ws;
   1.107 +        if (is.get(x)) {
   1.108 +          throw DataFormatError("Wrong variable bounds format");
   1.109 +        }
   1.110 +      } else {
   1.111 +        is.putback(x);
   1.112 +        double v;
   1.113 +        readNum(is, v);
   1.114 +        is >> std::ws;
   1.115 +        Relation op1;
   1.116 +        readRelation(is, op1);
   1.117 +        is >> std::ws;
   1.118 +        readCol(is, c);
   1.119 +        is >> std::ws;
   1.120 +        if (is.get(x)) {
   1.121 +          is.putback(x);
   1.122 +          is >> std::ws;
   1.123 +          Relation op2;
   1.124 +          readRelation(is, op2);
   1.125 +          double w;
   1.126 +          is >> std::ws;
   1.127 +          readNum(is, w);
   1.128 +          if (op2 != op1 || op1 == EQ) {
   1.129 +            throw DataFormatError("Wrong range format");
   1.130 +          }
   1.131 +          if (op1 == LE) {
   1.132 +            lp.colLowerBound(c, v);
   1.133 +            lp.colUpperBound(c, w);
   1.134 +          } else {
   1.135 +            lp.colLowerBound(c, w);
   1.136 +            lp.colUpperBound(c, v);
   1.137 +          }
   1.138 +          if (is.get(x)) {
   1.139 +            throw DataFormatError("Wrong variable bounds format");
   1.140 +          }
   1.141 +        } else {
   1.142 +          if (op1 == EQ) {
   1.143 +            lp.colLowerBound(c, v);
   1.144 +            lp.colUpperBound(c, v);
   1.145 +          } else if (op1 == LE) {
   1.146 +            lp.colLowerBound(c, v);
   1.147 +          } else {
   1.148 +            lp.colUpperBound(c, v);
   1.149 +          }
   1.150 +        }
   1.151 +      }
   1.152 +      return is;
   1.153      }
   1.154  
   1.155      std::istream& readExpression(std::istream& is, LpSolverBase::Expr& e) {
   1.156 @@ -277,40 +393,9 @@
   1.157  
   1.158      static bool varChar(char c) {
   1.159        return (c >= '0' && c <= '9') || 
   1.160 -        (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
   1.161 -    }
   1.162 -
   1.163 -
   1.164 -    void addConstraint(const LpSolverBase::Constr& constr) {
   1.165 -      if (constr.expr().size() != 1) {
   1.166 -        lp.addRow(constr);
   1.167 -      } else {
   1.168 -        Lp::Expr e = constr.expr();
   1.169 -        LpSolverBase::Col col = e.begin()->first;
   1.170 -        double coeff = e.begin()->second;
   1.171 -        double lb = LpSolverBase::NaN;
   1.172 -        double ub = LpSolverBase::NaN;
   1.173 -        if (coeff > 0) {
   1.174 -          if (constr.upperBounded()) {
   1.175 -            lb = (constr.lowerBound() - e.constComp()) / coeff;
   1.176 -          }
   1.177 -          if (constr.lowerBounded()) {
   1.178 -            ub = (constr.upperBound() - e.constComp()) / coeff;
   1.179 -          }
   1.180 -        } else if (coeff < 0) {
   1.181 -          if (constr.upperBounded()) {
   1.182 -            lb = (constr.upperBound() - e.constComp()) / coeff;
   1.183 -          }
   1.184 -          if (constr.lowerBounded()) {
   1.185 -            ub = (constr.lowerBound() - e.constComp()) / coeff;
   1.186 -          }
   1.187 -        } else {
   1.188 -          lb = -LpSolverBase::INF;
   1.189 -          ub = LpSolverBase::INF;
   1.190 -        }
   1.191 -        lp.colLowerBound(col, lb);
   1.192 -        lp.colUpperBound(col, ub);
   1.193 -      }
   1.194 +        (c >= 'a' && c <= 'z') || 
   1.195 +        (c >= 'A' && c <= 'Z') ||
   1.196 +        c == '[' || c == ']';
   1.197      }
   1.198      
   1.199    protected:
   1.200 @@ -320,26 +405,30 @@
   1.201      /// It reads the content of the section.
   1.202      virtual void read(std::istream& is) {
   1.203        std::string line;
   1.204 +      SubSection sub = CONSTRAINTS;
   1.205        while (getline(is, line)) {
   1.206          std::istringstream ls(line);
   1.207 -        std::string sense;
   1.208 -        ls >> sense;
   1.209 -        if (sense == "min" || sense == "max") {
   1.210 -          LpSolverBase::Expr expr;
   1.211 -          ls >> std::ws;
   1.212 -          readExpression(ls, expr);
   1.213 -          lp.setObj(expr);
   1.214 -          if (sense == "min") {
   1.215 -            lp.min();
   1.216 -          } else {
   1.217 -            lp.max();
   1.218 -          }
   1.219 +        std::string type;
   1.220 +        ls >> type;
   1.221 +        if (type == "constraints") {
   1.222 +          sub = CONSTRAINTS;
   1.223 +        } else if (type == "bounds") {
   1.224 +          sub = BOUNDS;
   1.225 +        } else if (type == "objective") {
   1.226 +          sub = OBJECTIVE;
   1.227          } else {
   1.228            ls.str(line);
   1.229 -          LpSolverBase::Constr constr;
   1.230 -          ls >> std::ws;
   1.231 -          readConstraint(ls, constr);
   1.232 -          addConstraint(constr);
   1.233 +          switch (sub) {
   1.234 +          case CONSTRAINTS:
   1.235 +            readConstraint(ls);
   1.236 +            break;
   1.237 +          case BOUNDS:
   1.238 +            readBounds(ls);
   1.239 +            break;
   1.240 +          case OBJECTIVE:
   1.241 +            readObjective(ls);
   1.242 +            break;
   1.243 +          }
   1.244          }        
   1.245        }
   1.246      }
   1.247 @@ -360,334 +449,177 @@
   1.248    };
   1.249  
   1.250  
   1.251 -//   class LpWriter : public LemonWriter::SectionWriter {
   1.252 -//     typedef LemonWriter::SectionWriter Parent;
   1.253 -//   public:
   1.254 +  class LpWriter : public LemonWriter::SectionWriter {
   1.255 +    typedef LemonWriter::SectionWriter Parent;
   1.256 +  public:
   1.257  
   1.258  
   1.259 -//     /// \brief Constructor.
   1.260 -//     ///
   1.261 -//     /// Constructor for LpWriter. It creates the LpWriter and attach
   1.262 -//     /// it into the given LemonWriter. The lp writer will add
   1.263 -//     /// variables, constraints and objective function to the
   1.264 -//     /// given lp solver.
   1.265 -//     LpWriter(LemonWriter& _writer, LpSolverBase& _lp, 
   1.266 -//              const std::string& _name = std::string())
   1.267 -//       : Parent(_writer), lp(_lp), name(_name) {} 
   1.268 +    /// \brief Constructor.
   1.269 +    ///
   1.270 +    /// Constructor for LpWriter. It creates the LpWriter and attach
   1.271 +    /// it into the given LemonWriter. The lp writer will add
   1.272 +    /// variables, constraints and objective function to the
   1.273 +    /// given lp solver.
   1.274 +    LpWriter(LemonWriter& _writer, LpSolverBase& _lp, 
   1.275 +             const std::string& _name = std::string())
   1.276 +      : Parent(_writer), lp(_lp), name(_name) {} 
   1.277  
   1.278  
   1.279 -//     /// \brief Destructor.
   1.280 -//     ///
   1.281 -//     /// Destructor for NodeSetWriter.
   1.282 -//     virtual ~LpWriter() {}
   1.283 +    /// \brief Destructor.
   1.284 +    ///
   1.285 +    /// Destructor for NodeSetWriter.
   1.286 +    virtual ~LpWriter() {}
   1.287  
   1.288 -//   private:
   1.289 -//     LpWriter(const LpWriter&);
   1.290 -//     void operator=(const LpWriter&);
   1.291 +  private:
   1.292 +    LpWriter(const LpWriter&);
   1.293 +    void operator=(const LpWriter&);
   1.294    
   1.295 -//   protected:
   1.296 +  protected:
   1.297  
   1.298 -//     /// \brief Gives back true when the SectionWriter can process 
   1.299 -//     /// the section with the given header line.
   1.300 -//     ///
   1.301 -//     /// It gives back the header line of the \c \@lp section.
   1.302 -//     virtual std::string header() {
   1.303 -//       std::ostringstream ls(line);
   1.304 -//       ls << "@lp " << name;
   1.305 -//       return ls.str();
   1.306 -//     }
   1.307 +    /// \brief Gives back true when the SectionWriter can process 
   1.308 +    /// the section with the given header line.
   1.309 +    ///
   1.310 +    /// It gives back the header line of the \c \@lp section.
   1.311 +    virtual std::string header() {
   1.312 +      std::ostringstream ls;
   1.313 +      ls << "@lp " << name;
   1.314 +      return ls.str();
   1.315 +    }
   1.316  
   1.317 -//   private:
   1.318 +  private:
   1.319  
   1.320 -//     std::ostream& writeConstraint(std::ostream& is, LpSolverBase::Constr& c) {
   1.321 -//       char x;
   1.322 +    void createCols() {
   1.323 +      int num = 1;
   1.324  
   1.325 +      std::map<std::string, LpSolverBase::Col> inverse;
   1.326 +
   1.327 +      for (LpSolverBase::ColIt it(lp); it != INVALID; ++it) {
   1.328 +        std::string name = lp.colName(it);
   1.329 +        if (!name.empty() && inverse.find(name) == inverse.end()) {
   1.330 +          cols.insert(std::make_pair(it, name));
   1.331 +          inverse.insert(std::make_pair(name, it));
   1.332 +        } else {
   1.333 +          std::ostringstream ls;
   1.334 +          ls << "var" << num;
   1.335 +          ++num;
   1.336 +          cols.insert(std::make_pair(it, ls.str()));
   1.337 +          inverse.insert(std::make_pair(ls.str(), it));
   1.338 +        }
   1.339 +      }
   1.340 +    }
   1.341 +    
   1.342 +    void writeExpression(std::ostream& os, const LpSolverBase::Expr& e) {
   1.343 +      bool first = true;
   1.344 +      for (LpSolverBase::Expr::const_iterator jt = e.begin(); 
   1.345 +           jt != e.end(); ++jt) {
   1.346 +        if (jt->second < 0.0) {
   1.347 +          os << "- ";
   1.348 +          if (jt->second != -1.0) {
   1.349 +            os << -jt->second << " * ";
   1.350 +          }
   1.351 +        } else if (jt->second > 0.0) {
   1.352 +          if (!first) {
   1.353 +            os << "+ ";
   1.354 +          }
   1.355 +          if (jt->second != 1.0) {
   1.356 +            os << jt->second << " * ";
   1.357 +          }          
   1.358 +        }
   1.359 +        first = false;
   1.360 +        os << cols[jt->first] << " ";
   1.361 +      }
   1.362 +      if (e.constComp() < 0.0) {
   1.363 +        os << "- " << -e.constComp() << " ";
   1.364 +      } else if (e.constComp() > 0.0) {
   1.365 +        if (!first) {
   1.366 +          os << "+ ";
   1.367 +        }
   1.368 +        os << e.constComp() << " ";
   1.369 +      } 
   1.370 +    }
   1.371 +
   1.372 +  protected:
   1.373 +
   1.374 +    /// \brief Writer function of the section.
   1.375 +    ///
   1.376 +    /// It writes the content of the section.
   1.377 +    virtual void write(std::ostream& os) {
   1.378 +      createCols();
   1.379 +
   1.380 +      os << "constraints" << std::endl;
   1.381        
   1.382 -//       LpSolverBase::Expr e1, e2;
   1.383 -//       Relation op1;
   1.384 -//       is >> std::ws;
   1.385 -//       writexpression(is, e1);
   1.386 -//       is >> std::ws;
   1.387 -//       writeRelation(is, op1);
   1.388 -//       is >> std::ws;
   1.389 -//       writexpression(is, e2);
   1.390 -//       if (!is.get(x)) {
   1.391 -//         if (op1 == LE) {
   1.392 -//           c = e1 <= e2;
   1.393 -//         } else if (op1 == GE) {
   1.394 -//           c = e1 >= e2;
   1.395 -//         } else {
   1.396 -//           c = e1 == e2;
   1.397 -//         }
   1.398 -//       } else {
   1.399 -//         is.putback(x);
   1.400 -//         LpSolverBase::Expr e3;
   1.401 -//         Relation op2;
   1.402 -//         writeRelation(is, op2);
   1.403 -//         is >> std::ws;
   1.404 -//         writexpression(is, e3);
   1.405 -//         if (!e1.empty() || !e3.empty()) {
   1.406 -//           throw DataFormatError("Wrong range format");
   1.407 -//         }
   1.408 -//         if (op2 != op1 || op1 == EQ) {
   1.409 -//           throw DataFormatError("Wrong range format");
   1.410 -//         }
   1.411 -//         if (op1 == LE) {
   1.412 -//           c = e1.constComp() <= e2 <= e3.constComp();
   1.413 -//         } else {
   1.414 -//           c = e1.constComp() >= e2 >= e3.constComp();
   1.415 -//         }
   1.416 -//       }
   1.417 -//     }
   1.418 +      for (LpSolverBase::RowIt it(lp); it != INVALID; ++it) {
   1.419 +        double lower, upper;
   1.420 +        lp.getRowBounds(it, lower, upper);
   1.421 +        if (lower == -LpSolverBase::INF && upper == LpSolverBase::INF) 
   1.422 +          continue;
   1.423 +        os << "   ";
   1.424 +        
   1.425 +        if (lower != upper) {
   1.426 +          if (lower != -LpSolverBase::INF) {
   1.427 +            os << lower << " <= ";
   1.428 +          }
   1.429 +          
   1.430 +          writeExpression(os, lp.row(it));
   1.431 +          
   1.432 +          if (upper != LpSolverBase::INF) {
   1.433 +            os << "<= " << upper << " ";
   1.434 +          }
   1.435 +        } else {
   1.436  
   1.437 -//     std::ostream& writexpression(std::ostream& is, LpSolverBase::Expr& e) {
   1.438 -//       LpSolverBase::Col c;
   1.439 -//       double d;
   1.440 -//       char x;
   1.441 -//       writelement(is, c, d);
   1.442 -//       if (c != INVALID) {
   1.443 -//         e += d * c;
   1.444 -//       } else {
   1.445 -//         e += d;
   1.446 -//       }
   1.447 -//       is >> std::ws;
   1.448 -//       while (is.get(x) && (x == '+' || x == '-')) {
   1.449 -//         is >> std::ws;
   1.450 -//         writelement(is, c, d);
   1.451 -//         if (c != INVALID) {
   1.452 -//           e += (x == '+' ? d : -d) * c;
   1.453 -//         } else {
   1.454 -//           e += (x == '+' ? d : -d);
   1.455 -//         }
   1.456 -//         is >> std::ws;
   1.457 -//       }
   1.458 -//       if (!is) {
   1.459 -//         is.clear();
   1.460 -//       } else {
   1.461 -//         is.putback(x);
   1.462 -//       }
   1.463 -//       return is;
   1.464 -//     }
   1.465 +          writeExpression(os, lp.row(it));
   1.466 +          os << "== " << upper << " ";
   1.467 +          
   1.468 +        }
   1.469  
   1.470 -//     std::ostream& writelement(std::ostream& is, 
   1.471 -//                               LpSolverBase::Col& c, double& d) { 
   1.472 -//       d = 1.0;
   1.473 -//       c = INVALID;
   1.474 -//       char x, y;
   1.475 -//       if (!is.get(x)) throw DataFormatError("Cannot find lp element");
   1.476 -//       if (x == '+' || x == '-') {
   1.477 -//         is >> std::ws;
   1.478 -//         d *= x == '-' ? -1 : 1;
   1.479 -//         while (is.get(x) && (x == '+' || x == '-')) {
   1.480 -//           d *= x == '-' ? -1 : 1;
   1.481 -//           is >> std::ws;
   1.482 -//         }
   1.483 -//         if (!is) throw DataFormatError("Cannot find lp element");
   1.484 -//       }
   1.485 -//       if (numFirstChar(x)) {
   1.486 -//         is.putback(x);
   1.487 -//         double e;
   1.488 -//         writeNum(is, e);
   1.489 -//         d *= e;
   1.490 -//       } else if (varFirstChar(x)) {
   1.491 -//         is.putback(x);
   1.492 -//         LpSolverBase::Col f;
   1.493 -//         writeCol(is, f);
   1.494 -//         c = f;
   1.495 -//       } else {
   1.496 -//         throw DataFormatError("Invalid expression format");          
   1.497 -//       }
   1.498 -//       is >> std::ws;
   1.499 -//       while (is.get(y) && (y == '*' || y == '/')) {
   1.500 -//         is >> std::ws;
   1.501 -//         if (!is.get(x)) throw DataFormatError("Cannot find lp element");
   1.502 -//         if (x == '+' || x == '-') {
   1.503 -//           is >> std::ws;
   1.504 -//           d *= x == '-' ? -1 : 1;
   1.505 -//           while (is.get(x) && (x == '+' || x == '-')) {
   1.506 -//             d *= x == '-' ? -1 : 1;
   1.507 -//             is >> std::ws;
   1.508 -//           }
   1.509 -//           if (!is) throw DataFormatError("Cannot find lp element");
   1.510 -//         }
   1.511 -//         if (numFirstChar(x)) {
   1.512 -//           is.putback(x);
   1.513 -//           double e;
   1.514 -//           writeNum(is, e);
   1.515 -//           if (y == '*') {
   1.516 -//             d *= e;
   1.517 -//           } else {
   1.518 -//             d /= e;
   1.519 -//           }
   1.520 -//         } else if (varFirstChar(x)) {
   1.521 -//           is.putback(x);
   1.522 -//           LpSolverBase::Col f;
   1.523 -//           writeCol(is, f);
   1.524 -//           if (y == '*') {
   1.525 -//             if (c == INVALID) {
   1.526 -//               c = f;
   1.527 -//             } else {
   1.528 -//               throw DataFormatError("Quadratic element in expression");
   1.529 -//             }
   1.530 -//           } else {
   1.531 -//             throw DataFormatError("Division by variable");
   1.532 -//           }
   1.533 -//         } else {
   1.534 -//           throw DataFormatError("Invalid expression format");          
   1.535 -//         }
   1.536 -//         is >> std::ws;
   1.537 -//       }
   1.538 -//       if (!is) {
   1.539 -//         is.clear();
   1.540 -//       } else {
   1.541 -//         is.putback(y);
   1.542 -//       }
   1.543 -//       return is;
   1.544 -//     }
   1.545 +        os << std::endl;
   1.546 +      }
   1.547  
   1.548 -//     std::ostream& writeCol(std::ostream& is, LpSolverBase::Col& c) {
   1.549 -//       char x;
   1.550 -//       std::string var;
   1.551 -//       while (is.get(x) && varChar(x)) {
   1.552 -//         var += x;
   1.553 -//       }
   1.554 -//       if (!is) {
   1.555 -//         is.clear();
   1.556 -//       } else {
   1.557 -//         is.putback(x);
   1.558 -//       }
   1.559 -//       ColMap::const_iterator it = cols.find(var);
   1.560 -//       if (cols.find(var) != cols.end()) {
   1.561 -//         c = it->second;
   1.562 -//       } else {
   1.563 -//         c = lp.addCol();
   1.564 -//         cols.insert(std::make_pair(var, c));
   1.565 -//         lp.colName(c, var);
   1.566 -//       }
   1.567 -//       return is;
   1.568 -//     }
   1.569 +      os << "bounds" << std::endl;
   1.570 +      
   1.571 +      for (LpSolverBase::ColIt it(lp); it != INVALID; ++it) {
   1.572 +        double lower = lp.colLowerBound(it);
   1.573 +        double upper = lp.colUpperBound(it);
   1.574 +        if (lower == -LpSolverBase::INF && upper == LpSolverBase::INF) 
   1.575 +          continue;
   1.576 +        os << "   ";
   1.577  
   1.578 -//     std::ostream& writeNum(std::ostream& is, double& d) {
   1.579 -//       is >> d;
   1.580 -//       if (!is) throw DataFormatError("Wrong number format");
   1.581 -//       return is;
   1.582 -//     }
   1.583 +        if (lower != upper) {
   1.584 +          if (lower != -LpSolverBase::INF) {
   1.585 +            os << lower << " <= ";
   1.586 +          }
   1.587 +          
   1.588 +          os << cols[it] << " ";
   1.589 +          
   1.590 +          if (upper != LpSolverBase::INF) {
   1.591 +            os << "<= " << upper << " ";
   1.592 +          }
   1.593 +        } else {
   1.594 +          os << cols[it] << " == " << upper << " ";
   1.595 +        }
   1.596 +        os << std::endl;
   1.597 +      }
   1.598  
   1.599 -//     std::ostream& writeRelation(std::ostream& is, Relation& op) {
   1.600 -//       char x, y;
   1.601 -//       if (!is.get(x) || !(x == '<' || x == '=' || x == '>')) {
   1.602 -//         throw DataFormatError("Wrong relation operator");
   1.603 -//       }
   1.604 -//       if (!is.get(y) || y != '=') {
   1.605 -//         throw DataFormatError("Wrong relation operator");
   1.606 -//       }
   1.607 -//       switch (x) {
   1.608 -//       case '<': op = LE; 
   1.609 -//         break;
   1.610 -//       case '=': op = EQ; 
   1.611 -//         break;
   1.612 -//       case '>': op = GE; 
   1.613 -//         break;
   1.614 -//       }
   1.615 -//       return is;
   1.616 -//     }
   1.617 +      os << "objective" << std::endl;
   1.618 +      os << "   ";
   1.619 +      if (lp.is_min()) {
   1.620 +        os << "min ";
   1.621 +      } else {
   1.622 +        os << "max ";
   1.623 +      }
   1.624 +      writeExpression(os, lp.obj());
   1.625 +      os << std::endl;
   1.626 +    }
   1.627 +      
   1.628  
   1.629 -//     static bool relationFirstChar(char c) {
   1.630 -//       return c == '<' || c == '=' || c == '>';
   1.631 -//     }
   1.632 +  private:
   1.633  
   1.634 -//     static bool varFirstChar(char c) {
   1.635 -//       return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
   1.636 -//     }
   1.637 -
   1.638 -//     static bool numFirstChar(char c) {
   1.639 -//       return (c >= '0' && c <= '9') || c == '.';
   1.640 -//     }
   1.641 -
   1.642 -//     static bool varChar(char c) {
   1.643 -//       return (c >= '0' && c <= '9') || 
   1.644 -//         (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
   1.645 -//     }
   1.646 -
   1.647 -
   1.648 -//     void addConstraint(const LpSolverBase::Constr& constr) {
   1.649 -//       if (constr.expr().size() != 1) {
   1.650 -//         lp.addRow(constr);
   1.651 -//       } else {
   1.652 -//         Lp::Expr e = constr.expr();
   1.653 -//         LpSolverBase::Col col = e.begin()->first;
   1.654 -//         double coeff = e.begin()->second;
   1.655 -//         double lb = LpSolverBase::NaN;
   1.656 -//         double ub = LpSolverBase::NaN;
   1.657 -//         if (coeff > 0) {
   1.658 -//           if (constr.upperBounded()) {
   1.659 -//             lb = (constr.lowerBound() - e.constComp()) / coeff;
   1.660 -//           }
   1.661 -//           if (constr.lowerBounded()) {
   1.662 -//             ub = (constr.upperBound() - e.constComp()) / coeff;
   1.663 -//           }
   1.664 -//         } else if (coeff < 0) {
   1.665 -//           if (constr.upperBounded()) {
   1.666 -//             lb = (constr.upperBound() - e.constComp()) / coeff;
   1.667 -//           }
   1.668 -//           if (constr.lowerBounded()) {
   1.669 -//             ub = (constr.lowerBound() - e.constComp()) / coeff;
   1.670 -//           }
   1.671 -//         } else {
   1.672 -//           lb = -LpSolverBase::INF;
   1.673 -//           ub = LpSolverBase::INF;
   1.674 -//         }
   1.675 -//         lp.colLowerBound(col, lb);
   1.676 -//         lp.colUpperBound(col, ub);
   1.677 -//       }
   1.678 -//     }
   1.679 -    
   1.680 -//   protected:
   1.681 -
   1.682 -//     /// \brief Writer function of the section.
   1.683 -//     ///
   1.684 -//     /// It writes the content of the section.
   1.685 -//     virtual void write(std::ostream& is) {
   1.686 -//       std::string line;
   1.687 -//       std::map<std::string, LpSolverBase::Col> vars;
   1.688 -//       while (getline(is, line)) {
   1.689 -//         std::istringstream ls(line);
   1.690 -//         std::string sense;
   1.691 -//         ls >> sense;
   1.692 -//         if (sense == "min" || sense == "max") {
   1.693 -//           LpSolverBase::Expr expr;
   1.694 -//           ls >> std::ws;
   1.695 -//           writeExpression(ls, expr);
   1.696 -//           lp.setObj(expr);
   1.697 -//           if (sense == "min") {
   1.698 -//             lp.min();
   1.699 -//           } else {
   1.700 -//             lp.max();
   1.701 -//           }
   1.702 -//         } else {
   1.703 -//           ls.str(line);
   1.704 -//           LpSolverBase::Constr constr;
   1.705 -//           ls >> std::ws;
   1.706 -//           writeConstraint(ls, constr);
   1.707 -//           addConstraint(constr);
   1.708 -//         }        
   1.709 -//       }
   1.710 -//     }
   1.711 +    typedef std::map<LpSolverBase::Col, std::string> ColMap;
   1.712        
   1.713 -//     virtual void missing() {
   1.714 -//       ErrorMessage msg;
   1.715 -//       msg << "Lp section not found in file: @lp " << name;
   1.716 -//       throw IoParameterError(msg.message());
   1.717 -//     }
   1.718 -
   1.719 -//   private:
   1.720 -
   1.721 -//     typedef std::map<std::string, LpSolverBase::Col> ColMap;
   1.722 -      
   1.723 -//     LpSolverBase& lp;
   1.724 -//     std::string name;
   1.725 -//     ColMap cols;
   1.726 -//   };
   1.727 +    LpSolverBase& lp;
   1.728 +    std::string name;
   1.729 +    ColMap cols;
   1.730 +  };
   1.731  
   1.732  }
   1.733